This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new a3a44f4c7b [CALCITE-5362] Geometry measurement functions
a3a44f4c7b is described below

commit a3a44f4c7b0a08f8d31dec05381b251ad6ba3f9c
Author: Bertil Chapuis <[email protected]>
AuthorDate: Wed Nov 2 22:18:09 2022 +0100

    [CALCITE-5362] Geometry measurement functions
---
 .../calcite/runtime/SpatialTypeFunctions.java      | 172 +++++++++++++++-
 core/src/test/resources/sql/spatial.iq             | 228 ++++++++++++++++++++-
 site/_docs/reference.md                            |  24 ++-
 3 files changed, 400 insertions(+), 24 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/runtime/SpatialTypeFunctions.java 
b/core/src/main/java/org/apache/calcite/runtime/SpatialTypeFunctions.java
index 8ba060348b..720b7968f6 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SpatialTypeFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SpatialTypeFunctions.java
@@ -38,6 +38,7 @@ import org.locationtech.jts.geom.GeometryCollection;
 import org.locationtech.jts.geom.GeometryComponentFilter;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.jts.geom.GeometryFilter;
+import org.locationtech.jts.geom.LineSegment;
 import org.locationtech.jts.geom.LineString;
 import org.locationtech.jts.geom.LinearRing;
 import org.locationtech.jts.geom.MultiLineString;
@@ -49,6 +50,8 @@ import org.locationtech.jts.geom.Polygon;
 import org.locationtech.jts.geom.PrecisionModel;
 import org.locationtech.jts.geom.util.AffineTransformation;
 import org.locationtech.jts.geom.util.GeometryFixer;
+import org.locationtech.jts.linearref.LengthIndexedLine;
+import org.locationtech.jts.operation.distance.DistanceOp;
 import org.locationtech.jts.operation.linemerge.LineMerger;
 import org.locationtech.jts.operation.overlay.snap.GeometrySnapper;
 import org.locationtech.jts.operation.polygonize.Polygonizer;
@@ -60,6 +63,7 @@ import org.locationtech.jts.util.GeometricShapeFactory;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
 import java.util.stream.Stream;
