Skip to content

[GH-2883] Add ST_MakeBox2D(p1, p2) scalar constructor#2897

Merged
jiayuasu merged 2 commits intoapache:masterfrom
jiayuasu:feature/st-makebox2d
May 3, 2026
Merged

[GH-2883] Add ST_MakeBox2D(p1, p2) scalar constructor#2897
jiayuasu merged 2 commits intoapache:masterfrom
jiayuasu:feature/st-makebox2d

Conversation

@jiayuasu
Copy link
Copy Markdown
Member

@jiayuasu jiayuasu commented May 3, 2026

Did you read the Contributor Guide?

Is this PR related to a ticket?

What changes were proposed in this PR?

Adds the ST_MakeBox2D(lower_left: Point, upper_right: Point) -> Box2D scalar constructor. PostGIS-compatible.

SELECT ST_MakeBox2D(ST_Point(1.0, 2.0), ST_Point(4.0, 5.0));
-- BOX(1.0 2.0, 4.0 5.0)

Behavior:

  • Coordinates are taken verbatim — no swapping or ordering validation. xmin > xmax / ymin > ymax are preserved as supplied. This is deliberate: it leaves those orderings reserved for a future antimeridian-wraparound semantics on the longitude axis (cf. apache/sedona-db's WraparoundInterval).
  • NULL or empty point inputs return NULL.
  • Non-point inputs raise IllegalArgumentException("ST_MakeBox2D requires two POINT geometries").

How was this patch tested?

constructorTestScala:

  • "Passed ST_MakeBox2D" — happy path, NULL right-hand input → NULL, empty left-hand input → NULL.
  • "ST_MakeBox2D preserves swapped corners" — ST_MakeBox2D(ST_Point(170,10), ST_Point(-170,20)) round-trips with xmin=170, xmax=-170 (no auto-swap).
  • "ST_MakeBox2D rejects non-point input" — LINESTRING raises with the documented message.
  • "ST_MakeBox2D ignores Z on 3D point input" — ST_PointZ inputs round-trip with Z ignored.

Did this PR include necessary documentation updates?

Construct a Box2D from two corner points (lower-left, upper-right).
PostGIS-compatible. Coordinates are taken verbatim — no swapping or
ordering validation — so xmin > xmax / ymin > ymax are preserved as
supplied. This leaves those orderings reserved for a future
antimeridian-wraparound semantics on the longitude axis (cf.
sedona-db's WraparoundInterval).

Null or empty point inputs return NULL. Non-point inputs raise
IllegalArgumentException.

Closes apache#2883.
@jiayuasu jiayuasu added this to the sedona-1.9.1 milestone May 3, 2026
@jiayuasu jiayuasu requested a review from Copilot May 3, 2026 18:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new PostGIS-compatible scalar constructor ST_MakeBox2D(p1, p2) to build a native Box2D value from two corner points, integrating it into Sedona’s Spark SQL function catalog and validating behavior via Scala tests.

Changes:

  • Implement ST_MakeBox2D Spark SQL expression backed by org.apache.sedona.common.Constructors.makeBox2D.
  • Register ST_MakeBox2D in the Sedona SQL UDF catalog under Geometry-Constructors.
  • Add Scala tests covering happy path, NULL/empty propagation, swapped-corner preservation, and non-point rejection.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
spark/common/src/test/scala/org/apache/sedona/sql/constructorTestScala.scala Adds unit tests for ST_MakeBox2D behavior and error handling.
spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Constructors.scala Introduces the ST_MakeBox2D Spark SQL expression wrapper.
spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala Registers ST_MakeBox2D in the function catalog.
common/src/main/java/org/apache/sedona/common/Constructors.java Implements makeBox2D helper to construct Box2D from two POINT geometries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +167
it("Passed ST_MakeBox2D") {
val df = sparkSession.sql("""
SELECT
ST_MakeBox2D(ST_Point(1.0, 2.0), ST_Point(4.0, 5.0)) AS bbox,
ST_MakeBox2D(ST_Point(10.0, 20.0), ST_GeomFromText(NULL)) AS bbox_null,
ST_MakeBox2D(ST_GeomFromText('POINT EMPTY'), ST_Point(1.0, 1.0)) AS bbox_empty
""")
val row = df.collect()(0)
val bbox = row.getAs[Box2D]("bbox")
assert(bbox.getXMin == 1.0)
assert(bbox.getYMin == 2.0)
assert(bbox.getXMax == 4.0)
assert(bbox.getYMax == 5.0)
assert(row.isNullAt(1))
assert(row.isNullAt(2))
}

it("ST_MakeBox2D preserves swapped corners") {
// No swapping or reordering; lower-left/upper-right are taken verbatim.
// This leaves xmin > xmax / ymin > ymax available for future antimeridian semantics.
val df = sparkSession.sql(
"SELECT ST_MakeBox2D(ST_Point(170.0, 10.0), ST_Point(-170.0, 20.0)) AS bbox")
val bbox = df.collect()(0).getAs[Box2D]("bbox")
assert(bbox.getXMin == 170.0)
assert(bbox.getXMax == -170.0)
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 16d9137. ST_PointZ inputs round-trip with Z ignored — Box2D gets the supplied X/Y verbatim.

@jiayuasu jiayuasu merged commit 1361fed into apache:master May 3, 2026
44 checks passed
jiayuasu added a commit to jiayuasu/sedona that referenced this pull request May 5, 2026
Mirrors the Phase 1 SQL surface added in apache#2890, apache#2895, apache#2897, apache#2898,
apache#2899 in PySpark wrappers:

- ST_Box2D in st_functions
- ST_MakeBox2D and ST_GeomFromBox2D in st_constructors
- ST_Extent in st_aggregates

Accessor overloads (ST_XMin/XMax/YMin/YMax) and ST_AsText already
worked with Box2D inputs through their existing wrappers; SQL
overload resolution happens on the JVM side.

The Python Box2DType UDT and Box2D value class were merged in apache#2878,
so collected results materialize as Box2D Python objects with
xmin/ymin/xmax/ymax attributes.

Closes apache#2887.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement ST_MakeBox2D(p1, p2) scalar constructor

2 participants