iGN5117 commented on code in PR #877:
URL: https://github.com/apache/sedona/pull/877#discussion_r1248087645


##########
docs/api/sql/Function.md:
##########
@@ -381,6 +381,32 @@ SELECT ST_Centroid(polygondf.countyshape)
 FROM polygondf
 ```
 
+## ST_ClosestPoint
+
+Introduction: Returns the 2-dimensional point on geom1 that is closest to 
geom2. This is the first point of the shortest line between the geometries. If 
using 3D geometries, the Z coordinates will be ignored. If you have a 3D 
Geometry, you may prefer to use ST_3DClosestPoint.
+

Review Comment:
   Update documentation here to include the thrown exception if any of the 
geometry is empty



##########
common/src/test/java/org/apache/sedona/common/FunctionsTest.java:
##########
@@ -1200,6 +1199,74 @@ public void geometryTypeWithMeasuredCollection() {
         assertEquals(expected4, actual4);
     }
 
+    @Test
+    public void closestPoint() {
+        Point point1 = GEOMETRY_FACTORY.createPoint(new Coordinate(1, 1));
+        LineString lineString1 = 
GEOMETRY_FACTORY.createLineString(coordArray(1, 0, 1, 1, 2, 1, 2, 0, 1, 0));
+        String expected1 = "POINT (1 1)";
+        String actual1 = Functions.closestPoint(point1, lineString1).toText();
+        assertEquals(expected1, actual1);
+
+        Point point2 = GEOMETRY_FACTORY.createPoint(new Coordinate(160, 40));
+        LineString lineString2 = 
GEOMETRY_FACTORY.createLineString(coordArray(10, 30, 50, 50, 30, 110, 70, 90, 
180, 140, 130, 190));
+        String expected2 = "POINT (160 40)";
+        String actual2 = Functions.closestPoint(point2, lineString2).toText();
+        assertEquals(expected2, actual2);
+        Point expectedPoint3 = GEOMETRY_FACTORY.createPoint(new 
Coordinate(125.75342465753425, 115.34246575342466));
+        Double expected3 = Functions.closestPoint(lineString2, 
point2).distance(expectedPoint3);
+        assertEquals(expected3, 0, 1e-6);
+
+        Point point4 = GEOMETRY_FACTORY.createPoint(new Coordinate(80, 160));
+        Polygon polygonA = GEOMETRY_FACTORY.createPolygon(coordArray(190, 150, 
20, 10, 160, 70, 190, 150));
+        Geometry polygonB = Functions.buffer(point4, 30);
+        Point expectedPoint4 = GEOMETRY_FACTORY.createPoint(new 
Coordinate(131.59149149528952, 101.89887534906197));
+        Double expected4 = Functions.closestPoint(polygonA, 
polygonB).distance(expectedPoint4);
+        assertEquals(expected4, 0, 1e-6);
+    }
+
+    @Test
+    public void closestPoint3d() {
+        // One of the object is 3D
+        Point point1 = GEOMETRY_FACTORY.createPoint(new Coordinate(1, 
1,10000));
+        LineString lineString1 = 
GEOMETRY_FACTORY.createLineString(coordArray(1, 0, 1, 1, 2, 1, 2, 0, 1, 0));
+        String expected1 = "POINT (1 1)";
+        String actual1 = Functions.closestPoint(point1, lineString1).toText();
+        assertEquals(expected1, actual1);
+
+        // Both of the object are 3D
+        LineString lineString3D = 
GEOMETRY_FACTORY.createLineString(coordArray3d(1, 0, 100, 1, 1, 20, 2, 1, 40, 
2, 0, 60, 1, 0, 70));
+        String expected2 = "POINT (1 1)";
+        String actual2 = Functions.closestPoint(point1, lineString3D).toText();
+        assertEquals(expected2, actual2);
+    }
+
+    @Test
+    public void closestPointGeomtryCollection() {
+        LineString line = GEOMETRY_FACTORY.createLineString(coordArray(2, 0, 
0, 2));
+        Geometry[] geometry = new Geometry[] {
+                GEOMETRY_FACTORY.createLineString(coordArray(2, 0, 2, 1)),
+                GEOMETRY_FACTORY.createPolygon(coordArray(0.0, 0.0, 1.0, 1.0, 
1.0, 0.0, 0.0, 0.0))
+        };
+        GeometryCollection geometryCollection = 
GEOMETRY_FACTORY.createGeometryCollection(geometry);
+        String actual1 = Functions.closestPoint(line, 
geometryCollection).toText();
+        String expected1 = "POINT (2 0)";
+        assertEquals(actual1 ,expected1);
+    }
+
+    @Test
+    public void closestPointEmpty() {
+        // One of the object is empty
+        Point point = GEOMETRY_FACTORY.createPoint(new Coordinate(1, 1));
+        LineString emptyLineString = GEOMETRY_FACTORY.createLineString();
+        Geometry actual = Functions.closestPoint(point, emptyLineString);
+        assertNull(actual);
+
+        // Both objects are empty
+        Polygon emptyPolygon = GEOMETRY_FACTORY.createPolygon();

Review Comment:
   refactor these test cases to catch the meaningful exception.
   There would be 2 asserts, 1 for the type of exception thrown, 1 for the 
message in the exception.
   Check implementation and tests of nRings for reference



##########
common/src/test/java/org/apache/sedona/common/FunctionsTest.java:
##########
@@ -1200,6 +1199,31 @@ public void geometryTypeWithMeasuredCollection() {
         assertEquals(expected4, actual4);
     }
 
+    @Test
+    public void closestPoint() {
+        Point point1 = GEOMETRY_FACTORY.createPoint(new Coordinate(1, 1));
+        LineString lineString1 = 
GEOMETRY_FACTORY.createLineString(coordArray(1, 0, 1, 1, 2, 1, 2, 0, 1, 0));
+        String expected1 = "POINT (1 1)";
+        String actual1 = Functions.closestPoint(point1, lineString1).toText();
+        assertEquals(expected1, actual1);
+
+        Point point2 = GEOMETRY_FACTORY.createPoint(new Coordinate(160, 40));
+        LineString lineString2 = 
GEOMETRY_FACTORY.createLineString(coordArray(10, 30, 50, 50, 30, 110, 70, 90, 
180, 140, 130, 190));
+        String expected2 = "POINT (160 40)";
+        String actual2 = Functions.closestPoint(point2, lineString2).toText();
+        assertEquals(expected2, actual2);
+        Point expectedPoint3 = GEOMETRY_FACTORY.createPoint(new 
Coordinate(125.75342465753425, 115.34246575342466));
+        Double expected3 = Functions.closestPoint(lineString2, 
point2).distance(expectedPoint3);
+        assertEquals(expected3, 0, 1e-3);
+
+        Point point4 = GEOMETRY_FACTORY.createPoint(new Coordinate(80, 160));
+        Polygon polygonA = GEOMETRY_FACTORY.createPolygon(coordArray(190, 150, 
20, 10, 160, 70, 190, 150));
+        Geometry polygonB = Functions.buffer(point4, 30);
+        Point expectedPoint4 = GEOMETRY_FACTORY.createPoint(new 
Coordinate(131.59149149528952, 101.89887534906197));
+        Double expected4 = Functions.closestPoint(polygonA, 
polygonB).distance(expectedPoint4);
+        assertEquals(expected4, 0, 1e-6);
+    }

Review Comment:
   There could be many possible use cases. Like given a geometry collection 
representing a neighborhood (polygon/multipolygon for houses), find closest 
point to a given external point. 



##########
docs/api/flink/Function.md:
##########
@@ -363,6 +363,31 @@ Input: `MULTILINESTRING((0 0, 10 0, 10 10, 0 10, 0 0),(10 
10, 20 10, 20 20, 10 2
 
 Output: `MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((10 10,10 20,20 20,20 10,10 
10)))`
 
+## ST_ClosestPoint
+
+Introduction: Returns the 2-dimensional point on geom1 that is closest to 
geom2. This is the first point of the shortest line between the geometries.
+
+Format: `ST_ClosestPoint(g1: geomtry, g2: geometry)`
+
+Since: `1.5.0`
+
+Example1:
+```sql
+SELECT ST_AsText( ST_ClosestPoint(g1, g2)) As ptwkt;

Review Comment:
   Update documentation here to include the thrown exception if any of the 
geometry is empty



##########
common/src/main/java/org/apache/sedona/common/Functions.java:
##########
@@ -447,6 +448,17 @@ public static Geometry lineFromMultiPoint(Geometry 
geometry) {
         return GEOMETRY_FACTORY.createLineString(coordinates.toArray(new 
Coordinate[0]));
     }
 
+    public static Geometry closestPoint(Geometry left, Geometry right) {
+        DistanceOp distanceOp = new DistanceOp(left, right);
+        try {
+            Coordinate[] closestPoints = distanceOp.nearestPoints();
+            return GEOMETRY_FACTORY.createPoint(closestPoints[0]);
+        }
+        catch (Exception e) {
+            return null;

Review Comment:
   Do not throw null here, throw a meaningful exception. If this is thrown if 
the geometry is empty, throw an IllegalArgumentException with an appropriate 
message



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to