Added MultiPolygon parsing and serialization support
This commit is contained in:
parent
8080fdc509
commit
4f5e62e988
|
@ -26,6 +26,7 @@ import com.spatial4j.core.shape.jts.JtsPoint;
|
|||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.GeometryFactory;
|
||||
import com.vividsolutions.jts.geom.LinearRing;
|
||||
import com.vividsolutions.jts.geom.Polygon;
|
||||
import org.elasticsearch.ElasticSearchParseException;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
|
@ -142,25 +143,44 @@ public class GeoJSONShapeParser {
|
|||
} else if ("linestring".equals(shapeType)) {
|
||||
return new JtsGeometry(GEOMETRY_FACTORY.createLineString(toCoordinates(node)), GeoShapeConstants.SPATIAL_CONTEXT, true);
|
||||
} else if ("polygon".equals(shapeType)) {
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(toCoordinates(node.children.get(0)));
|
||||
LinearRing[] holes = null;
|
||||
if (node.children.size() > 1) {
|
||||
holes = new LinearRing[node.children.size() - 1];
|
||||
for (int i = 0; i < node.children.size() - 1; i++) {
|
||||
holes[i] = GEOMETRY_FACTORY.createLinearRing(toCoordinates(node.children.get(i + 1)));
|
||||
}
|
||||
}
|
||||
return new JtsGeometry(GEOMETRY_FACTORY.createPolygon(shell, holes), GeoShapeConstants.SPATIAL_CONTEXT, true);
|
||||
return new JtsGeometry(buildPolygon(node), GeoShapeConstants.SPATIAL_CONTEXT, true);
|
||||
} else if ("multipoint".equals(shapeType)) {
|
||||
return new JtsGeometry(GEOMETRY_FACTORY.createMultiPoint(toCoordinates(node)), GeoShapeConstants.SPATIAL_CONTEXT, true);
|
||||
} else if ("envelope".equals(shapeType)) {
|
||||
Coordinate[] coordinates = toCoordinates(node);
|
||||
return new RectangleImpl(coordinates[0].x, coordinates[1].x, coordinates[1].y, coordinates[0].y, GeoShapeConstants.SPATIAL_CONTEXT);
|
||||
} else if ("multipolygon".equals(shapeType)) {
|
||||
Polygon[] polygons = new Polygon[node.children.size()];
|
||||
for (int i = 0; i < node.children.size(); i++) {
|
||||
polygons[i] = buildPolygon(node.children.get(i));
|
||||
}
|
||||
return new JtsGeometry(
|
||||
GEOMETRY_FACTORY.createMultiPolygon(polygons),
|
||||
GeoShapeConstants.SPATIAL_CONTEXT,
|
||||
true);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("ShapeType [" + shapeType + "] not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link Polygon} from the given CoordinateNode
|
||||
*
|
||||
* @param node CoordinateNode that the Polygon will be built from
|
||||
* @return Polygon consisting of the coordinates in the CoordinateNode
|
||||
*/
|
||||
private static Polygon buildPolygon(CoordinateNode node) {
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(toCoordinates(node.children.get(0)));
|
||||
LinearRing[] holes = null;
|
||||
if (node.children.size() > 1) {
|
||||
holes = new LinearRing[node.children.size() - 1];
|
||||
for (int i = 0; i < node.children.size() - 1; i++) {
|
||||
holes[i] = GEOMETRY_FACTORY.createLinearRing(toCoordinates(node.children.get(i + 1)));
|
||||
}
|
||||
}
|
||||
return GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the children of the given CoordinateNode into an array of
|
||||
* {@link Coordinate}.
|
||||
|
|
|
@ -59,6 +59,8 @@ public class GeoJSONShapeSerializer {
|
|||
serializePolygon((Polygon) geometry, builder);
|
||||
} else if (geometry instanceof MultiPoint) {
|
||||
serializeMultiPoint((MultiPoint) geometry, builder);
|
||||
} else if (geometry instanceof MultiPolygon) {
|
||||
serializeMulitPolygon((MultiPolygon) geometry, builder);
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("Geometry type [" + geometry.getGeometryType() + "] not supported");
|
||||
}
|
||||
|
@ -143,6 +145,19 @@ public class GeoJSONShapeSerializer {
|
|||
builder.field("type", "Polygon")
|
||||
.startArray("coordinates");
|
||||
|
||||
serializePolygonCoordinates(polygon, builder);
|
||||
|
||||
builder.endArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the actual coordinates of the given {@link Polygon}
|
||||
*
|
||||
* @param polygon Polygon whose coordinates will be serialized
|
||||
* @param builder XContentBuilder it will be serialized to
|
||||
* @throws IOException Thrown if an error occurs while writing to the XContentBuilder
|
||||
*/
|
||||
private static void serializePolygonCoordinates(Polygon polygon, XContentBuilder builder) throws IOException {
|
||||
builder.startArray(); // start outer ring
|
||||
|
||||
for (Coordinate coordinate : polygon.getExteriorRing().getCoordinates()) {
|
||||
|
@ -162,7 +177,26 @@ public class GeoJSONShapeSerializer {
|
|||
|
||||
builder.endArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the given {@link MultiPolygon}
|
||||
*
|
||||
* @param multiPolygon MultiPolygon that will be serialized
|
||||
* @param builder XContentBuilder it will be serialized to
|
||||
* @throws IOException Thrown if an error occurs while writing to the XContentBuilder
|
||||
*/
|
||||
private static void serializeMulitPolygon(MultiPolygon multiPolygon, XContentBuilder builder) throws IOException {
|
||||
builder.field("type", "MultiPolygon")
|
||||
.startArray("coordinates");
|
||||
|
||||
for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
|
||||
builder.startArray();
|
||||
|
||||
serializePolygonCoordinates((Polygon) multiPolygon.getGeometryN(i), builder);
|
||||
|
||||
builder.endArray();
|
||||
}
|
||||
|
||||
builder.endArray();
|
||||
}
|
||||
|
@ -170,7 +204,7 @@ public class GeoJSONShapeSerializer {
|
|||
/**
|
||||
* Serializes the given {@link MultiPoint}
|
||||
*
|
||||
* @param multiPoint MulitPoint that will be serialized
|
||||
* @param multiPoint MultiPoint that will be serialized
|
||||
* @param builder XContentBuilder it will be serialized to
|
||||
* @throws IOException Thrown if an error occurs while writing to the XContentBuilder
|
||||
*/
|
||||
|
|
|
@ -141,6 +141,75 @@ public class GeoJSONShapeParserTests {
|
|||
assertGeometryEquals(new JtsGeometry(expected, GeoShapeConstants.SPATIAL_CONTEXT, false), multiPointGeoJson);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse_multiPolygon() throws IOException {
|
||||
String multiPolygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "MultiPolygon")
|
||||
.startArray("coordinates")
|
||||
.startArray()
|
||||
.startArray()
|
||||
.startArray().value(102.0).value(2.0).endArray()
|
||||
.startArray().value(103.0).value(2.0).endArray()
|
||||
.startArray().value(103.0).value(3.0).endArray()
|
||||
.startArray().value(102.0).value(3.0).endArray()
|
||||
.startArray().value(102.0).value(2.0).endArray()
|
||||
.endArray()
|
||||
.endArray()
|
||||
.startArray()
|
||||
.startArray()
|
||||
.startArray().value(100.0).value(0.0).endArray()
|
||||
.startArray().value(101.0).value(0.0).endArray()
|
||||
.startArray().value(101.0).value(1.0).endArray()
|
||||
.startArray().value(100.0).value(1.0).endArray()
|
||||
.startArray().value(100.0).value(0.0).endArray()
|
||||
.endArray()
|
||||
.startArray()
|
||||
.startArray().value(100.2).value(0.2).endArray()
|
||||
.startArray().value(100.8).value(0.2).endArray()
|
||||
.startArray().value(100.8).value(0.8).endArray()
|
||||
.startArray().value(100.2).value(0.8).endArray()
|
||||
.startArray().value(100.2).value(0.2).endArray()
|
||||
.endArray()
|
||||
.endArray()
|
||||
.endArray()
|
||||
.endObject().string();
|
||||
|
||||
List<Coordinate> shellCoordinates = new ArrayList<Coordinate>();
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
|
||||
List<Coordinate> holeCoordinates = new ArrayList<Coordinate>();
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(
|
||||
shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
LinearRing[] holes = new LinearRing[1];
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(
|
||||
holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
||||
Polygon withHoles = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||
|
||||
shellCoordinates = new ArrayList<Coordinate>();
|
||||
shellCoordinates.add(new Coordinate(102, 2));
|
||||
shellCoordinates.add(new Coordinate(103, 2));
|
||||
shellCoordinates.add(new Coordinate(103, 3));
|
||||
shellCoordinates.add(new Coordinate(102, 3));
|
||||
shellCoordinates.add(new Coordinate(102, 2));
|
||||
|
||||
shell = GEOMETRY_FACTORY.createLinearRing(
|
||||
shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
Polygon withoutHoles = GEOMETRY_FACTORY.createPolygon(shell, null);
|
||||
|
||||
MultiPolygon expected = GEOMETRY_FACTORY.createMultiPolygon(new Polygon[] {withoutHoles, withHoles});
|
||||
|
||||
assertGeometryEquals(new JtsGeometry(expected, GeoShapeConstants.SPATIAL_CONTEXT, false), multiPolygonGeoJson);
|
||||
}
|
||||
|
||||
private void assertGeometryEquals(Shape expected, String geoJson) throws IOException {
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(geoJson);
|
||||
parser.nextToken();
|
||||
|
|
|
@ -144,6 +144,76 @@ public class GeoJSONShapeSerializerTests {
|
|||
assertSerializationEquals(expected, new JtsGeometry(multiPoint, GeoShapeConstants.SPATIAL_CONTEXT, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialize_multiPolygon() throws IOException {
|
||||
XContentBuilder expected = XContentFactory.jsonBuilder().startObject().field("type", "MultiPolygon")
|
||||
.startArray("coordinates")
|
||||
.startArray()
|
||||
.startArray()
|
||||
.startArray().value(100.0).value(0.0).endArray()
|
||||
.startArray().value(101.0).value(0.0).endArray()
|
||||
.startArray().value(101.0).value(1.0).endArray()
|
||||
.startArray().value(100.0).value(1.0).endArray()
|
||||
.startArray().value(100.0).value(0.0).endArray()
|
||||
.endArray()
|
||||
.startArray()
|
||||
.startArray().value(100.2).value(0.2).endArray()
|
||||
.startArray().value(100.8).value(0.2).endArray()
|
||||
.startArray().value(100.8).value(0.8).endArray()
|
||||
.startArray().value(100.2).value(0.8).endArray()
|
||||
.startArray().value(100.2).value(0.2).endArray()
|
||||
.endArray()
|
||||
.endArray()
|
||||
.startArray()
|
||||
.startArray()
|
||||
.startArray().value(102.0).value(2.0).endArray()
|
||||
.startArray().value(103.0).value(2.0).endArray()
|
||||
.startArray().value(103.0).value(3.0).endArray()
|
||||
.startArray().value(102.0).value(3.0).endArray()
|
||||
.startArray().value(102.0).value(2.0).endArray()
|
||||
.endArray()
|
||||
.endArray()
|
||||
|
||||
.endArray()
|
||||
.endObject();
|
||||
|
||||
List<Coordinate> shellCoordinates = new ArrayList<Coordinate>();
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
|
||||
List<Coordinate> holeCoordinates = new ArrayList<Coordinate>();
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(
|
||||
shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
LinearRing[] holes = new LinearRing[1];
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(
|
||||
holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
||||
Polygon withHoles = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||
|
||||
shellCoordinates = new ArrayList<Coordinate>();
|
||||
shellCoordinates.add(new Coordinate(102, 2));
|
||||
shellCoordinates.add(new Coordinate(103, 2));
|
||||
shellCoordinates.add(new Coordinate(103, 3));
|
||||
shellCoordinates.add(new Coordinate(102, 3));
|
||||
shellCoordinates.add(new Coordinate(102, 2));
|
||||
|
||||
shell = GEOMETRY_FACTORY.createLinearRing(
|
||||
shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
Polygon withoutHoles = GEOMETRY_FACTORY.createPolygon(shell, null);
|
||||
|
||||
MultiPolygon multiPolygon = GEOMETRY_FACTORY.createMultiPolygon(new Polygon[] {withHoles, withoutHoles});
|
||||
|
||||
assertSerializationEquals(expected, new JtsGeometry(multiPolygon, GeoShapeConstants.SPATIAL_CONTEXT, false));
|
||||
}
|
||||
|
||||
private void assertSerializationEquals(XContentBuilder expected, Shape shape) throws IOException {
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||
builder.startObject();
|
||||
|
|
Loading…
Reference in New Issue