WKTReader.java
package org.cugos.wkg;
import org.antlr.v4.runtime.*;
import org.cugos.wkg.internal.WKTBaseListener;
import org.cugos.wkg.internal.WKTLexer;
import org.cugos.wkg.internal.WKTParser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
/**
* Read a Geometry from a Well Known Text (WKT) String
*/
public class WKTReader implements Reader<String> {
/**
* Read the WKT and return a Geometry
* @param wkt The WKT
* @return A Geometry
*/
@Override
public Geometry read(String wkt) {
WKTLexer lexer = new WKTLexer(CharStreams.fromString(wkt));
WKTParser parser = new WKTParser(new CommonTokenStream(lexer));
parser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
throw new IllegalStateException("failed to parse at line " + line + " due to " + msg, e);
}
});
final Stack<Geometry> geometries = new Stack<Geometry>();
final Var<Dimension> dimension = new Var<Dimension>();
final Var<String> srid = new Var<String>();
dimension.set(Dimension.Two);
parser.addParseListener(new WKTBaseListener() {
@Override
public void exitDimension(WKTParser.DimensionContext ctx) {
if (ctx.M() != null) {
dimension.set(Dimension.TwoMeasured);
} else if (ctx.Z() != null) {
dimension.set(Dimension.Three);
} else if (ctx.ZM() != null) {
dimension.set(Dimension.ThreeMeasured);
}
}
@Override
public void exitSrid(WKTParser.SridContext ctx) {
srid.set(ctx.Number().getText());
}
@Override
public void exitPoint(WKTParser.PointContext ctx) {
Point point;
if (ctx.coordinate() == null) {
point = Point.createEmpty();
} else {
point = point(ctx, dimension, srid);
}
geometries.push(point);
}
@Override
public void exitLineString(WKTParser.LineStringContext ctx) {
LineString lineString;
if (ctx.coordinates() == null) {
lineString = LineString.createEmpty();
} else {
lineString = lineString(ctx, dimension, srid);
}
geometries.push(lineString);
}
@Override
public void exitCircularString(WKTParser.CircularStringContext ctx) {
CircularString lineString;
if (ctx.coordinates() == null) {
lineString = CircularString.createEmpty();
} else {
lineString = new CircularString(coordinates(ctx.coordinates(), dimension), dimension.get(), srid.get());
}
geometries.push(lineString);
}
@Override
public void exitMultiPoint(WKTParser.MultiPointContext ctx) {
MultiPoint lineString;
if (ctx.coordinates() == null && ctx.coordinatesets() == null) {
lineString = MultiPoint.createEmpty();
} else {
lineString = multiPoint(ctx, dimension, srid);
}
geometries.push(lineString);
}
@Override
public void exitPolygon(WKTParser.PolygonContext ctx) {
Polygon polygon;
if (ctx.coordinatesets() == null || ctx.coordinatesets().coordinates().size() == 0) {
polygon = Polygon.createEmpty();
} else {
polygon = polygon(ctx.coordinatesets(), dimension, srid);
}
geometries.push(polygon);
}
@Override
public void exitTriangle(WKTParser.TriangleContext ctx) {
Triangle polygon;
if (ctx.coordinatesets() == null || ctx.coordinatesets().coordinates().size() == 0) {
polygon = Triangle.createEmpty();
} else {
polygon = triangle(ctx.coordinatesets().coordinates(), dimension, srid);
}
geometries.push(polygon);
}
@Override
public void exitTin(WKTParser.TinContext ctx) {
Tin tin;
if (ctx.coordinatesetsset() == null || ctx.coordinatesetsset().coordinatesets().isEmpty()) {
tin = Tin.createEmpty();
} else {
List<Triangle> triangles = new ArrayList<Triangle>();
for (WKTParser.CoordinatesetsContext cctx : ctx.coordinatesetsset().coordinatesets()) {
List<WKTParser.CoordinatesContext> coordinatesContexts = cctx.coordinates();
triangles.add(triangle(coordinatesContexts, dimension, srid));
}
tin = new Tin(triangles, dimension.get(), srid.get());
}
geometries.push(tin);
}
@Override
public void exitMultiLineString(WKTParser.MultiLineStringContext ctx) {
MultiLineString multiLineString;
if (ctx.coordinatesets() == null || ctx.coordinatesets().coordinates().size() == 0) {
multiLineString = MultiLineString.createEmpty();
} else {
List<LineString> linesStrings = new ArrayList<LineString>();
for(WKTParser.CoordinatesContext cctx : ctx.coordinatesets().coordinates()) {
linesStrings.add(new LineString(coordinates(cctx, dimension), dimension.get(), srid.get()));
}
multiLineString = new MultiLineString(linesStrings,dimension.get() , srid.get());
}
geometries.push(multiLineString);
}
@Override
public void exitPolyHedralSurface(WKTParser.PolyHedralSurfaceContext ctx) {
PolyHedralSurface polyHedralSurface;
if (ctx.coordinatesetsset() == null || ctx.coordinatesetsset().coordinatesets().isEmpty()) {
polyHedralSurface = PolyHedralSurface.createEmpty();
} else {
List<Polygon> polygons = new ArrayList<Polygon>();
for (WKTParser.CoordinatesetsContext cctx : ctx.coordinatesetsset().coordinatesets()) {
polygons.add(polygon(cctx, dimension, srid));
}
polyHedralSurface = new PolyHedralSurface(polygons, dimension.get(), srid.get());
}
geometries.push(polyHedralSurface);
}
@Override
public void exitMultiPolygon(WKTParser.MultiPolygonContext ctx) {
MultiPolygon multiPolygon;
if (ctx.coordinatesetsset() == null || ctx.coordinatesetsset().coordinatesets().isEmpty()) {
multiPolygon = MultiPolygon.createEmpty();
} else {
List<Polygon> polygons = new ArrayList<Polygon>();
for (WKTParser.CoordinatesetsContext cctx : ctx.coordinatesetsset().coordinatesets()) {
polygons.add(polygon(cctx, dimension, srid));
}
multiPolygon = new MultiPolygon(polygons, dimension.get(), srid.get());
}
geometries.push(multiPolygon);
}
@Override
public void exitCurvePolygon(WKTParser.CurvePolygonContext ctx) {
CurvePolygon curvePolygon;
if (ctx.curvePolygonItems() == null || ctx.curvePolygonItems().curvePolygonElements() == null) {
curvePolygon = CurvePolygon.createEmpty();
} else {
List<Curve> curves = new ArrayList<Curve>();
for(WKTParser.CurvePolygonElementsContext cpext : ctx.curvePolygonItems().curvePolygonElements()) {
if (cpext.circularString() != null) {
curves.add((Curve) geometries.pop());
} else if (cpext.compoundCurve() != null) {
curves.add((Curve) geometries.pop());
} else if (cpext.lineStringCoordinates() != null) {
curves.add(lineString(cpext.lineStringCoordinates().coordinates(), dimension, srid));
}
}
curvePolygon = new CurvePolygon(
curves.get(0),
curves.subList(1, curves.size()),
dimension.get(), srid.get());
}
geometries.push(curvePolygon);
}
@Override
public void exitCompoundCurve(WKTParser.CompoundCurveContext ctx) {
CompoundCurve compoundCurve;
if (ctx.compoundCurveItems() == null || ctx.compoundCurveItems().compoundCurveElements() == null) {
compoundCurve = CompoundCurve.createEmpty();
} else {
List<Curve> curves = new ArrayList<Curve>();
for(WKTParser.CompoundCurveElementsContext ccext : ctx.compoundCurveItems().compoundCurveElements()) {
if (ccext.circularString() != null) {
curves.add((Curve) geometries.pop());
} else if (ccext.lineStringCoordinates() != null) {
curves.add(lineString(ccext.lineStringCoordinates().coordinates(), dimension, srid));
}
}
compoundCurve = new CompoundCurve(
curves,
dimension.get(), srid.get());
}
geometries.push(compoundCurve);
}
@Override
public void exitMultiCurve(WKTParser.MultiCurveContext ctx) {
MultiCurve multiCurve;
if (ctx.multiCurveItems() == null || ctx.multiCurveItems().multiCurveElements() == null) {
multiCurve = MultiCurve.createEmpty();
} else {
List<Curve> curves = new ArrayList<Curve>();
for(WKTParser.MultiCurveElementsContext ccext : ctx.multiCurveItems().multiCurveElements()) {
if (ccext.circularString() != null) {
curves.add((CircularString) geometries.pop());
} else if (ccext.lineStringCoordinates() != null) {
curves.add(lineString(ccext.lineStringCoordinates().coordinates(), dimension, srid));
} else if (ccext.compoundCurve() != null) {
curves.add((CompoundCurve) geometries.pop());
}
}
multiCurve = new MultiCurve(
curves,
dimension.get(), srid.get());
}
geometries.push(multiCurve);
}
@Override
public void exitMultiSurface(WKTParser.MultiSurfaceContext ctx) {
MultiSurface multiSurface;
if (ctx.multiSurfaceItems() == null || ctx.multiSurfaceItems().multiSurfaceElements() == null) {
multiSurface = MultiSurface.createEmpty();
} else {
List<Surface> surfaces = new ArrayList<Surface>();
for(WKTParser.MultiSurfaceElementsContext ccext : ctx.multiSurfaceItems().multiSurfaceElements()) {
if (ccext.curvePolygon() != null) {
surfaces.add((CurvePolygon) geometries.pop());
} else if (ccext.polygonCoordinates() != null) {
surfaces.add(polygon(ccext.polygonCoordinates().coordinatesets(), dimension, srid));
}
}
multiSurface = new MultiSurface(
surfaces,
dimension.get(), srid.get());
}
geometries.push(multiSurface);
}
@Override
public void exitGeometryCollection(WKTParser.GeometryCollectionContext ctx) {
GeometryCollection geometryCollection;
if (ctx.geometryCollectionItems() == null || ctx.geometryCollectionItems().geometryCollectionElements() == null) {
geometryCollection = GeometryCollection.createEmpty();
} else {
List<Geometry> geometryList = new ArrayList<Geometry>();
for(WKTParser.GeometryCollectionElementsContext ccext : ctx.geometryCollectionItems().geometryCollectionElements()) {
geometryList.add(geometries.pop());
}
Collections.reverse(geometryList);
geometryCollection = new GeometryCollection(
geometryList,
dimension.get(), srid.get());
}
geometries.push(geometryCollection);
}
});
parser.wkt();
return geometries.isEmpty() ? null : geometries.pop();
}
@Override
public String getName() {
return "WKT";
}
private Coordinate coordinate(WKTParser.CoordinateContext ctx, Var<Dimension> dimension) {
double x = Double.parseDouble(ctx.Number(0).getText());
double y = Double.parseDouble(ctx.Number(1).getText());
if (dimension.get() == Dimension.Two && ctx.Number().size() == 3) {
dimension.set(Dimension.Three);
} else if (dimension.get() == Dimension.Two && ctx.Number().size()== 4) {
dimension.set(Dimension.ThreeMeasured);
}
if (dimension.get() == Dimension.TwoMeasured) {
return Coordinate.create2DM(x,y, Double.parseDouble(ctx.Number(2).getText()));
} if (dimension.get() == Dimension.Three) {
return Coordinate.create3D(x,y, Double.parseDouble(ctx.Number(2).getText()));
} if (dimension.get() == Dimension.ThreeMeasured) {
return Coordinate.create3DM(x,y, Double.parseDouble(ctx.Number(2).getText()), Double.parseDouble(ctx.Number(3).getText()));
} /*if (dimension == Dimension.Two)*/ {
return Coordinate.create2D(x,y);
}
}
private List<Coordinate> coordinates(WKTParser.CoordinatesContext ctx, Var<Dimension> dimension) {
List<Coordinate> points = new ArrayList<Coordinate>();
for(WKTParser.CoordinateContext cctx : ctx.coordinate()) {
points.add(coordinate(cctx, dimension));
}
return points;
}
private List<Point> points(WKTParser.CoordinatesContext ctx, Var<Dimension> dimension, Var<String> srid) {
List<Point> points = new ArrayList<Point>();
for(Coordinate coordinate : coordinates(ctx, dimension)) {
points.add(new Point(coordinate, dimension.get(), srid.get()));
}
return points;
}
private List<Point> points(WKTParser.CoordinatesetsContext ctx, Var<Dimension> dimension, Var<String> srid) {
List<Point> points = new ArrayList<Point>();
List<WKTParser.CoordinatesContext> coordinatesContexts = ctx.coordinates();
for(WKTParser.CoordinatesContext cctx : coordinatesContexts) {
points.addAll(points(cctx, dimension, srid));
}
return points;
}
private Point point(WKTParser.PointContext ctx, Var<Dimension> dimension, Var<String> srid) {
return new Point(coordinate(ctx.coordinate(), dimension), dimension.get(), srid.get());
}
private LineString lineString(WKTParser.LineStringContext ctx, Var<Dimension> dimension, Var<String> srid) {
return new LineString(coordinates(ctx.coordinates(), dimension), dimension.get(), srid.get());
}
private LineString lineString(WKTParser.CoordinatesContext ctx, Var<Dimension> dimension, Var<String> srid) {
return new LineString(coordinates(ctx, dimension), dimension.get(), srid.get());
}
private Polygon polygon(WKTParser.CoordinatesetsContext cctx, Var<Dimension> dimension, Var<String> srid) {
List<WKTParser.CoordinatesContext> coordinatesContexts = cctx.coordinates();
LinearRing linearRing = new LinearRing(coordinates(coordinatesContexts.get(0), dimension), dimension.get(), srid.get());
List<LinearRing> holes = new ArrayList<LinearRing>();
for(int i = 1; i<coordinatesContexts.size(); i++) {
LinearRing hole = new LinearRing(coordinates(coordinatesContexts.get(i), dimension), dimension.get(), srid.get());
holes.add(hole);
}
return new Polygon(linearRing, holes, dimension.get(), srid.get());
}
private MultiPoint multiPoint(WKTParser.MultiPointContext ctx, Var<Dimension> dimension, Var<String> srid) {
if (ctx.coordinates() != null) {
return new MultiPoint(points(ctx.coordinates(), dimension, srid), dimension.get(), srid.get());
} else {
return new MultiPoint(points(ctx.coordinatesets(), dimension, srid), dimension.get(), srid.get());
}
}
private Triangle triangle(List<WKTParser.CoordinatesContext> coordinatesContexts, Var<Dimension> dimension, Var<String> srid) {
LinearRing linearRing = new LinearRing(coordinates(coordinatesContexts.get(0), dimension), dimension.get(), srid.get());
List<LinearRing> holes = new ArrayList<LinearRing>();
for(int i = 1; i<coordinatesContexts.size(); i++) {
LinearRing hole = new LinearRing(coordinates(coordinatesContexts.get(i), dimension), dimension.get(), srid.get());
holes.add(hole);
}
return new Triangle(linearRing, holes, dimension.get(), srid.get());
}
private static class Var<T> {
private T variable = null;
public T get() {
return variable;
}
public void set(T var) {
this.variable = var;
}
}
}