Replace the geo crate as vortex-spatial's computation engine with an in-house core that runs directly over the native columnar geometry layout. geo stays only as a dev-dependency: test oracle and bench baseline.
Status
Active
Motivation
Each row-oriented kernel (ST_Intersects, ST_Contains, ST_Distance, ST_Area, ST_ConvexHull) currently decodes every batch Vortex → Arrow → geoarrow → per-row geo_types::Geometry before computing. Owning the core:
- removes that materialization — measured ~3-4x on
ST_Area after the swap;
- puts geometry semantics (degenerate inputs, NaN policy, panics) under Vortex's control;
- aligns with the kernels that are already native (
ST_Length, ST_MakeLine, ST_Collect, ST_Envelope).
Approach
vortex-spatial/src/algorithms/: pure 2-D functions over borrowed slice views (GeometryRef) — no vortex-array types, no per-row allocation.
GeometryBatch canonicalizes a column once and hands out zero-copy row views; a constant operand is a one-row batch.
- Kernels keep the existing dispatch shells; only the decode bridge and the per-row math change.
- The
robust crate supplies exact orientation predicates where a sign test decides topology.
Correctness
- Every algorithm is differential-tested against
geo: curated fixed cases (empties, unclosed rings, holes past the exterior, mixed winding) plus proptest properties per geometry family — failures shrink to a minimal counterexample and persist to proptest-regressions/.
- Comparisons are exact, not epsilon: the core mirrors
geo's float operation order, so drift fails loudly.
- The oracle is
geo as the kernels actually used it, through the geo_types constructors. Phase 1 caught two traps this hides: rings are implicitly closed, and a polygon's bbox is its exterior ring only.
- Pre-existing kernel tests stay green unchanged. Deliberate divergences (e.g. hull ring rotation) get a documented canonical form with their own tests.
- On disagreement, PostGIS is the tie-breaker —
geo is not automatically right.
Phases
Out of scope
- Overlay/boolean ops (
ST_Intersection, union, difference) stay on geo::BooleanOps; no generic DE-9IM relate.
- Arrow/WKB interop (
geoarrow, geoarrow-cast, wkb) is untouched — this Epic covers computation only.
Replace the
geocrate as vortex-spatial's computation engine with an in-house core that runs directly over the native columnar geometry layout.geostays only as a dev-dependency: test oracle and bench baseline.Status
Active
Motivation
Each row-oriented kernel (
ST_Intersects,ST_Contains,ST_Distance,ST_Area,ST_ConvexHull) currently decodes every batch Vortex → Arrow → geoarrow → per-rowgeo_types::Geometrybefore computing. Owning the core:ST_Areaafter the swap;ST_Length,ST_MakeLine,ST_Collect,ST_Envelope).Approach
vortex-spatial/src/algorithms/: pure 2-D functions over borrowed slice views (GeometryRef) — no vortex-array types, no per-row allocation.GeometryBatchcanonicalizes a column once and hands out zero-copy row views; a constant operand is a one-row batch.robustcrate supplies exact orientation predicates where a sign test decides topology.Correctness
geo: curated fixed cases (empties, unclosed rings, holes past the exterior, mixed winding) plusproptestproperties per geometry family — failures shrink to a minimal counterexample and persist toproptest-regressions/.geo's float operation order, so drift fails loudly.geoas the kernels actually used it, through thegeo_typesconstructors. Phase 1 caught two traps this hides: rings are implicitly closed, and a polygon's bbox is its exterior ring only.geois not automatically right.Phases
geooracle, coveringST_LengthandST_Distancefirst — test(vortex-spatial): add differential test harness against the geo oracle #9391GeometryRefviews,Aabb, area, bounding-rect; swapST_Area, theGeometryAabbaggregate, and the prune rulesST_Distance: point/segment/segment-segment primitives plus point-in-polygonST_Intersects: segment intersection and the full type-pair matrix, with a columnar bbox prescreenST_Contains: interior/boundary-aware matrix (no generic DE-9IM relate)ST_ConvexHull: monotone chain, canonical ring form, native polygon output sinkgeo_typesdecode path; movegeoto dev-dependenciesOut of scope
ST_Intersection, union, difference) stay ongeo::BooleanOps; no generic DE-9IMrelate.geoarrow,geoarrow-cast,wkb) is untouched — this Epic covers computation only.