diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultGeometry.java b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultGeometry.java index 885d9bd48b7..14d4e960c8a 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultGeometry.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultGeometry.java @@ -29,7 +29,9 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.Serializable; +import java.math.BigDecimal; import java.nio.ByteBuffer; +import java.util.List; import net.jcip.annotations.Immutable; @Immutable @@ -199,4 +201,48 @@ private void readObject(ObjectInputStream stream) throws InvalidObjectException public String toString() { return asWellKnownText(); } + + protected static void appendPosition(StringBuilder builder, double x, double y) { + builder + .append('[') + .append(formatCoordinate(x)) + .append(',') + .append(formatCoordinate(y)) + .append(']'); + } + + protected static void appendPosition(StringBuilder builder, Point point) { + appendPosition(builder, point.X(), point.Y()); + } + + protected static void appendPositions( + StringBuilder builder, List points, boolean closeRing) { + builder.append('['); + for (int i = 0; i < points.size(); i++) { + if (i > 0) { + builder.append(','); + } + appendPosition(builder, points.get(i)); + } + if (closeRing && !points.isEmpty()) { + Point first = points.get(0); + Point last = points.get(points.size() - 1); + if (!haveSameCoordinates(first, last)) { + builder.append(','); + appendPosition(builder, first); + } + } + builder.append(']'); + } + + private static boolean haveSameCoordinates(Point first, Point second) { + return Double.compare(first.X(), second.X()) == 0 && Double.compare(first.Y(), second.Y()) == 0; + } + + private static String formatCoordinate(double value) { + if (!Double.isFinite(value)) { + throw new IllegalArgumentException("Coordinate values must be finite"); + } + return BigDecimal.valueOf(value).toString(); + } } diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultLineString.java b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultLineString.java index 1cf64bb366d..5b8d5a604bf 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultLineString.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultLineString.java @@ -57,6 +57,17 @@ public List getPoints() { return points; } + @NonNull + @Override + public String asGeoJson() { + int estimatedSize = Math.max(32, points.size() * 32); + StringBuilder builder = new StringBuilder(estimatedSize); + builder.append("{\"type\":\"LineString\",\"coordinates\":"); + appendPositions(builder, points, false); + builder.append('}'); + return builder.toString(); + } + /** * This object gets replaced by an internal proxy for serialization. * diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPoint.java b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPoint.java index c9540b10d8a..ad7f5a4e14b 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPoint.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPoint.java @@ -53,6 +53,16 @@ public double Y() { return getOgcGeometry().Y(); } + @NonNull + @Override + public String asGeoJson() { + StringBuilder builder = new StringBuilder(64); + builder.append("{\"type\":\"Point\",\"coordinates\":"); + appendPosition(builder, X(), Y()); + builder.append('}'); + return builder.toString(); + } + /** * This object gets replaced by an internal proxy for serialization. * diff --git a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPolygon.java b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPolygon.java index 27d375d42b1..bedfa95d4de 100644 --- a/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPolygon.java +++ b/core/src/main/java/com/datastax/dse/driver/internal/core/data/geometry/DefaultPolygon.java @@ -71,6 +71,24 @@ public List> getInteriorRings() { return interiorRings; } + @NonNull + @Override + public String asGeoJson() { + if (exteriorRing.isEmpty()) { + return "{\"type\":\"Polygon\",\"coordinates\":[]}"; + } + int totalRings = 1 + interiorRings.size(); + StringBuilder builder = new StringBuilder(Math.max(64, totalRings * 96)); + builder.append("{\"type\":\"Polygon\",\"coordinates\":["); + appendPositions(builder, exteriorRing, true); + for (List ring : interiorRings) { + builder.append(','); + appendPositions(builder, ring, true); + } + builder.append("]}"); + return builder.toString(); + } + private static OGCPolygon fromPoints(Point p1, Point p2, Point p3, Point... pn) { com.esri.core.geometry.Polygon polygon = new com.esri.core.geometry.Polygon(); addPath(polygon, p1, p2, p3, pn); diff --git a/osgi-tests/pom.xml b/osgi-tests/pom.xml index 279b0a4635c..5d0d810f22d 100644 --- a/osgi-tests/pom.xml +++ b/osgi-tests/pom.xml @@ -95,6 +95,10 @@ com.esri.geometry esri-geometry-api + + org.json + json + org.apache.tinkerpop gremlin-core diff --git a/pom.xml b/pom.xml index defa19f606a..6fc990acb8b 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 2.2.2 4.2.37 4.1.127.Final - 1.2.1 + 2.2.4