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

jiayu pushed a commit to branch SEDONA-602
in repository https://gitbox.apache.org/repos/asf/sedona.git

commit 87c8532727cec08316cf0ea23b3828a459c12801
Author: Feng Zhang <[email protected]>
AuthorDate: Mon Jun 3 09:45:28 2024 -0700

    Merge pull request #208 from wherobots/refactor-st-locate-along
    
    [TASK-187] Refactor ST_LocateAlong implementation to remove instanceof 
operator
---
 .../java/org/apache/sedona/common/Functions.java   |   4 +-
 .../org/apache/sedona/common/utils/GeomUtils.java  |  96 ----------------
 .../common/utils/GeometryLocateAlongProcessor.java | 122 +++++++++++++++++++++
 3 files changed, 125 insertions(+), 97 deletions(-)

diff --git a/common/src/main/java/org/apache/sedona/common/Functions.java 
b/common/src/main/java/org/apache/sedona/common/Functions.java
index 767e1b77b..e3124cc2e 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -20,7 +20,9 @@ import com.uber.h3core.util.LatLng;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.sedona.common.geometryObjects.Circle;
 import org.apache.sedona.common.sphere.Spheroid;
+import org.apache.sedona.common.subDivide.ExtentBasedGeometrySubDivider;
 import org.apache.sedona.common.subDivide.GeometrySubDivider;
+import org.apache.sedona.common.subDivide.SubdivideOptions;
 import org.apache.sedona.common.utils.*;
 import org.locationtech.jts.algorithm.MinimumBoundingCircle;
 import org.locationtech.jts.algorithm.Orientation;
@@ -975,7 +977,7 @@ public class Functions {
     }
 
     public static Geometry locateAlong(Geometry linear, double measure, double 
offset) {
-        return GeomUtils.locateAlong(linear, measure, offset);
+        return GeometryLocateAlongProcessor.processGeometry(linear, measure, 
offset);
     }
 
     public static Geometry locateAlong(Geometry linear, double measure) {
diff --git a/common/src/main/java/org/apache/sedona/common/utils/GeomUtils.java 
b/common/src/main/java/org/apache/sedona/common/utils/GeomUtils.java
index b946dd7fb..fc36e79e5 100644
--- a/common/src/main/java/org/apache/sedona/common/utils/GeomUtils.java
+++ b/common/src/main/java/org/apache/sedona/common/utils/GeomUtils.java
@@ -550,100 +550,4 @@ public class GeomUtils {
             return geom;
         }
     }
