Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SEDONA-180] Make ST_* expressions foldable and declares input types for type checking #704

Merged
merged 1 commit into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 107 additions & 6 deletions common/src/main/java/org/apache/sedona/common/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.apache.sedona.common.utils.GeometryGeoHashEncoder;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.locationtech.jts.algorithm.MinimumBoundingCircle;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
Expand All @@ -28,13 +29,17 @@
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.operation.distance3d.Distance3DOp;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.geom.util.GeometryFixer;
import org.locationtech.jts.io.gml2.GMLWriter;
import org.locationtech.jts.io.kml.KMLWriter;
import org.locationtech.jts.linearref.LengthIndexedLine;
import org.locationtech.jts.operation.distance3d.Distance3DOp;
import org.locationtech.jts.operation.linemerge.LineMerger;
import org.locationtech.jts.operation.valid.IsSimpleOp;
import org.locationtech.jts.operation.valid.IsValidOp;
import org.locationtech.jts.precision.GeometryPrecisionReducer;
import org.opengis.referencing.FactoryException;

import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
Expand All @@ -48,6 +53,8 @@

public class Functions {
private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
private static Geometry EMPTY_POLYGON = GEOMETRY_FACTORY.createPolygon(null, null);
private static GeometryCollection EMPTY_GEOMETRY_COLLECTION = GEOMETRY_FACTORY.createGeometryCollection(null);

public static double area(Geometry geometry) {
return geometry.getArea();
Expand Down Expand Up @@ -339,10 +346,7 @@ public static Geometry addPoint(Geometry linestring, Geometry point, int positio

public static Geometry removePoint(Geometry linestring) {
if (linestring != null) {
int length = linestring.getCoordinates().length;
if (1 < length) {
return removePoint(linestring, length - 1);
}
return removePoint(linestring, -1);
}
return null;
}
Expand All @@ -351,6 +355,9 @@ public static Geometry removePoint(Geometry linestring, int position) {
if (linestring instanceof LineString) {
List<Coordinate> coordinates = new ArrayList<>(Arrays.asList(linestring.getCoordinates()));
if (2 < coordinates.size() && position < coordinates.size()) {
if (position == -1) {
position = coordinates.size() - 1;
}
coordinates.remove(position);
return GEOMETRY_FACTORY.createLineString(coordinates.toArray(new Coordinate[0]));
}
Expand Down Expand Up @@ -383,4 +390,98 @@ public static Geometry lineFromMultiPoint(Geometry geometry) {
}
return GEOMETRY_FACTORY.createLineString(coordinates.toArray(new Coordinate[0]));
}

public static Geometry convexHull(Geometry geometry) {
return geometry.convexHull();
}

public static Geometry getCentroid(Geometry geometry) {
return geometry.getCentroid();
}

public static Geometry intersection(Geometry leftGeometry, Geometry rightGeometry) {
boolean isIntersects = leftGeometry.intersects(rightGeometry);
if (!isIntersects) {
return EMPTY_POLYGON;
}
if (leftGeometry.contains(rightGeometry)) {
return rightGeometry;
}
if (rightGeometry.contains(leftGeometry)) {
return leftGeometry;
}
return leftGeometry.intersection(rightGeometry);
}

public static Geometry makeValid(Geometry geometry, boolean keepCollapsed) {
GeometryFixer fixer = new GeometryFixer(geometry);
fixer.setKeepCollapsed(keepCollapsed);
return fixer.getResult();
}

public static Geometry reducePrecision(Geometry geometry, int precisionScale) {
GeometryPrecisionReducer precisionReduce = new GeometryPrecisionReducer(new PrecisionModel(Math.pow(10, precisionScale)));
return precisionReduce.reduce(geometry);
}

public static Geometry lineMerge(Geometry geometry) {
if (geometry instanceof MultiLineString) {
MultiLineString multiLineString = (MultiLineString) geometry;
int numLineStrings = multiLineString.getNumGeometries();
LineMerger merger = new LineMerger();
for (int k = 0; k < numLineStrings; k++) {
LineString line = (LineString) multiLineString.getGeometryN(k);
merger.add(line);
}
if (merger.getMergedLineStrings().size() == 1) {
// If the merger was able to join the lines, there will be only one element
return (Geometry) merger.getMergedLineStrings().iterator().next();
} else {
// if the merger couldn't join the lines, it will contain the individual lines, so return the input
return geometry;
}
}
return EMPTY_GEOMETRY_COLLECTION;
}

public static Geometry minimumBoundingCircle(Geometry geometry, int quadrantSegments) {
MinimumBoundingCircle minimumBoundingCircle = new MinimumBoundingCircle(geometry);
Coordinate centre = minimumBoundingCircle.getCentre();
double radius = minimumBoundingCircle.getRadius();
Geometry circle = null;
if (centre == null) {
circle = geometry.getFactory().createPolygon();
} else {
circle = geometry.getFactory().createPoint(centre);
if (radius != 0D) {
circle = circle.buffer(radius, quadrantSegments);
}
}
return circle;
}

public static Geometry lineSubString(Geometry geom, double fromFraction, double toFraction) {
double length = geom.getLength();
LengthIndexedLine indexedLine = new LengthIndexedLine(geom);
Geometry subLine = indexedLine.extractLine(length * fromFraction, length * toFraction);
return subLine;
}

public static Geometry lineInterpolatePoint(Geometry geom, double fraction) {
double length = geom.getLength();
LengthIndexedLine indexedLine = new LengthIndexedLine(geom);
Coordinate interPoint = indexedLine.extractPoint(length * fraction);
return GEOMETRY_FACTORY.createPoint(interPoint);
}

public static Geometry difference(Geometry leftGeometry, Geometry rightGeometry) {
boolean isIntersects = leftGeometry.intersects(rightGeometry);
if (!isIntersects) {
return leftGeometry;
} else if (rightGeometry.contains(leftGeometry)) {
return EMPTY_POLYGON;
} else {
return leftGeometry.difference(rightGeometry);
}
}
}
2 changes: 1 addition & 1 deletion python/tests/sql/test_dataframe_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
(stf.ST_MakeValid, ("geom",), "invalid_geom", "", "MULTIPOLYGON (((1 5, 3 3, 1 1, 1 5)), ((5 3, 7 5, 7 1, 5 3)))"),
(stf.ST_MakePolygon, ("geom",), "closed_linestring_geom", "", "POLYGON ((0 0, 1 0, 1 1, 0 0))"),
(stf.ST_MinimumBoundingCircle, ("line",), "linestring_geom", "ST_PrecisionReduce(geom, 2)", "POLYGON ((4.95 -0.49, 4.81 -0.96, 4.58 -1.39, 4.27 -1.77, 3.89 -2.08, 3.46 -2.31, 2.99 -2.45, 2.5 -2.5, 2.01 -2.45, 1.54 -2.31, 1.11 -2.08, 0.73 -1.77, 0.42 -1.39, 0.19 -0.96, 0.05 -0.49, 0 0, 0.05 0.49, 0.19 0.96, 0.42 1.39, 0.73 1.77, 1.11 2.08, 1.54 2.31, 2.01 2.45, 2.5 2.5, 2.99 2.45, 3.46 2.31, 3.89 2.08, 4.27 1.77, 4.58 1.39, 4.81 0.96, 4.95 0.49, 5 0, 4.95 -0.49))"),
(stf.ST_MinimumBoundingCircle, ("line", 2), "linestring_geom", "ST_PrecisionReduce(geom, 2)", "POLYGON ((4.95 -0.49, 4.81 -0.96, 4.58 -1.39, 4.27 -1.77, 3.89 -2.08, 3.46 -2.31, 2.99 -2.45, 2.5 -2.5, 2.01 -2.45, 1.54 -2.31, 1.11 -2.08, 0.73 -1.77, 0.42 -1.39, 0.19 -0.96, 0.05 -0.49, 0 0, 0.05 0.49, 0.19 0.96, 0.42 1.39, 0.73 1.77, 1.11 2.08, 1.54 2.31, 2.01 2.45, 2.5 2.5, 2.99 2.45, 3.46 2.31, 3.89 2.08, 4.27 1.77, 4.58 1.39, 4.81 0.96, 4.95 0.49, 5 0, 4.95 -0.49))"),
(stf.ST_MinimumBoundingCircle, ("line", 2), "linestring_geom", "ST_PrecisionReduce(geom, 2)", "POLYGON ((4.27 -1.77, 2.5 -2.5, 0.73 -1.77, 0 0, 0.73 1.77, 2.5 2.5, 4.27 1.77, 5 0, 4.27 -1.77))"),
(stf.ST_MinimumBoundingRadius, ("line",), "linestring_geom", "", {"center": "POINT (2.5 0)", "radius": 2.5}),
(stf.ST_Multi, ("point",), "point_geom", "", "MULTIPOINT (0 1)"),
(stf.ST_Normalize, ("geom",), "triangle_geom", "", "POLYGON ((0 0, 1 1, 1 0, 0 0))"),
Expand Down
Loading