You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to the Box2D epic (#2877). Adds the planar 3D bounding box type — PostGIS's box3d — as a first-class Sedona SQL type.
Scope (Phase 1)
Mirrors Box2D's Phase 1 shape, scoped down to JVM + SQL surface only. Cross-language bindings, GeoParquet covering interop, casts, join-planner integration, and the ST_3DDWithin distance predicate are all explicit follow-ups.
Foundation
Box3D value class in common/.../geometryObjects/Box3D.java (6 doubles: xmin, ymin, zmin, xmax, ymax, zmax, mirroring PostGIS's storage order).
Box3DUDT (struct of 6 non-nullable doubles) + UDT registration.
SQL surface
ST_Box3D(geom) — planar 3D bounding box of a Geometry. Geometries without Z get zmin = zmax = 0 (matches PostGIS).
ST_3DExtent(geom) aggregate — Box3D over a column.
ST_ZMin(box3d) / ST_ZMax(box3d) overloads (the existing Geometry-input forms stay).
ST_XMin/YMin/XMax/YMax(box3d) overloads.
ST_3DBoxIntersects(box3d, box3d) — closed-interval intersection on all three axes. Matches PostGIS &&& (the 3D overlap operator).
ST_3DBoxContains(box3d, box3d) — closed-interval containment on all three axes. Matches PostGIS ~~ on box3d.
ST_AsText(box3d) — BOX3D(xmin ymin zmin, xmax ymax zmax) text form.
Semantics
Closed-interval (edge/face/corner-touching counts as intersecting and contained), matching Box2D's contract.
NULL for absent (no in-band empty marker).
xmin > xmax / ymin > ymax / zmin > zmax are explicitly rejected by predicates with IllegalArgumentException — same contract as Box2D. (We're not carrying forward Box2D's "reserved for future antimeridian wraparound" exception for Z; Z doesn't wraparound.)
GeoParquet covering-bbox recognition for Box3D columns (the spec allows optional zmin/zmax).
Casts between Box2D and Box3D (lossy in either direction).
Spatial join planner integration for ST_3DBoxIntersects / ST_3DBoxContains.
Filter pushdown for Box3D predicates against Box3D columns.
ST_3DDWithin distance predicate (needs squared-Euclidean over 3D).
Why Phase 1 is narrow
Box2D's Phase 1 was wide because GeoParquet covering bbox interop drove concrete demand. Box3D today has no equivalent pull (see the original epic's "when a concrete user appears" note). This issue ships the foundation and the SQL surface so it's available, and defers everything that benefits from a real workload to inform design.
Coordination
Match Box2D's design choices wherever possible — the type-system contract (separate UDT, six-double struct), the closed-interval semantics, and the inverted-bounds throw should all feel parallel.
Follow-up to the Box2D epic (#2877). Adds the planar 3D bounding box type — PostGIS's
box3d— as a first-class Sedona SQL type.Scope (Phase 1)
Mirrors Box2D's Phase 1 shape, scoped down to JVM + SQL surface only. Cross-language bindings, GeoParquet covering interop, casts, join-planner integration, and the
ST_3DDWithindistance predicate are all explicit follow-ups.Foundation
Box3Dvalue class incommon/.../geometryObjects/Box3D.java(6 doubles:xmin, ymin, zmin, xmax, ymax, zmax, mirroring PostGIS's storage order).Box3DUDT(struct of 6 non-nullable doubles) + UDT registration.SQL surface
ST_Box3D(geom)— planar 3D bounding box of a Geometry. Geometries without Z getzmin = zmax = 0(matches PostGIS).ST_3DMakeBox(p1: PointZ, p2: PointZ)— two-corner constructor.ST_3DExtent(geom)aggregate — Box3D over a column.ST_ZMin(box3d)/ST_ZMax(box3d)overloads (the existing Geometry-input forms stay).ST_XMin/YMin/XMax/YMax(box3d)overloads.ST_3DBoxIntersects(box3d, box3d)— closed-interval intersection on all three axes. Matches PostGIS&&&(the 3D overlap operator).ST_3DBoxContains(box3d, box3d)— closed-interval containment on all three axes. Matches PostGIS~~on box3d.ST_AsText(box3d)—BOX3D(xmin ymin zmin, xmax ymax zmax)text form.Semantics
xmin > xmax/ymin > ymax/zmin > zmaxare explicitly rejected by predicates withIllegalArgumentException— same contract as Box2D. (We're not carrying forward Box2D's "reserved for future antimeridian wraparound" exception for Z; Z doesn't wraparound.)zmin = zmax = 0(PostGIS-compatible default).Out of scope (separate follow-ups)
Box3DTypebindings and Scala DataFrame helpers.Box3DTypeSerializer).zmin/zmax).ST_3DBoxIntersects/ST_3DBoxContains.ST_3DDWithindistance predicate (needs squared-Euclidean over 3D).Why Phase 1 is narrow
Box2D's Phase 1 was wide because GeoParquet covering bbox interop drove concrete demand. Box3D today has no equivalent pull (see the original epic's "when a concrete user appears" note). This issue ships the foundation and the SQL surface so it's available, and defers everything that benefits from a real workload to inform design.
Coordination
Match Box2D's design choices wherever possible — the type-system contract (separate UDT, six-double struct), the closed-interval semantics, and the inverted-bounds throw should all feel parallel.