-
-    public static Geometry locateAlong(Geometry geometry, double measure, 
double offset) {
-        if (!isMeasuredGeometry(geometry)) {
-            throw new IllegalArgumentException("Input geometry is doesn't have 
a measure dimension");
-        }
-
-        if (geometry instanceof Point) {
-            return locateAlongPoint(geometry, measure, offset);
-        }
-        if (geometry instanceof MultiPoint) {
-            // iterating through Points in MultiPoint object
-            Point[] points = new Point[geometry.getNumGeometries()];
-            for (int i = 0; i < geometry.getNumGeometries(); i++) {
-                points[i] = locateAlongPoint(geometry.getGeometryN(i), 
measure, offset);
-            }
-            return 
geometry.getFactory().createMultiPoint(Arrays.stream(points).filter(Objects::nonNull).toArray(Point[]::new));
-        }
-        if (geometry instanceof LineString) {
-            return locateAlongLinestring(geometry, measure, offset);
-        }
-        if (geometry instanceof MultiLineString) {
-            // iterating through LineStrings in MultiLineString object
-            List<Point> points = new ArrayList<>();
-            for (int i = 0; i < geometry.getNumGeometries(); i++) {
-                MultiPoint mPoint = (MultiPoint) 
locateAlongLinestring(geometry.getGeometryN(i), measure, offset);
-                for (int j = 0; j < mPoint.getNumGeometries(); j++) {
-                    points.add((Point) mPoint.getGeometryN(j));
-                }
-            }
-
-            return geometry.getFactory().createMultiPoint(points.toArray(new 
Point[0]));
-        }
-
-        throw new IllegalArgumentException(String.format("%s geometry type not 
supported, supported types are: (Multi)Point and (Multi)LineString.", 
geometry.getGeometryType()));
-    }
-
-    private static Geometry locateAlongLinestring(Geometry geometry, double 
measure, double offset) {
-        Coordinate[] coordinates = geometry.getCoordinates();
-        CoordinateList coordinateList = new CoordinateList();
-
-        for (int i = 1; i < coordinates.length; i++) {
-            Coordinate coordinate1 = coordinates[i - 1];
-            Coordinate coordinate2 = coordinates[i];
-            CoordinateXYZM newCoordinate = new CoordinateXYZM();
-            double position;
-
-            double measure1 = coordinate1.getM(),
-                    measure2 = coordinate2.getM();
-
-            if ((measure < Math.min(measure1, measure2)) || (measure > 
Math.max(measure1, measure2))) {
-                continue;
-            }
-
-            if (measure1 == measure2) {
-                // If the measures are equal then there is no valid 
interpolation range
-                if (coordinate1.equals(coordinate2)) {
-                    newCoordinate.setX(coordinate1.getX());
-                    newCoordinate.setY(coordinate1.getY());
-                    newCoordinate.setZ(coordinate1.getZ());
-                    newCoordinate.setM(coordinate1.getM());
-                    coordinateList.add(newCoordinate, false);
-                    continue;
-                }
-                // the point will be in the midpoint of coordinate1 and 
coordinate2 as measure1 and measure2 are same
-                position = 0.5;
-            } else {
-                // calculate the interpolation factor / position
-                position = (measure - measure1) / (measure2 - measure1);
-            }
-
-            // apply linear interpolation to find the point along the line
-            newCoordinate.setX(coordinate1.x + (coordinate2.x - coordinate1.x) 
* position);
-            newCoordinate.setY(coordinate1.y + (coordinate2.y - coordinate1.y) 
* position);
-            newCoordinate.setZ(coordinate1.z + (coordinate2.z - coordinate1.z) 
* position);
-            newCoordinate.setM(measure);
-
-            if (offset != 0D) {
-                // calculate the angle of the line segment
-                double theta = Math.atan2(coordinate2.y - coordinate1.y, 
coordinate2.x - coordinate1.x);
-                // shift the coordinate left or right by the offset
-                // if the offset is positive then shift to left
-                // else the offset is negative then shift to right
-                newCoordinate.setX(newCoordinate.x - Math.sin(theta) * offset);
-                newCoordinate.setY(newCoordinate.y + Math.cos(theta) * offset);
-            }
-            coordinateList.add(newCoordinate, false);
-        }
-        return 
geometry.getFactory().createMultiPointFromCoords(Arrays.stream(coordinateList.toCoordinateArray()).filter(Objects::nonNull).toArray(Coordinate[]::new));
-    }
-
-    private static Point locateAlongPoint(Geometry geometry, double measure, 
double offset) {
-        if (measure == geometry.getCoordinate().getM()) {
-            return (Point) geometry;
-        }
-        return null;
-    }
 }
diff --git 
a/common/src/main/java/org/apache/sedona/common/utils/GeometryLocateAlongProcessor.java
 
