Skip to content

Commit

Permalink
[SEDONA-200] Add ST_CoordDim to Sedona (#889)
Browse files Browse the repository at this point in the history
  • Loading branch information
furqaankhan committed Jul 12, 2023
1 parent b93dfa3 commit c764200
Show file tree
Hide file tree
Showing 15 changed files with 172 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1055,4 +1055,5 @@ public static Double hausdorffDistance(Geometry g1, Geometry g2, double densityF
public static Double hausdorffDistance(Geometry g1, Geometry g2) throws Exception{
return GeomUtils.getHausdorffDistance(g1, g2, -1);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
import org.apache.commons.lang3.tuple.Pair;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.sedona.common.geometryObjects.Circle;
import org.apache.sedona.common.utils.GeomUtils;
import org.apache.sedona.core.enums.IndexType;
import org.apache.sedona.core.enums.JoinBuildSide;
import org.apache.sedona.common.geometryObjects.Circle;
import org.apache.sedona.core.joinJudgement.*;
import org.apache.sedona.core.monitoring.Metric;
import org.apache.sedona.core.monitoring.Metrics;
import org.apache.sedona.core.spatialPartitioning.SpatialPartitioner;
import org.apache.sedona.core.spatialRDD.CircleRDD;
import org.apache.sedona.core.spatialRDD.SpatialRDD;
Expand All @@ -37,7 +38,6 @@
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.sedona.core.monitoring.Metrics;
import org.locationtech.jts.geom.Geometry;
import scala.Tuple2;

Expand Down
26 changes: 26 additions & 0 deletions docs/api/flink/Function.md
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,30 @@ SELECT ST_ConvexHull(polygondf.countyshape)
FROM polygondf
```

## ST_CoordDim

Introduction: Returns the coordinate dimensions of the geometry. It is an alias of `ST_NDims`.

Format: `ST_CoordDim(geom: geometry)`

Since: `v1.5.0`

Example with x, y, z coordinate:

```sql
SELECT ST_CoordDim(ST_GeomFromText('POINT(1 1 2'))
```

Output: `3`

Example with x, y coordinate:

```sql
SELECT ST_CoordDim(ST_GeomFromEWKT('POINT(3 7)'))
```

Output: `2`

## ST_Dimension

Introduction: Return the topological dimension of this Geometry object, which must be less than or equal to the coordinate dimension. OGC SPEC s2.1.1.1 - returns 0 for POINT, 1 for LINESTRING, 2 for POLYGON, and the largest dimension of the components of a GEOMETRYCOLLECTION. If the dimension is unknown (e.g. for an empty GEOMETRYCOLLECTION) 0 is returned.
Expand Down Expand Up @@ -1932,3 +1956,5 @@ SELECT ST_ZMin(ST_GeomFromText('LINESTRING(1 3 4, 5 6 7)'))
```

Output: `4.0`


24 changes: 24 additions & 0 deletions docs/api/sql/Function.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,30 @@ SELECT ST_ConvexHull(polygondf.countyshape)
FROM polygondf
```

## ST_CoordDim

Introduction: Returns the coordinate dimensions of the geometry. It is an alias of `ST_NDims`.

Format: `ST_CoordDim(geom: geometry)`

Since: `v1.5.0`

Example with x, y, z coordinate:

```sql
SELECT ST_CoordDim(ST_GeomFromText('POINT(1 1 2'))
```

Output: `3`

Example with x, y coordinate:

```sql
SELECT ST_CoordDim(ST_GeomFromEWKT('POINT(3 7)'))
```

Output: `2`

## ST_Degrees

Introduction: Convert an angle in radian to degrees.
Expand Down
1 change: 1 addition & 0 deletions flink/src/main/java/org/apache/sedona/flink/Catalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public static UserDefinedFunction[] getFuncs() {
new Functions.ST_Angle(),
new Functions.ST_Degrees(),
new Functions.ST_HausdorffDistance(),
new Functions.ST_CoordDim(),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,15 @@ public Double eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts
}
}


public static class ST_CoordDim extends ScalarFunction {
@DataTypeHint("Integer")
public Integer eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) {
Geometry geom = (Geometry) o;
return org.apache.sedona.common.Functions.nDims(geom);
}
}

public static class ST_Angle extends ScalarFunction {

@DataTypeHint("Double")
Expand Down Expand Up @@ -962,6 +971,7 @@ public static class ST_Degrees extends ScalarFunction {
@DataTypeHint("Double")
public Double eval(@DataTypeHint("Double") Double angleInRadian) {
return org.apache.sedona.common.Functions.degrees(angleInRadian);

}
}
}
17 changes: 17 additions & 0 deletions flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1020,4 +1020,21 @@ public void testHausdorffDistance() {
assertEquals(expected, actual);
assertEquals(expectedDefault, actualDefault);
}

@Test
public void testCoordDimFor2D() {
Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POINT(3 7)') AS " + polygonColNames[0]);
polygonTable = polygonTable.select(call(Functions.ST_CoordDim.class.getSimpleName(), $(polygonColNames[0])));
int result = (int) first(polygonTable).getField(0);
assertEquals(2, result, 0);
}

@Test
public void testCoordDimFor3D() {
Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POINT(1 2 1)') AS " + polygonColNames[0]);
polygonTable = polygonTable.select(call(Functions.ST_CoordDim.class.getSimpleName(), $(polygonColNames[0])));
int result = (int) first(polygonTable).getField(0);
assertEquals(3, result, 0);
}

}
12 changes: 12 additions & 0 deletions python/sedona/sql/st_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"ST_Angle",
"ST_Degrees",
"ST_FrechetDistance",
"ST_CoordDim",
"ST_Affine",
"ST_BoundingDiagonal"
]
Expand Down Expand Up @@ -1422,3 +1423,14 @@ def ST_HausdorffDistance(g1: ColumnOrName, g2: ColumnOrName, densityFrac: Option
args = (g1, g2, densityFrac)
return _call_st_function("ST_HausdorffDistance", args)

@validate_argument_types
def ST_CoordDim(geometry: ColumnOrName) -> Column:
"""Return the number of dimensions contained in a coordinate
:param geometry: Geometry column to return for.
:type geometry: ColumnOrName
:return: Number of dimensinos in a coordinate column as an integer column.
:rtype: Column
"""
return _call_st_function("ST_CoordDim", geometry)

1 change: 1 addition & 0 deletions python/tests/sql/test_dataframe_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
(stf.ST_ConcaveHull, ("geom", 1.0), "triangle_geom", "", "POLYGON ((0 0, 1 1, 1 0, 0 0))"),
(stf.ST_ConcaveHull, ("geom", 1.0, True), "triangle_geom", "", "POLYGON ((1 1, 1 0, 0 0, 1 1))"),
(stf.ST_ConvexHull, ("geom",), "triangle_geom", "", "POLYGON ((0 0, 1 1, 1 0, 0 0))"),
(stf.ST_CoordDim, ("point",), "point_geom", "", 2),
(stf.ST_Difference, ("a", "b"), "overlapping_polys", "", "POLYGON ((1 0, 0 0, 0 1, 1 1, 1 0))"),
(stf.ST_Dimension, ("geom",), "geometry_geom_collection", "", 1),
(stf.ST_Distance, ("a", "b"), "two_points", "", 3.0),
Expand Down
6 changes: 6 additions & 0 deletions python/tests/sql/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,3 +1177,9 @@ def test_hausdorffDistance(self):
actual_default = actual_df_default.take(1)[0][0]
assert expected == actual
assert expected == actual_default

def test_st_coord_dim(self):

point_df = self.spark.sql("SELECT ST_GeomFromWkt('POINT(7 8 6)') AS geom")
point_row = [pt_row[0] for pt_row in point_df.selectExpr("ST_CoordDim(geom)").collect()]
assert(point_row == [3])
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ object Catalog {
function[ST_GeomFromGeoJSON](),
function[ST_GeomFromGML](),
function[ST_GeomFromKML](),
function[ST_CoordDim](),
function[ST_Point](),
function[ST_PointZ](0),
function[ST_PolygonFromEnvelope](),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1070,3 +1070,16 @@ case class ST_Degrees(inputExpressions: Seq[Expression])
copy(inputExpressions = newChildren)
}
}

/**
* Return the number of ddimensions in geometry.
*
* @param inputExpressions
* */
case class ST_CoordDim(inputExpressions: Seq[Expression])
extends InferredExpression(Functions.nDims _) {
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]): Expression = {
copy(inputExpressions = newChildren)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -380,5 +380,9 @@ object st_functions extends DataFrameAPI {

def ST_HausdorffDistance(g1: String, g2: String, densityFrac: Double) = wrapExpression[ST_HausdorffDistance](g1, g2, densityFrac);

def ST_CoordDim(geometry: Column): Column = wrapExpression[ST_CoordDim](geometry)

def ST_CoordDim(geometry: String): Column = wrapExpression[ST_CoordDim](geometry)

}

Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,38 @@ class dataFrameAPITestScala extends TestBaseScala {
assertEquals(expected, actual)
}

it("Passed ST_CoordDim with 3D point") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINT(1 1 2)') AS geom")
val expected = 3
val df = polyDf.select(ST_CoordDim("geom"))
val actual = df.take(1)(0).getInt(0)
assert(expected == actual)
}

it("Passed ST_CoordDim with Z coordinates") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINTZ(1 1 0.5)') AS geom")
val expected = 3
val df = polyDf.select(ST_CoordDim("geom"))
val actual = df.take(1)(0).getInt(0)
assert(expected == actual)
}

it("Passed ST_CoordDim with XYM point") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINT M(1 2 3)') AS geom")
val expected = 3
val df = polyDf.select(ST_CoordDim("geom"))
val actual = df.take(1)(0).getInt(0)
assert(expected == actual)
}

it("Passed ST_CoordDim with XYZM point") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINT ZM(1 2 3 4)') AS geom")
val expected = 4
val df = polyDf.select(ST_CoordDim("geom"))
val actual = df.take(1)(0).getInt(0)
assert(expected == actual)
}

it("Passed ST_Angle - 4 Points") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINT (10 10)') AS p1, ST_GeomFromWKT('POINT (0 0)') AS p2," +
" ST_GeomFromWKT('POINT (90 90)') AS p3, ST_GeomFromWKT('POINT (100 80)') AS p4")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,27 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample
}
}


it("Passed ST_CoordDim with 3D point") {
val test = sparkSession.sql("SELECT ST_CoordDim(ST_GeomFromWKT('POINT(1 1 2)'))")
assert(test.take(1)(0).get(0).asInstanceOf[Int] == 3)
}

it("Passed ST_CoordDim with Z coordinates") {
val test = sparkSession.sql("SELECT ST_CoordDim(ST_GeomFromWKT('POINTZ(1 1 0.5)'))")
assert(test.take(1)(0).get(0).asInstanceOf[Int] == 3)
}

it("Passed ST_CoordDim with XYM point") {
val test = sparkSession.sql("SELECT ST_CoordDim(ST_GeomFromWKT('POINT M(1 2 3)'))")
assert(test.take(1)(0).get(0).asInstanceOf[Int] == 3)
}

it("Passed ST_CoordDim with XYZM point") {
val test = sparkSession.sql("SELECT ST_CoordDim(ST_GeomFromWKT('POINT ZM(1 2 3 4)'))")
assert(test.take(1)(0).get(0).asInstanceOf[Int] == 4)
}

it ("should pass GeometryType") {
val geomTestCases = Map (
("'POINT (51.3168 -0.56)'") -> "'POINT'",
Expand All @@ -2172,6 +2193,7 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample
val expected = df.take(1)(0).get(1).asInstanceOf[String]
assertEquals(expected, actual)
}

}

}

0 comments on commit c764200

Please sign in to comment.