From bf26811fd215394821efd23f6275ff76287fa3a2 Mon Sep 17 00:00:00 2001 From: jericks Date: Thu, 9 Oct 2014 19:43:07 -0700 Subject: [PATCH] Add curved geometry support: CircularStrings and CompoundCurves --- doc/api/geom.rst | 2 + doc/api/geom/circularstring.rst | 57 ++++++ doc/api/geom/compoundcurve.rst | 56 ++++++ .../org/geoscript/js/geom/CircularString.java | 139 +++++++++++++ .../org/geoscript/js/geom/CompoundCurve.java | 188 ++++++++++++++++++ .../geoscript/js/geom/GeometryWrapper.java | 4 + .../java/org/geoscript/js/geom/Module.java | 3 +- src/main/java/org/geoscript/js/io/WKT.java | 3 +- .../org/geoscript/js/lib/geoscript/geom.js | 31 +++ .../geoscript/geom/test_circularstring.js | 41 ++++ .../geoscript/geom/test_compoundcurve.js | 59 ++++++ .../geoscript/js/tests/geoscript/test_geom.js | 2 + 12 files changed, 583 insertions(+), 2 deletions(-) create mode 100644 doc/api/geom/circularstring.rst create mode 100644 doc/api/geom/compoundcurve.rst create mode 100644 src/main/java/org/geoscript/js/geom/CircularString.java create mode 100644 src/main/java/org/geoscript/js/geom/CompoundCurve.java create mode 100644 src/test/resources/org/geoscript/js/tests/geoscript/geom/test_circularstring.js create mode 100644 src/test/resources/org/geoscript/js/tests/geoscript/geom/test_compoundcurve.js diff --git a/doc/api/geom.rst b/doc/api/geom.rst index be2ef21b..f0ffad7e 100644 --- a/doc/api/geom.rst +++ b/doc/api/geom.rst @@ -24,6 +24,8 @@ Constructors geom/multilinestring geom/multipolygon geom/bounds + geom/circularstring + geom/compoundcurve Module Data diff --git a/doc/api/geom/circularstring.rst b/doc/api/geom/circularstring.rst new file mode 100644 index 00000000..b662885e --- /dev/null +++ b/doc/api/geom/circularstring.rst @@ -0,0 +1,57 @@ +:class:`geom.CircularString` +======================== + +.. class:: geom.CircularString(coords) + + :arg Array coords: Coordinates array. + + Create a new circularstring. + + +Example Use +----------- + +Sample code to new circularstring: + +.. code-block:: javascript + + >> var CircularString = require("geoscript/geom").CircularString; + >> var cs = new CircularString([[6.12, 10.0], [7.07, 7.07], [10.0, 0.0]]); + >> cs.controlPoints.length + 3 + >> cs.linear.getGeometryType() + LineString + >> cs.curvedWkt + CIRCULARSTRING(6.12 10.0, 7.07 7.07, 10.0 0.0) + + +Properties +---------- + +In addition to the properties common to :class:`geom.LineString` subclasses, +circularstring geometries have the properties documented below. + + +.. attribute:: CircularString.curvedWkt + + :class:`String` + The curved WKT as a string. + +.. attribute:: CircularString.controlPoints + + ``Array`` + An array of the original control Points. + + +.. attribute:: CircularString.linear + + :class:`geom.LineString` + A linearized LineString. + + + +Methods +------- + +CircularString geometries have the methods common to :class:`geom.LineString` +subclasses. diff --git a/doc/api/geom/compoundcurve.rst b/doc/api/geom/compoundcurve.rst new file mode 100644 index 00000000..7a3f1a25 --- /dev/null +++ b/doc/api/geom/compoundcurve.rst @@ -0,0 +1,56 @@ +:class:`geom.CompoundCurve` +=========================== + +.. class:: geom.CompoundCurve(lineStrings) + + :arg Array lineStrings: An array of LineStrings or CircularStrings. + + Create a new CompoundCurve. + + +Example Use +----------- + +Sample code to new compoundcurve: + +.. code-block:: javascript + + >> var GEOM = require("geoscript/geom"); + >> var cs = new GEOM.CircularString([[10.0, 10.0], [0.0, 20.0], [-10.0, 10.0]]); + >> var line = new GEOM.LineString([[-10.0, 10.0], [-10.0, 0.0], [10.0, 0.0], [5.0, 5.0]]) + >> var cc = new GEOM.CompoundCurve([cs, line]); + >> cc.components.length + 2 + >> cc.linear.getGeometryType() + LineString + >> cc.curvedWkt + COMPOUNDCURVE(CIRCULARSTRING(10.0 10.0, 0.0 20.0, -10.0 10.0), (-10.0 10.0, -10.0 0.0, 10.0 0.0, 5.0 5.0)) + + +Properties +---------- + +In addition to the properties common to all :class:`geom.LineString` subclasses, +compoundcurve geometries have the properties documented below. + + +.. attribute:: CompoundCurve.components + + :class:`geom.LineString` + The original LineString or CircularStrings. + +.. attribute:: CircularString.curvedWkt + + :class:`String` + The curved WKT as a string. + +.. attribute:: CircularString.linear + + :class:`geom.LineString` + A linearized LineString. + +Methods +------- + +CompoundCurve geometries have the methods common to all :class:`geom.LineString` +subclasses. diff --git a/src/main/java/org/geoscript/js/geom/CircularString.java b/src/main/java/org/geoscript/js/geom/CircularString.java new file mode 100644 index 00000000..cf623e58 --- /dev/null +++ b/src/main/java/org/geoscript/js/geom/CircularString.java @@ -0,0 +1,139 @@ +package org.geoscript.js.geom; + +import com.vividsolutions.jts.geom.Coordinate; +import org.geotools.geometry.jts.CurvedGeometryFactory; +import org.mozilla.javascript.*; +import org.mozilla.javascript.annotations.JSConstructor; +import org.mozilla.javascript.annotations.JSGetter; + +import java.util.ArrayList; +import java.util.List; + +public class CircularString extends LineString implements Wrapper { + + /** serialVersionUID */ + private static final long serialVersionUID = -5048539260091857410L; + + /** + * Prototype constructor. + * @return + */ + public CircularString() { + } + + /** + * Constructor for config object. + * @param config + */ + public CircularString(NativeObject config) { + NativeArray array = (NativeArray) config.get("coordinates", config); + double tolerance = config.has("tolerance", config) ? (Double) config.get("tolerance", config) : Double.MAX_VALUE; + Coordinate[] coords = arrayToCoords(array); + setGeometry(createCircularString(coords, tolerance)); + } + + /** + * Constructor for config object (without new keyword). + * @param scope + * @param config + */ + public CircularString(Scriptable scope, NativeObject config) { + this(config); + this.setParentScope(scope); + this.setPrototype(Module.getClassPrototype(CircularString.class)); + } + + /** + * Constructor from JTS geometry. + * @param geometry + */ + public CircularString(Scriptable scope, org.geotools.geometry.jts.CircularString geometry) { + this.setParentScope(scope); + this.setPrototype(Module.getClassPrototype(CircularString.class)); + setGeometry(geometry); + } + + /** + * JavaScript constructor. + * @param cx + * @param args + * @param ctorObj + * @param inNewExpr + * @return + */ + @JSConstructor + public static Object constructor(Context cx, Object[] args, Function ctorObj, boolean inNewExpr) { + if (args.length != 1) { + throw ScriptRuntime.constructError("Error", "CircularString constructor takes a single argument"); + } + NativeObject config = prepConfig(cx, (Scriptable) args[0]); + CircularString line = null; + if (inNewExpr) { + line = new CircularString(config); + } else { + line = new CircularString(config.getParentScope(), config); + } + return line; + } + + /** + * Create a CircularString from an array of Coordinates and a tolerance used to linearize the curve. + * @param coords The Array of Coordinates + * @param tolerance The tolerance used to linearize the curve + * @return A CircularString + */ + private com.vividsolutions.jts.geom.Geometry createCircularString(Coordinate[] coords, double tolerance) { + CurvedGeometryFactory factory = new CurvedGeometryFactory(tolerance); + double[] values = new double[coords.length * 2]; + for(int i = 0; i < coords.length; i++) { + int c = i * 2; + values[c] = coords[i].x; + values[c + 1] = coords[i].y; + } + return new org.geotools.geometry.jts.CircularString(values, factory, tolerance); + } + + /** + * Get the curved WKT + * @return The curved WKT + */ + @JSGetter + public String getCurvedWkt() { + return ((org.geotools.geometry.jts.CircularString)getGeometry()).toCurvedText(); + } + + /** + * Get the original control Points (not the linearized Points) + * @return The original control Points + */ + @JSGetter + public NativeArray getControlPoints() { + Context cx = getCurrentContext(); + List points = new ArrayList<>(); + org.geotools.geometry.jts.CircularString cs = (org.geotools.geometry.jts.CircularString)getGeometry(); + double[] cp = cs.getControlPoints(); + for(int i=0; i lines = new ArrayList(); + for (int i=0; i lineStrings = new ArrayList(); + List lines = cs.getComponents(); + for (com.vividsolutions.jts.geom.LineString line : lines) { + lineStrings.add((LineString)GeometryWrapper.wrap(getParentScope(), line)); + } + return (NativeArray) cx.newArray(getParentScope(), lineStrings.toArray()); + } + + /** + * Get the linearized Geometry + * @return The linearized Geometry + */ + @JSGetter + public Geometry getLinear() { + org.geotools.geometry.jts.CompoundCurve cs = (org.geotools.geometry.jts.CompoundCurve)getGeometry(); + return (Geometry) GeometryWrapper.wrap(getParentScope(), cs.linearize()); + } + + /** + * Returns underlying JTS geometry. + */ + public org.geotools.geometry.jts.CompoundCurve unwrap() { + return (org.geotools.geometry.jts.CompoundCurve) getGeometry(); + } +} diff --git a/src/main/java/org/geoscript/js/geom/GeometryWrapper.java b/src/main/java/org/geoscript/js/geom/GeometryWrapper.java index 4f3f7f20..029f6dbb 100644 --- a/src/main/java/org/geoscript/js/geom/GeometryWrapper.java +++ b/src/main/java/org/geoscript/js/geom/GeometryWrapper.java @@ -10,6 +10,10 @@ public static ScriptableObject wrap(Scriptable scope, com.vividsolutions.jts.geo try { if (geometry instanceof com.vividsolutions.jts.geom.Point) { wrapped = new Point(scope, (com.vividsolutions.jts.geom.Point) geometry); + } else if (geometry instanceof org.geotools.geometry.jts.CompoundCurve) { + wrapped = new CompoundCurve(scope, (org.geotools.geometry.jts.CompoundCurve) geometry); + } else if (geometry instanceof org.geotools.geometry.jts.CircularString) { + wrapped = new CircularString(scope, (org.geotools.geometry.jts.CircularString) geometry); } else if (geometry instanceof com.vividsolutions.jts.geom.LineString) { wrapped = new LineString(scope, (com.vividsolutions.jts.geom.LineString) geometry); } else if (geometry instanceof com.vividsolutions.jts.geom.Polygon) { diff --git a/src/main/java/org/geoscript/js/geom/Module.java b/src/main/java/org/geoscript/js/geom/Module.java index 592dd680..9c537388 100644 --- a/src/main/java/org/geoscript/js/geom/Module.java +++ b/src/main/java/org/geoscript/js/geom/Module.java @@ -30,7 +30,8 @@ public static void init(Scriptable scope) throws IllegalAccessException, Instant List> classes = Arrays.asList( Geometry.class, Point.class, LineString.class, Polygon.class, GeometryCollection.class, MultiPoint.class, - MultiLineString.class, MultiPolygon.class, Bounds.class); + MultiLineString.class, MultiPolygon.class, Bounds.class, + CircularString.class, CompoundCurve.class); prototypes = new HashMap(); for (Class cls : classes) { diff --git a/src/main/java/org/geoscript/js/io/WKT.java b/src/main/java/org/geoscript/js/io/WKT.java index f9b1e1df..c6b9833e 100644 --- a/src/main/java/org/geoscript/js/io/WKT.java +++ b/src/main/java/org/geoscript/js/io/WKT.java @@ -11,11 +11,12 @@ import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; +import org.geotools.geometry.jts.WKTReader2; import com.vividsolutions.jts.io.WKTWriter; public class WKT { - static WKTReader wktReader = new WKTReader(); + static WKTReader wktReader = new WKTReader2(); static WKTWriter wktWriter = new WKTWriter(); /** diff --git a/src/main/resources/org/geoscript/js/lib/geoscript/geom.js b/src/main/resources/org/geoscript/js/lib/geoscript/geom.js index f22b1efb..44e19ae4 100644 --- a/src/main/resources/org/geoscript/js/lib/geoscript/geom.js +++ b/src/main/resources/org/geoscript/js/lib/geoscript/geom.js @@ -165,6 +165,37 @@ registry.register(new Factory(exports.MultiPolygon, { } })); +/** api: classes[] = circularstring */ +exports.CircularString = this["org.geoscript.js.geom.CircularString"]; + +//register a circularstring factory for the module +registry.register(new Factory(exports.CircularString, { + handles: function(config) { + config = prepConfig(config); + var capable = false; + if (config.coordinates && UTIL.isArray(config.coordinates)) { + for (var i=0, ii=config.coordinates.length; i