b/common/src/main/java/org/apache/sedona/common/utils/GeometryLocateAlongProcessor.java
new file mode 100644
index 000000000..49bbdc4b4
--- /dev/null
+++ 
b/common/src/main/java/org/apache/sedona/common/utils/GeometryLocateAlongProcessor.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sedona.common.utils;
+
+import org.locationtech.jts.geom.*;
+
+import java.util.*;
+import java.util.function.BiFunction;
+
+public class GeometryLocateAlongProcessor {
+
+    private final Map<Class<?>, BiFunction<Geometry, double[], Geometry>> 
geometryFunctions = new HashMap<>();
+
+    public GeometryLocateAlongProcessor() {
+        geometryFunctions.put(Point.class, (geometry, params) -> 
locateAlongPoint((Point) geometry, params[0], params[1]));
+        geometryFunctions.put(MultiPoint.class, (geometry, params) -> 
locateAlongMultiPoint((MultiPoint) geometry, params[0], params[1]));
+        geometryFunctions.put(LineString.class, (geometry, params) -> 
locateAlongLineString((LineString) geometry, params[0], params[1]));
+        geometryFunctions.put(MultiLineString.class, (geometry, params) -> 
locateAlongMultiLineString((MultiLineString) geometry, params[0], params[1]));
+    }
+
+    public static Geometry processGeometry(Geometry geometry, double measure, 
double offset) {
+        GeometryLocateAlongProcessor processor = new 
GeometryLocateAlongProcessor();
+        BiFunction<Geometry, double[], Geometry> function = 
processor.geometryFunctions.get(geometry.getClass());
+        if (function != null) {
+            return function.apply(geometry, new double[]{measure, offset});
+        }
+        throw new IllegalArgumentException(String.format("%s geometry type not 
supported, supported types are: (Multi)Point and (Multi)LineString.", 
geometry.getGeometryType()));
+    }
+
+    private Geometry locateAlongPoint(Point point, double measure, double 
offset) {
+        if (measure == point.getCoordinate().getM()) {
+            return point;
+        }
+        return null;
+    }
+
+    private Geometry locateAlongMultiPoint(MultiPoint multiPoint, double 
measure, double offset) {
+        Point[] points = new Point[multiPoint.getNumGeometries()];
+        for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
+            points[i] = (Point) locateAlongPoint((Point) 
multiPoint.getGeometryN(i), measure, offset);
+        }
+        return 
multiPoint.getFactory().createMultiPoint(Arrays.stream(points).filter(Objects::nonNull).toArray(Point[]::new));
+    }
+
+    private Geometry locateAlongLineString(LineString lineString, double 
measure, double offset) {
+        Coordinate[] coordinates = lineString.getCoordinates();
+        CoordinateList coordinateList = new CoordinateList();
+
+        for (int i = 1; i < coordinates.length; i++) {
+            Coordinate coordinate1 = coordinates[i - 1];
+            Coordinate coordinate2 = coordinates[i];
+            CoordinateXYZM newCoordinate = new CoordinateXYZM();
+            double position;
+
+            double measure1 = coordinate1.getM(),
+                    measure2 = coordinate2.getM();
+
+            if ((measure < Math.min(measure1, measure2)) || (measure > 
Math.max(measure1, measure2))) {
+                continue;
+            }
+
+            if (measure1 == measure2) {
+                // If the measures are equal then there is no valid 
interpolation range
+                if (coordinate1.equals(coordinate2)) {
+                    newCoordinate.setX(coordinate1.getX());
+                    newCoordinate.setY(coordinate1.getY());
+                    newCoordinate.setZ(coordinate1.getZ());
+                    newCoordinate.setM(coordinate1.getM());
+                    coordinateList.add(newCoordinate, false);
+                    continue;
+                }
+                // the point will be in the midpoint of coordinate1 and 
coordinate2 as measure1 and measure2 are same
+                position = 0.5;
+            } else {
+                // calculate the interpolation factor / position
+                position = (measure - measure1) / (measure2 - measure1);
+            }
+
+            // apply linear interpolation to find the point along the line
+            newCoordinate.setX(coordinate1.x + (coordinate2.x - coordinate1.x) 
* position);
+            newCoordinate.setY(coordinate1.y + (coordinate2.y - coordinate1.y) 
* position);
+            newCoordinate.setZ(coordinate1.z + (coordinate2.z - coordinate1.z) 
* position);
+            newCoordinate.setM(measure);
+
+            if (offset != 0D) {
+                // calculate the angle of the line segment
+                double theta = Math.atan2(coordinate2.y - coordinate1.y, 
coordinate2.x - coordinate1.x);
+                // shift the coordinate left or right by the offset
+                // if the offset is positive then shift to left
+                // else the offset is negative then shift to right
+                newCoordinate.setX(newCoordinate.x - Math.sin(theta) * offset);
+                newCoordinate.setY(newCoordinate.y + Math.cos(theta) * offset);
+            }
+            coordinateList.add(newCoordinate, false);
+        }
+        return 
lineString.getFactory().createMultiPointFromCoords(Arrays.stream(coordinateList.toCoordinateArray()).filter(Objects::nonNull).toArray(Coordinate[]::new));
+    }
+
+    private Geometry locateAlongMultiLineString(MultiLineString 
multiLineString, double measure, double offset) {
+        // iterating through LineStrings in MultiLineString object
+        List<Point> points = new ArrayList<>();
+        for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
+            MultiPoint mPoint = (MultiPoint) 
locateAlongLineString((LineString) multiLineString.getGeometryN(i), measure, 
offset);
+            for (int j = 0; j < mPoint.getNumGeometries(); j++) {
+                points.add((Point) mPoint.getGeometryN(j));
+            }
+        }
+
+        return 
multiLineString.getFactory().createMultiPoint(points.toArray(new Point[0]));
+    }
+}

Reply via email to