@@ -290,7 +294,7 @@ public class SpatialTypeFunctions {
   /**
    * Converts the coordinates of a {@code geom} into a MULTIPOINT.
    */
-  public static Geometry ST_ToMultiPoint(Geometry geom) {
+  public static @Nullable Geometry ST_ToMultiPoint(Geometry geom) {
     CoordinateSequence coordinateSequence = GEOMETRY_FACTORY
         .getCoordinateSequenceFactory().create(geom.getCoordinates());
     return GEOMETRY_FACTORY.createMultiPoint(coordinateSequence);
@@ -299,7 +303,7 @@ public class SpatialTypeFunctions {
   /**
    * Converts the a {@code geom} into a MULTILINESTRING.
    */
-  public static Geometry ST_ToMultiLine(Geometry geom) {
+  public static @Nullable Geometry ST_ToMultiLine(Geometry geom) {
     GeometryFactory factory = geom.getFactory();
     ArrayList<LineString> lines = new ArrayList<>();
     geom.apply((GeometryComponentFilter) inputGeom -> {
@@ -317,7 +321,7 @@ public class SpatialTypeFunctions {
   /**
    * Converts a {@code geom} into a set of distinct segments stored in a 
MULTILINESTRING.
    */
-  public static Geometry ST_ToMultiSegments(Geometry geom) {
+  public static @Nullable Geometry ST_ToMultiSegments(Geometry geom) {
     GeometryFactory factory = geom.getFactory();
     ArrayList<LineString> lines = new ArrayList<>();
     geom.apply((GeometryComponentFilter) inputGeom -> {
@@ -1318,6 +1322,168 @@ public class SpatialTypeFunctions {
     return transformation.transform(geom);
   }
 
+  // Geometry measurement functions
+
+  /**
+   * Returns the area of the {@code geom}.
+   */
+  public static @Nullable Double ST_Area(Geometry geom) {
+    return geom.getArea();
+  }
+
+  /**
+   * Returns the coordinate(s) of {@code geom} closest to {@code point}.
+   */
+  public static @Nullable Geometry ST_ClosestCoordinate(Geometry point, 
Geometry geom) {
+    List<Coordinate> closestCoordinates = new ArrayList<>();
+    double minDistance = Double.MAX_VALUE;
+    for (Coordinate coordinate : geom.getCoordinates()) {
+      double distance = point.getCoordinate().distance(coordinate);
+      if (distance < minDistance) {
+        minDistance = distance;
+        closestCoordinates.clear();
+        closestCoordinates.add(coordinate);
+      } else if (distance == minDistance && 
!closestCoordinates.contains(coordinate)) {
+        closestCoordinates.add(coordinate);
+      }
+    }
+    if (closestCoordinates.size() == 1) {
+      return GEOMETRY_FACTORY.createPoint(closestCoordinates.get(0));
+    } else {
+      Coordinate[] coordinates = closestCoordinates.toArray(new Coordinate[0]);
+      return GEOMETRY_FACTORY.createMultiPointFromCoords(coordinates);
+    }
+  }
+
+  /**
+   * Returns the point of {@code geom1} closest to {@code geom2}.
+   */
+  public static @Nullable Geometry ST_ClosestPoint(Geometry geom1, Geometry 
geom2) {
+    return GEOMETRY_FACTORY.createPoint(DistanceOp.nearestPoints(geom1, 
geom2)[0]);
+  }
+
+  /**
+   * Returns the coordinate(s) of {@code geom} furthest from {@code point}.
+   */
+  public static @Nullable Geometry ST_FurthestCoordinate(Geometry point, 
Geometry geom) {
+    List<Coordinate> closestCoordinates = new ArrayList<>();
+    double maxDistance = Double.MIN_VALUE;
+    for (Coordinate coordinate : geom.getCoordinates()) {
+      double distance = point.getCoordinate().distance(coordinate);
+      if (distance > maxDistance) {
+        maxDistance = distance;
+        closestCoordinates.clear();
+        closestCoordinates.add(coordinate);
+      } else if (distance == maxDistance && 
!closestCoordinates.contains(coordinate)) {
+        closestCoordinates.add(coordinate);
+      }
+    }
+    if (closestCoordinates.size() == 1) {
+      return GEOMETRY_FACTORY.createPoint(closestCoordinates.get(0));
+    } else {
+      Coordinate[] coordinates = closestCoordinates.toArray(new Coordinate[0]);
+      return GEOMETRY_FACTORY.createMultiPointFromCoords(coordinates);
+    }
+  }
+
+  /**
+   * Returns the length of the {@code geom}.
+   */
+  public static @Nullable Double ST_Length(Geometry geom) {
+    return geom.getLength();
+  }
+
+  /**
+   * Returns a MULTIPOINT containing points along the line segments of {@code 
geom}
+   * at {@code segmentLengthFraction} and {@code offsetDistance}.
+   */
+  public static @Nullable Geometry ST_LocateAlong(Geometry geom, BigDecimal 
segmentLengthFraction,
+      BigDecimal offsetDistance) {
+    List<Coordinate> coordinates = new ArrayList<>();
+    for (int i = 0; i < geom.getNumGeometries(); i++) {
+      Geometry geometry = geom.getGeometryN(i);
+      Coordinate[] geometryCoordinates = geometry.getCoordinates();
+      for (int j = 0; j < geometryCoordinates.length - 1; j++) {
+        Coordinate c1 = geometryCoordinates[j];
+        Coordinate c2 = geometryCoordinates[j + 1];
+        LineSegment lineSegment = new LineSegment(c1, c2);
+        coordinates.add(
+            lineSegment.pointAlongOffset(
+            segmentLengthFraction.doubleValue(),
+            offsetDistance.doubleValue()));
+      }
+    }
+    Coordinate[] coordinateArray = coordinates.toArray(new Coordinate[0]);
+    return GEOMETRY_FACTORY.createMultiPointFromCoords(coordinateArray);
+  }
+
+  /**
+   * Returns the 2-dimensional longest line-string between the points
+   * of {@code geom1} and {@code geom2}.
+   */
+  public static @Nullable Geometry ST_LongestLine(Geometry geom1, Geometry 
geom2) {
+    double maxDistance = Double.MIN_VALUE;
+    Coordinate c1 = null;
+    Coordinate c2 = null;
+    for (Coordinate coordinate1 : geom1.getCoordinates()) {
+      for (Coordinate coordinate2 : geom2.getCoordinates()) {
+        double distance = coordinate1.distance(coordinate2);
+        if (distance > maxDistance) {
+          maxDistance = distance;
+          c1 = coordinate1;
+          c2 = coordinate2;
+        }
+      }
+    }
+    if (c1 == null || c2 == null) {
+      return null;
+    }
+    return GEOMETRY_FACTORY.createLineString(new Coordinate[] {c1, c2});
+  }
+
+  /**
+   * Computes the maximum distance between {@code geom1} and {@code geom2}.
+   */
+  public static @Nullable Double ST_MaxDistance(Geometry geom1, Geometry 
geom2) {
+    double maxDistance = Double.MIN_VALUE;
+    for (Coordinate coordinate1 : geom1.getCoordinates()) {
+      for (Coordinate coordinate2 : geom2.getCoordinates()) {
+        double distance = coordinate1.distance(coordinate2);
+        if (distance > maxDistance) {
+          maxDistance = distance;
+        }
+      }
+    }
+    return maxDistance;
+  }
+
+  /**
+   * Returns the length of the perimeter of *polygon* (which may be a 
MULTIPOLYGON).
+   */
+  public static @Nullable Double ST_Perimeter(Geometry geom) {
+    double perimeter = 0;
+    for (int i = 0; i < geom.getNumGeometries(); i++) {
+      Geometry geometry = geom.getGeometryN(i);
+      if (geometry instanceof Polygon) {
+        perimeter += geometry.getLength();
+      }
+    }
+    return perimeter;
+  }
+
+  /**
+   * Projects {@code point} onto a {@code lineString} (which may be a 
MULTILINESTRING).
+   */
+  public static @Nullable Geometry ST_ProjectPoint(Geometry point, Geometry 
lineString) {
+    if (lineString.getDimension() > 1) {
+      return null;
+    }
+    LengthIndexedLine lengthIndexedLine = new LengthIndexedLine(lineString);
+    double index = lengthIndexedLine.project(point.getCoordinate());
+    Coordinate projectedCoordinate = lengthIndexedLine.extractPoint(index);
+    return GEOMETRY_FACTORY.createPoint(projectedCoordinate);
+  }
+
   // Space-filling curves
 
   /**
diff --git a/core/src/test/resources/sql/spatial.iq 
b/core/src/test/resources/sql/spatial.iq
index 9ec31ccf9a..4f7fa14c60 100644
--- a/core/src/test/resources/sql/spatial.iq
+++ b/core/src/test/resources/sql/spatial.iq
@@ -135,6 +135,7 @@ srid:4326;LINESTRING (1 2, 3 4)
 !ok
 
 # ST_GeomFromText(wkt [, srid ]) Returns a specified geometry value from 
Well-Known Text representation
+
 SELECT ST_GeomFromText('LINESTRING(-71.160281 42.258729,-71.160837 
42.259113,-71.161144 42.25932)');
 EXPR$0
 LINESTRING (-71.160281 42.258729, -71.160837 42.259113, -71.161144 42.25932)
@@ -1654,34 +1655,241 @@ GEOMETRYCOLLECTION (POLYGON ((-1 1, 2 6, 5 7, -1 8, -1 
1)), MULTIPOINT ((-1 2),
 #### Geometry measurement functions (2D)
 
 # ST_Area(geom) Returns the area of *geom* (which may be a geometry collection)
-# Not implemented
+
+SELECT ST_Area('POINT(0 12)');
+EXPR$0
+0.0
+!ok
+
+SELECT ST_Area('LINESTRING(5 4, 1 1, 3 4, 4 5)');
+EXPR$0
+0.0
+!ok
+
+SELECT ST_Area('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))');
+EXPR$0
+100.0
+!ok
+
+SELECT ST_Area('MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0), (5 4, 1 1, 3 4, 4 
5, 5 4)))');
+EXPR$0
+96.0
+!ok
+
+SELECT ST_Area('GEOMETRYCOLLECTION(LINESTRING(5 4, 1 1, 3 4, 4 5), POINT(0 
12), POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)), POLYGON((5 4, 1 1, 3 4, 4 5, 5 
4)))');
+EXPR$0
+104.0
+!ok
 
 # ST_ClosestCoordinate(geom, point) Returns the coordinate(s) of *geom* 
closest to *point*
-# Not implemented
+
+SELECT ST_ClosestCoordinate('POINT(0 0)', 'POLYGON((2 2, 10 0, 10 5, 0 5, 2 
2))');
+EXPR$0
+POINT (2 2)
+!ok
+
+SELECT ST_ClosestCoordinate('POINT(4 2.5)', 'POLYGON((0 0, 10 0, 10 5, 0 5, 0 
0))');
+EXPR$0
+MULTIPOINT ((0 0), (0 5))
+!ok
+
+SELECT ST_ClosestCoordinate('POINT(4 2)', 'LINESTRING(10 0, 10 5, 0 5)');
+EXPR$0
+POINT (0 5)
+!ok
 
 # ST_ClosestPoint(geom1, geom2) Returns the point of *geom1* closest to *geom2*
-# Not implemented
+
+SELECT  ST_ClosestPoint('POLYGON((0 0, 10 0, 10 5, 0 5, 0 0))', 'POINT(4 2)');
+EXPR$0
+POINT (4 2)
+!ok
+
+SELECT  ST_ClosestPoint('POLYGON((0 0, 10 0, 10 5, 0 5, 0 0))', 'POINT(5 7)');
+EXPR$0
+POINT (5 5)
+!ok
+
+SELECT ST_ClosestPoint('LINESTRING(1 1, 1 5))', 'LINESTRING(2 1, 2 5))') A,
+       ST_ClosestPoint('LINESTRING(1 1, 1 5))', 'LINESTRING(2 5, 2 1))') B;
+A, B
+POINT (1 1), POINT (1 5)
+!ok
+
+SELECT ST_ClosestPoint('POLYGON((0 0, 10 0, 10 5, 0 5, 0 0))',
+                       'POLYGON((13 2, 15 0, 13 4, 13 2))') A,
+       ST_ClosestPoint('POLYGON((0 0, 10 0, 10 5, 0 5, 0 0))',
+                       'POLYGON((13 4, 13 2, 15 0, 13 4))') B;
+A, B
+POINT (10 2), POINT (10 4)
+!ok
 
 # ST_FurthestCoordinate(geom, point) Returns the coordinate(s) of *geom* that 
are furthest from *point*
-# Not implemented
+
+SELECT ST_FurthestCoordinate('POINT(0 0)', 'POLYGON((2 2, 10 0, 10 5, 0 5, 2 
2))');
+EXPR$0
+POINT (10 5)
+!ok
+
+SELECT ST_FurthestCoordinate('POINT(5 2.5)', 'LINESTRING(3 1, 2 2, 2 4, 4 5)');
+EXPR$0
+POINT (2 4)
+!ok
+
+SELECT ST_FurthestCoordinate('POINT(5 2.5)', 'POLYGON((0 0, 10 0, 10 5, 0 5, 0 
0))');
+EXPR$0
+MULTIPOINT ((0 0), (10 0), (10 5), (0 5))
+!ok
 
 # ST_Length(lineString) Returns the length of *lineString*
-# Not implemented
+
+SELECT ST_Length('MULTIPOINT((4 4), (1 1), (1 0), (0 3)))');
+EXPR$0
+0.0
+!ok
+
+SELECT ST_Length('LINESTRING(2 1, 1 3, 5 2)');
+EXPR$0
+6.35917360311745
+!ok
+
+SELECT ST_Length('POLYGON((1 2, 4 2, 4 6, 1 6, 1 2))');
+EXPR$0
+14.0
+!ok
+
+SELECT ST_Length('MULTIPOLYGON(((0 2, 3 2, 3 6, 0 6, 0 2)), ((5 0, 7 0, 7 1, 5 
1, 5 0)))');
+EXPR$0
+20.0
+!ok
+
+SELECT ST_Length('GEOMETRYCOLLECTION(
+    MULTIPOINT((4 4), (1 1), (1 0), (0 3)),
+    LINESTRING(2 1, 1 3, 5 2),
+    POLYGON((1 2, 4 2, 4 6, 1 6, 1 2)))');
+EXPR$0
+20.35917360311745
+!ok
 
 # ST_LocateAlong(geom, segmentLengthFraction, offsetDistance) Returns a 
multi-point containing points along the line segments of *geom* at 
*segmentLengthFraction* and *offsetDistance*
-# Not implemented
+
+SELECT ST_LocateAlong('LINESTRING(1 1, 5 4)', 0.5, 2.0);
+EXPR$0
+MULTIPOINT ((1.8 4.1))
+!ok
+
+SELECT ST_LocateAlong('LINESTRING(1 1, 5 1, 5 3)', 0.5, 1.0);
+EXPR$0
+MULTIPOINT ((3 2), (4 2))
+!ok
+
+SELECT ST_LocateAlong('POLYGON((1 1, 4 1, 4 3, 1 3, 1 1))', 0.5, -1.0);
+EXPR$0
+MULTIPOINT ((2.5 0), (5 2), (2.5 4), (0 2))
+!ok
+
+SELECT ST_LocateAlong('GEOMETRYCOLLECTION(
+    LINESTRING(1 4, 5 4, 5 2),
+    POLYGON((1 1, 4 1, 4 3, 1 3, 1 1)))', 2.0, 1.0);
+EXPR$0
+MULTIPOINT ((9 5), (6 0), (7 2), (3 5), (-2 2), (2 -1))
+!ok
 
 # ST_LongestLine(geom1, geom2) Returns the 2-dimensional longest line-string 
between the points of *geom1* and *geom2*
-# Not implemented
+
+SELECT ST_LongestLine('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))', 'POLYGON ((2 3, 2 
2, 3 2, 4 3, 2 3))');
+EXPR$0
+LINESTRING (0 0, 4 3)
+!ok
+
+SELECT ST_LongestLine('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))', 'LINESTRING (1 3, 
4 3)');
+EXPR$0
+LINESTRING (0 0, 4 3)
+!ok
+
+SELECT ST_LongestLine('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))', 'POINT (3 2)');
+EXPR$0
+LINESTRING (0 0, 3 2)
+!ok
+
+SELECT ST_LongestLine('MULTIPOLYGON (((0 1, 1 1, 1 0, 0 0, 0 1)), ((2 3, 2 2, 
3 3, 2 3)))', 'POINT (3 2)');
+EXPR$0
+LINESTRING (0 0, 3 2)
+!ok
+
+SELECT ST_LongestLine('POLYGON ((1 3, 0 0, 3 2, 1 3))', 'POLYGON ((1 3, 0 0, 3 
2, 1 3))');
+EXPR$0
+LINESTRING (0 0, 3 2)
+!ok
 
 # ST_MaxDistance(geom1, geom2) Computes the maximum distance between *geom1* 
and *geom2*
-# Not implemented
+
+SELECT ST_MaxDistance('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))', 'POLYGON ((2 3, 2 
2, 3 2, 4 3, 2 3))');
+EXPR$0
+5.0
+!ok
+
+SELECT ST_MaxDistance('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))', 'LINESTRING (1 3, 
4 3)');
+EXPR$0
+5.0
+!ok
+
+SELECT ST_MaxDistance('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))', 'POINT (3 2)');
+EXPR$0
+3.605551275463989
+!ok
+
+SELECT ST_MaxDistance('POLYGON ((1 3, 0 0, 3 2, 1 3))', 'POLYGON ((1 3, 0 0, 3 
2, 1 3))');
+EXPR$0
+3.605551275463989
+!ok
 
 # ST_Perimeter(polygon) Returns the length of the perimeter of *polygon* 
(which may be a multi-polygon)
-# Not implemented
+
+SELECT ST_Perimeter('POLYGON((1 2, 4 2, 4 6, 1 6, 1 2))');
+EXPR$0
+14.0
+!ok
+
+SELECT ST_Perimeter('MULTIPOLYGON(((0 2, 3 2, 3 6, 0 6, 0 2)), ((5 0, 7 0, 7 
1, 5 1, 5 0)))');
+EXPR$0
+20.0
+!ok
+
+SELECT ST_Perimeter('GEOMETRYCOLLECTION(
+                    MULTIPOINT((4 4), (1 1), (1 0), (0 3)),
+                    LINESTRING(2 1, 1 3, 5 2),
+                    POLYGON((1 2, 4 2, 4 6, 1 6, 1 2)))');
+EXPR$0
+14.0
+!ok
+
+SELECT ST_Perimeter('LINESTRING(2 1, 1 3, 5 2)');
+EXPR$0
+0.0
+!ok
 
 # ST_ProjectPoint(point, lineString) Projects *point* onto a *lineString* 
(which may be a multi-line-string)
-# Not implemented
+
+SELECT ST_PROJECTPOINT('POINT(0 4)', 'LINESTRING(0 0, 4 4)');
+EXPR$0
+POINT (2 2)
+!ok
+
+SELECT ST_PROJECTPOINT('POINT(2 4)', 'MULTILINESTRING ((0 0, 4 0), (0 2, 4 
2))');
+EXPR$0
+POINT (2 2)
+!ok
+
+SELECT ST_PROJECTPOINT('POINT(0 4)', 'LINESTRING (0 0, 4 4)');
+EXPR$0
+POINT (2 2)
+!ok
+
+SELECT ST_PROJECTPOINT('POINT(0 4)', 'POLYGON ((2 4, 0 2, 3 0, 2 4))');
+EXPR$0
+null
+!ok
 
 #### Geometry measurement functions (3D)
 
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 00e2c2048c..f51badec51 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2389,18 +2389,20 @@ Not implemented:
 
 #### Geometry measurement functions (2D)
 
-Not implemented:
+The following functions measure geometries.
 
-* ST_Area(geom) Returns the area of *geom* (which may be a GEOMETRYCOLLECTION)
-* ST_ClosestCoordinate(geom, point) Returns the coordinate(s) of *geom* 
closest to *point*
-* ST_ClosestPoint(geom1, geom2) Returns the point of *geom1* closest to *geom2*
-* ST_FurthestCoordinate(geom, point) Returns the coordinate(s) of *geom* that 
are furthest from *point*
-* ST_Length(lineString) Returns the length of *lineString*
-* ST_LocateAlong(geom, segmentLengthFraction, offsetDistance) Returns a 
MULTIPOINT containing points along the line segments of *geom* at 
*segmentLengthFraction* and *offsetDistance*
-* ST_LongestLine(geom1, geom2) Returns the 2-dimensional longest line-string 
between the points of *geom1* and *geom2*
-* ST_MaxDistance(geom1, geom2) Computes the maximum distance between *geom1* 
and *geom2*
-* ST_Perimeter(polygon) Returns the length of the perimeter of *polygon* 
(which may be a MULTIPOLYGON)
-* ST_ProjectPoint(point, lineString) Projects *point* onto a *lineString* 
(which may be a MULTILINESTRING)
+| C | Operator syntax      | Description
+|:- |:-------------------- |:-----------
+| o | ST_Area(geom) | Returns the area of *geom* (which may be a 
GEOMETRYCOLLECTION)
+| h | ST_ClosestCoordinate(point, geom) | Returns the coordinate(s) of *geom* 
closest to *point*
+| h | ST_ClosestPoint(geom1, geom2) | Returns the point of *geom1* closest to 
*geom2*
+| h | ST_FurthestCoordinate(geom, point) | Returns the coordinate(s) of *geom* 
that are furthest from *point*
+| h | ST_Length(geom) | Returns the length of *geom*
+| h | ST_LocateAlong(geom, segmentLengthFraction, offsetDistance) | Returns a 
MULTIPOINT containing points along the line segments of *geom* at 
*segmentLengthFraction* and *offsetDistance*
+| h | ST_LongestLine(geom1, geom2) | Returns the 2-dimensional longest 
line-string between the points of *geom1* and *geom2*
+| h | ST_MaxDistance(geom1, geom2) | Computes the maximum distance between 
*geom1* and *geom2*
+| h | ST_Perimeter(polygon) | Returns the length of the perimeter of *polygon* 
(which may be a MULTIPOLYGON)
+| h | ST_ProjectPoint(point, lineString) | Projects *point* onto a 
*lineString* (which may be a MULTILINESTRING)
 
 #### Geometry measurement functions (3D)
 

Reply via email to