Skip to content

Add ST_DWithin(Box2D, Box2D, distance) overload #2971

@jiayuasu

Description

@jiayuasu

Follow-up to the Box2D spatial-join work in #2939. That PR explicitly scoped out the distance-join case because ST_DWithin only accepted (Geometry, Geometry, distance) and (Geography, Geography, distance) overloads — so ST_DWithin(box, box, d) was rejected at analysis time.

Scope

Add a planar (Box2D, Box2D, distance) overload so distance joins on Box2D columns are accepted and route through Sedona's existing distance-join planner (BroadcastIndexJoinExec and DistanceJoinExec).

Semantics

  • Closed-interval Euclidean distance between two AABBs: sqrt(dx² + dy²) where dx = max(0, max(a.xmin - b.xmax, b.xmin - a.xmax)) and similarly for dy. Overlapping or edge/corner-touching boxes have distance 0 and therefore match any non-negative radius.
  • Inverted bounds (xmin > xmax / ymin > ymax) throw IllegalArgumentException, matching the contract of ST_BoxIntersects / ST_BoxContains. Inverted-bound values are reserved for the future antimeridian-wraparound semantics.
  • Negative radius never matches.

Why a new overload

ST_DWithin is already wired through JoinQueryDetector and OptimizableJoinCondition; both treat the 3-arg form generically based on shape expression dataType, and the toExpandedEnvelopeRDD path uses the Box2D → polygon dispatch landed in #2939. The only thing blocking Box2D × Box2D distance joins is the absence of a scalar Predicates.dWithin(Box2D, Box2D, double) overload and a matching inferrableFunction3 entry in the ST_DWithin InferredExpression. With those, the join planner accepts the predicate and the per-pair refine dispatches back to the new scalar.

Deliverables

  • Predicates.dWithin(Box2D, Box2D, double) in common.
  • 4th inferrableFunction3 entry on ST_DWithin in spark/common/.../Predicates.scala. The pre-existing 3-arg geometry entry needs an explicit lambda because two arity-3 overloads named Predicates.dWithin now exist on the Java side.
  • Scalar tests in PredicatesTest (overlap, edge/corner touching, separation on one axis, Pythagorean separation, negative radius, inverted-bound rejection).
  • Join tests in Box2DJoinSuite (broadcast-index path at multiple radii, non-broadcast DistanceJoinExec path, zero-radius edge-touching).
  • Docs: new docs/api/sql/box2d/Box2D-Predicates/ST_DWithin.md and a row in Box2D-Functions.md.

Out of scope

  • A (Box2D, Box2D, distance, useSpheroid) 4-arg overload. useSpheroid is geography territory; Box2D is planar.
  • A specialised R-tree over Box2D (tracked separately in Specialized R-tree index over Box2D (perf) #2940 — only worth doing if profiling shows the JTS Envelope construction is a real cost).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions