Added MultiPolygon parsing and serialization support

This commit is contained in:
Chris Male 2012-09-21 23:36:19 +12:00 committed by Shay Banon
parent 8080fdc509
commit 4f5e62e988
4 changed files with 203 additions and 10 deletions

View File

@ -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}.

View File

@ -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
*/

View File

@ -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();

View File

@ -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();