Skip to content

Commit dca2035

Browse files
authored
[GH-2882] Overload ST_XMin/XMax/YMin/YMax for Box2D (#2895)
1 parent 1d58f22 commit dca2035

5 files changed

Lines changed: 67 additions & 4 deletions

File tree

common/src/main/java/org/apache/sedona/common/Functions.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,10 @@ public static Double xMin(Geometry geometry) {
699699
return min == Double.MAX_VALUE ? null : min;
700700
}
701701

702+
public static Double xMin(Box2D box) {
703+
return box == null ? null : box.getXMin();
704+
}
705+
702706
public static Double xMax(Geometry geometry) {
703707
Coordinate[] points = geometry.getCoordinates();
704708
double max = -Double.MAX_VALUE;
@@ -708,6 +712,10 @@ public static Double xMax(Geometry geometry) {
708712
return max == -Double.MAX_VALUE ? null : max;
709713
}
710714

715+
public static Double xMax(Box2D box) {
716+
return box == null ? null : box.getXMax();
717+
}
718+
711719
public static Double yMin(Geometry geometry) {
712720
Coordinate[] points = geometry.getCoordinates();
713721
double min = Double.MAX_VALUE;
@@ -717,6 +725,10 @@ public static Double yMin(Geometry geometry) {
717725
return min == Double.MAX_VALUE ? null : min;
718726
}
719727

728+
public static Double yMin(Box2D box) {
729+
return box == null ? null : box.getYMin();
730+
}
731+
720732
public static Double yMax(Geometry geometry) {
721733
Coordinate[] points = geometry.getCoordinates();
722734
double max = -Double.MAX_VALUE;
@@ -726,6 +738,10 @@ public static Double yMax(Geometry geometry) {
726738
return max == -Double.MAX_VALUE ? null : max;
727739
}
728740

741+
public static Double yMax(Box2D box) {
742+
return box == null ? null : box.getYMax();
743+
}
744+
729745
public static Double zMax(Geometry geometry) {
730746
Coordinate[] points = geometry.getCoordinates();
731747
double max = -Double.MAX_VALUE;

spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.apache.spark.sql.sedona_sql.expressions
2020

2121
import org.apache.sedona.common.{Functions, FunctionsGeoTools, FunctionsProj4}
22+
import org.apache.sedona.common.geometryObjects.Box2D
2223
import org.apache.sedona.common.sphere.{Haversine, Spheroid}
2324
import org.apache.sedona.common.utils.{InscribedCircle, ValidDetail}
2425
import org.apache.sedona.core.utils.SedonaConf
@@ -69,15 +70,19 @@ private[apache] case class ST_Distance(inputExpressions: Seq[Expression])
6970
}
7071

7172
private[apache] case class ST_YMax(inputExpressions: Seq[Expression])
72-
extends InferredExpression(Functions.yMax _) {
73+
extends InferredExpression(
74+
inferrableFunction1((g: Geometry) => Functions.yMax(g)),
75+
inferrableFunction1((b: Box2D) => Functions.yMax(b))) {
7376

7477
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
7578
copy(inputExpressions = newChildren)
7679
}
7780
}
7881

7982
private[apache] case class ST_YMin(inputExpressions: Seq[Expression])
80-
extends InferredExpression(Functions.yMin _) {
83+
extends InferredExpression(
84+
inferrableFunction1((g: Geometry) => Functions.yMin(g)),
85+
inferrableFunction1((b: Box2D) => Functions.yMin(b))) {
8186

8287
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
8388
copy(inputExpressions = newChildren)
@@ -1489,7 +1494,9 @@ private[apache] case class ST_IsEmpty(inputExpressions: Seq[Expression])
14891494
* @param inputExpressions
14901495
*/
14911496
private[apache] case class ST_XMax(inputExpressions: Seq[Expression])
1492-
extends InferredExpression(Functions.xMax _) {
1497+
extends InferredExpression(
1498+
inferrableFunction1((g: Geometry) => Functions.xMax(g)),
1499+
inferrableFunction1((b: Box2D) => Functions.xMax(b))) {
14931500

14941501
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
14951502
copy(inputExpressions = newChildren)
@@ -1502,7 +1509,9 @@ private[apache] case class ST_XMax(inputExpressions: Seq[Expression])
15021509
* @param inputExpressions
15031510
*/
15041511
private[apache] case class ST_XMin(inputExpressions: Seq[Expression])
1505-
extends InferredExpression(Functions.xMin _) {
1512+
extends InferredExpression(
1513+
inferrableFunction1((g: Geometry) => Functions.xMin(g)),
1514+
inferrableFunction1((b: Box2D) => Functions.xMin(b))) {
15061515

15071516
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
15081517
copy(inputExpressions = newChildren)

spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/InferredExpression.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ object InferredTypes {
217217
expr.toGeography(input)
218218
} else if (t =:= typeOf[Array[Geography]]) { expr => input =>
219219
expr.toGeographyArray(input)
220+
} else if (t =:= typeOf[Box2D]) { expr => input =>
221+
expr.toBox2D(input)
220222
} else if (InferredRasterExpression.isRasterType(t)) {
221223
InferredRasterExpression.rasterExtractor
222224
} else if (t =:= typeOf[Array[Double]]) { expr => input =>

spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/implicits.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.apache.spark.sql.sedona_sql.expressions
2020

2121
import org.apache.sedona.common.S2Geography.{Geography, GeographyWKBSerializer}
22+
import org.apache.sedona.common.geometryObjects.Box2D
2223
import org.apache.sedona.sql.utils.GeometrySerializer
2324
import org.apache.spark.sql.catalyst.InternalRow
2425
import org.apache.spark.sql.catalyst.expressions.Expression
@@ -73,6 +74,19 @@ object implicits {
7374
}
7475
}
7576

77+
def toBox2D(input: InternalRow): Box2D = {
78+
inputExpression match {
79+
case serdeAware: SerdeAware =>
80+
serdeAware.evalWithoutSerialization(input).asInstanceOf[Box2D]
81+
case _ =>
82+
inputExpression.eval(input) match {
83+
case row: InternalRow =>
84+
new Box2D(row.getDouble(0), row.getDouble(1), row.getDouble(2), row.getDouble(3))
85+
case _ => null
86+
}
87+
}
88+
}
89+
7690
def toGeographyArray(input: InternalRow): Array[Geography] = {
7791
inputExpression match {
7892
case aware: SerdeAware =>

spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,28 @@ class functionTestScala
274274
assert(test.take(1)(0).get(0).asInstanceOf[Double] == -3.0)
275275
}
276276

277+
it("Passed ST_XMin / XMax / YMin / YMax for Box2D") {
278+
val df = sparkSession.sql("""
279+
WITH t AS (
280+
SELECT ST_Box2D(ST_GeomFromText('POLYGON((1 2, 1 5, 4 5, 4 2, 1 2))')) AS bbox,
281+
ST_Box2D(ST_GeomFromText(NULL)) AS bbox_null
282+
)
283+
SELECT
284+
ST_XMin(bbox), ST_YMin(bbox), ST_XMax(bbox), ST_YMax(bbox),
285+
ST_XMin(bbox_null), ST_YMin(bbox_null), ST_XMax(bbox_null), ST_YMax(bbox_null)
286+
FROM t
287+
""")
288+
val row = df.collect()(0)
289+
assert(row.getDouble(0) == 1.0)
290+
assert(row.getDouble(1) == 2.0)
291+
assert(row.getDouble(2) == 4.0)
292+
assert(row.getDouble(3) == 5.0)
293+
assert(row.isNullAt(4))
294+
assert(row.isNullAt(5))
295+
assert(row.isNullAt(6))
296+
assert(row.isNullAt(7))
297+
}
298+
277299
it("Passed ST_ZMax") {
278300
val test = sparkSession.sql(
279301
"SELECT ST_ZMax(ST_GeomFromWKT('POLYGON((0 0 0,0 5 0,5 0 0,0 0 5),(1 1 0,3 1 0,1 3 0,1 1 0))'))")

0 commit comments

Comments
 (0)