2222import org .apache .calcite .linq4j .function .Strict ;
2323import org .apache .calcite .util .Util ;
2424
25+ import com .esri .core .geometry .Envelope ;
2526import com .esri .core .geometry .Geometry ;
2627import com .esri .core .geometry .GeometryEngine ;
28+ import com .esri .core .geometry .Line ;
2729import com .esri .core .geometry .MapGeometry ;
30+ import com .esri .core .geometry .Operator ;
31+ import com .esri .core .geometry .OperatorBoundary ;
32+ import com .esri .core .geometry .OperatorFactoryLocal ;
33+ import com .esri .core .geometry .OperatorIntersects ;
2834import com .esri .core .geometry .Point ;
2935import com .esri .core .geometry .Polygon ;
36+ import com .esri .core .geometry .Polyline ;
3037import com .esri .core .geometry .SpatialReference ;
3138import com .esri .core .geometry .WktExportFlags ;
3239import com .esri .core .geometry .WktImportFlags ;
4653 * <li>Should we create aliases for functions in upper-case?
4754 * Without ST_ prefix?
4855 * <li>Consider adding spatial literals, e.g. `GEOMETRY 'POINT (30 10)'`
49- * <li>Integer arugments, e.g. SELECT ST_MakePoint(1, 2, 1.5)
56+ * <li>Integer arguments, e.g. SELECT ST_MakePoint(1, 2, 1.5),
57+ * ST_MakePoint(1, 2)
5058 * <li>Are GEOMETRY values comparable? If so add ORDER BY test
59+ * <li>We have to add 'Z' to create 3D objects. This is inconsistent with
60+ * PostGIS. Who is right? At least document the difference.
61+ * <li>Should add GeometryEngine.intersects; similar to disjoint etc.
62+ * <li>Make {@link #ST_MakeLine(Geom, Geom)} varargs</li>
5163 * </ul>
5264 */
5365@ SuppressWarnings ({"UnnecessaryUnboxing" , "WeakerAccess" , "unused" })
@@ -168,27 +180,76 @@ public static Geom ST_MPolyFromText(String wkt, int srid) {
168180
169181 // Geometry creation functions ==============================================
170182
171- /** Constructs a 2D point from coordinates. */
172- public static Geom ST_MakePoint (BigDecimal x , BigDecimal y ) {
173- // NOTE: Combine the double and BigDecimal variants of this function
174- if (x == null || y == null ) {
175- return null ; // TODO: strictness should make this check unnecessary
176- }
177- return ST_MakePoint (x .doubleValue (), y .doubleValue ());
183+ /** Creates a line-string from the given POINTs (or MULTIPOINTs). */
184+ public static Geom ST_MakeLine (Geom geom1 , Geom geom2 ) {
185+ return makeLine (geom1 , geom2 );
178186 }
179187
180- private static Geom ST_MakePoint (double x , double y ) {
181- final Geometry g = new Point (x , y );
188+ public static Geom ST_MakeLine (Geom geom1 , Geom geom2 , Geom geom3 ) {
189+ return makeLine (geom1 , geom2 , geom3 );
190+ }
191+
192+ public static Geom ST_MakeLine (Geom geom1 , Geom geom2 , Geom geom3 ,
193+ Geom geom4 ) {
194+ return makeLine (geom1 , geom2 , geom3 , geom4 );
195+ }
196+
197+ public static Geom ST_MakeLine (Geom geom1 , Geom geom2 , Geom geom3 ,
198+ Geom geom4 , Geom geom5 ) {
199+ return makeLine (geom1 , geom2 , geom3 , geom4 , geom5 );
200+ }
201+
202+ public static Geom ST_MakeLine (Geom geom1 , Geom geom2 , Geom geom3 ,
203+ Geom geom4 , Geom geom5 , Geom geom6 ) {
204+ return makeLine (geom1 , geom2 , geom3 , geom4 , geom5 , geom6 );
205+ }
206+
207+ private static Geom makeLine (Geom ... geoms ) {
208+ final Polyline g = new Polyline ();
209+ Point p = null ;
210+ for (Geom geom : geoms ) {
211+ if (geom .g () instanceof Point ) {
212+ final Point prev = p ;
213+ p = (Point ) geom .g ();
214+ if (prev != null ) {
215+ final Line line = new Line ();
216+ line .setStart (prev );
217+ line .setEnd (p );
218+ g .addSegment (line , false );
219+ }
220+ }
221+ }
182222 return new SimpleGeom (g );
183223 }
184224
185- /** Constructs a 3D point from coordinates. */
225+ /** Alias for {@link #ST_Point(BigDecimal, BigDecimal)}. */
226+ public static Geom ST_MakePoint (BigDecimal x , BigDecimal y ) {
227+ return ST_Point (x , y );
228+ }
229+
230+ /** Alias for {@link #ST_Point(BigDecimal, BigDecimal, BigDecimal)}. */
186231 public static Geom ST_MakePoint (BigDecimal x , BigDecimal y , BigDecimal z ) {
232+ return ST_Point (x , y , z );
233+ }
234+
235+ /** Constructs a 2D point from coordinates. */
236+ public static Geom ST_Point (BigDecimal x , BigDecimal y ) {
237+ // NOTE: Combine the double and BigDecimal variants of this function
238+ return point (x .doubleValue (), y .doubleValue ());
239+ }
240+
241+ /** Constructs a 3D point from coordinates. */
242+ public static Geom ST_Point (BigDecimal x , BigDecimal y , BigDecimal z ) {
187243 final Geometry g = new Point (x .doubleValue (), y .doubleValue (),
188244 z .doubleValue ());
189245 return new SimpleGeom (g );
190246 }
191247
248+ private static Geom point (double x , double y ) {
249+ final Geometry g = new Point (x , y );
250+ return new SimpleGeom (g );
251+ }
252+
192253 // Geometry properties (2D and 3D) ==========================================
193254
194255 /** Returns whether {@code geom} has at least one z-coordinate. */
@@ -202,13 +263,141 @@ public static Double ST_Z(Geom geom) {
202263 ? ((Point ) geom .g ()).getZ () : null ;
203264 }
204265
266+ /** Returns the boundary of {@code geom}. */
267+ public static Geom ST_Boundary (Geom geom ) {
268+ OperatorBoundary op = OperatorBoundary .local ();
269+ Geometry result = op .execute (geom .g (), null );
270+ return geom .wrap (result );
271+ }
272+
205273 /** Returns the distance between {@code geom1} and {@code geom2}. */
206274 public static double ST_Distance (Geom geom1 , Geom geom2 ) {
207275 return GeometryEngine .distance (geom1 .g (), geom2 .g (), geom1 .sr ());
208276 }
209277
278+ /** Returns the type of {@code geom}. */
279+ public static String ST_GeometryType (Geom geom ) {
280+ return type (geom .g ()).name ();
281+ }
282+
283+ /** Returns the OGC SFS type code of {@code geom}. */
284+ public static int ST_GeometryTypeCode (Geom geom ) {
285+ return type (geom .g ()).code ;
286+ }
287+
288+ /** Returns the OGC type of a geometry. */
289+ private static Type type (Geometry g ) {
290+ switch (g .getType ()) {
291+ case Point :
292+ return Type .POINT ;
293+ case Polyline :
294+ return Type .LINESTRING ;
295+ case Polygon :
296+ return Type .POLYGON ;
297+ case MultiPoint :
298+ return Type .MULTIPOINT ;
299+ case Envelope :
300+ return Type .POLYGON ;
301+ case Line :
302+ return Type .LINESTRING ;
303+ case Unknown :
304+ return Type .Geometry ;
305+ default :
306+ throw new AssertionError (g );
307+ }
308+ }
309+
310+ /** Returns the minimum bounding box of {@code geom} (which may be a
311+ * GEOMETRYCOLLECTION). */
312+ public static Geom ST_Envelope (Geom geom ) {
313+ final Envelope env = envelope (geom .g ());
314+ return geom .wrap (env );
315+ }
316+
317+ private static Envelope envelope (Geometry g ) {
318+ final Envelope env = new Envelope ();
319+ g .queryEnvelope (env );
320+ return env ;
321+ }
322+
210323 // Geometry predicates ======================================================
211324
325+ /** Returns whether {@code geom1} contains {@code geom2}. */
326+ public static boolean ST_Contains (Geom geom1 , Geom geom2 ) {
327+ return GeometryEngine .contains (geom1 .g (), geom2 .g (), geom1 .sr ());
328+ }
329+
330+ /** Returns whether {@code geom1} contains {@code geom2} but does not
331+ * intersect its boundary. */
332+ public static boolean ST_ContainsProperly (Geom geom1 , Geom geom2 ) {
333+ return GeometryEngine .contains (geom1 .g (), geom2 .g (), geom1 .sr ())
334+ && !GeometryEngine .crosses (geom1 .g (), geom2 .g (), geom1 .sr ());
335+ }
336+
337+ /** Returns whether no point in {@code geom2} is outside {@code geom1}. */
338+ private static boolean ST_Covers (Geom geom1 , Geom geom2 ) {
339+ throw todo ();
340+ }
341+
342+ /** Returns whether {@code geom1} crosses {@code geom2}. */
343+ public static boolean ST_Crosses (Geom geom1 , Geom geom2 ) {
344+ return GeometryEngine .crosses (geom1 .g (), geom2 .g (), geom1 .sr ());
345+ }
346+
347+ /** Returns whether {@code geom1} and {@code geom2} are disjoint. */
348+ public static boolean ST_Disjoint (Geom geom1 , Geom geom2 ) {
349+ return GeometryEngine .disjoint (geom1 .g (), geom2 .g (), geom1 .sr ());
350+ }
351+
352+ /** Returns whether the envelope of {@code geom1} intersects the envelope of
353+ * {@code geom2}. */
354+ public static boolean ST_EnvelopesIntersect (Geom geom1 , Geom geom2 ) {
355+ final Geometry e1 = envelope (geom1 .g ());
356+ final Geometry e2 = envelope (geom2 .g ());
357+ return intersects (e1 , e2 , geom1 .sr ());
358+ }
359+
360+ /** Returns whether {@code geom1} equals {@code geom2}. */
361+ public static boolean ST_Equals (Geom geom1 , Geom geom2 ) {
362+ return GeometryEngine .equals (geom1 .g (), geom2 .g (), geom1 .sr ());
363+ }
364+
365+ /** Returns whether {@code geom1} intersects {@code geom2}. */
366+ public static boolean ST_Intersects (Geom geom1 , Geom geom2 ) {
367+ final Geometry g1 = geom1 .g ();
368+ final Geometry g2 = geom2 .g ();
369+ final SpatialReference sr = geom1 .sr ();
370+ return intersects (g1 , g2 , sr );
371+ }
372+
373+ private static boolean intersects (Geometry g1 , Geometry g2 ,
374+ SpatialReference sr ) {
375+ final OperatorIntersects op = (OperatorIntersects ) OperatorFactoryLocal
376+ .getInstance ().getOperator (Operator .Type .Intersects );
377+ return op .execute (g1 , g2 , sr , null );
378+ }
379+
380+ /** Returns whether {@code geom1} equals {@code geom2} and their coordinates
381+ * and component Geometries are listed in the same order. */
382+ public static boolean ST_OrderingEquals (Geom geom1 , Geom geom2 ) {
383+ return GeometryEngine .equals (geom1 .g (), geom2 .g (), geom1 .sr ());
384+ }
385+
386+ /** Returns {@code geom1} overlaps {@code geom2}. */
387+ public static boolean ST_Overlaps (Geom geom1 , Geom geom2 ) {
388+ return GeometryEngine .overlaps (geom1 .g (), geom2 .g (), geom1 .sr ());
389+ }
390+
391+ /** Returns whether {@code geom1} touches {@code geom2}. */
392+ public static boolean ST_Touches (Geom geom1 , Geom geom2 ) {
393+ return GeometryEngine .touches (geom1 .g (), geom2 .g (), geom1 .sr ());
394+ }
395+
396+ /** Returns whether {@code geom1} is within {@code geom2}. */
397+ public static boolean ST_Within (Geom geom1 , Geom geom2 ) {
398+ return GeometryEngine .within (geom1 .g (), geom2 .g (), geom1 .sr ());
399+ }
400+
212401 /** Returns whether {@code geom1} and {@code geom2} are within
213402 * {@code distance} of each other. */
214403 public static boolean ST_DWithin (Geom geom1 , Geom geom2 , double distance ) {
@@ -436,6 +625,27 @@ public Geom wrap(Geometry g) {
436625 return bind (g , this .mg .getSpatialReference ());
437626 }
438627 }
628+
629+ /** Geometry types, with the names and codes assigned by OGC. */
630+ enum Type {
631+ Geometry (0 ),
632+ POINT (1 ),
633+ LINESTRING (2 ),
634+ POLYGON (3 ),
635+ MULTIPOINT (4 ),
636+ MULTILINESTRING (5 ),
637+ MULTIPOLYGON (6 ),
638+ GEOMCOLLECTION (7 ),
639+ CURVE (13 ),
640+ SURFACE (14 ),
641+ POLYHEDRALSURFACE (15 );
642+
643+ final int code ;
644+
645+ Type (int code ) {
646+ this .code = code ;
647+ }
648+ }
439649}
440650
441651// End GeoFunctions.java
0 commit comments