Add the OverlayNG noding substrate (phase 1): exact noded arrangements with symbolic nodes#442
Draft
asinghvi17 wants to merge 6 commits into
Draft
Add the OverlayNG noding substrate (phase 1): exact noded arrangements with symbolic nodes#442asinghvi17 wants to merge 6 commits into
asinghvi17 wants to merge 6 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the `rk_compare_along_segment` kernel predicate (planar and spherical
implementations, certified Float64 filter with a conditioning-inflated error
bound escalating to an exact `Rational{BigInt}` / triple-product fallback) for
OverlayNG node ordering (design §2.5).
Grow the exact-crossing authority in place: give `_exact_crossing_point` a
`NodeKey` call shape so node-ordering keys, coincidence, and emission fallback
share one shape, and route the two internal callers through it (design §2.6).
Add `_ring_material_interior_on_left` beside `_ring_interior_on_left` so the
hole flip for overlay labeling lives in exactly one place (design §2.7).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add `src/methods/clipping/overlayng/noding/`, the exact-arrangement noding substrate (design §2.1–§2.6): `NodedArrangement` and its symbolic `NodeTable`, the collect / node-identity / split / emit stages, and the certified double-double planar emission fast path with a rational fallback plus the gated-float spherical crossing-direction emission. Node identity, ordering, and coincidence are decided by exact kernel predicates over input vertices and symbolic `NodeKey`s; Float64 appears only as certified filters and at emission. Reuses `RelateSegmentString`, the RelateNG edge index, and the exact kernel unchanged. Everything is internal (no exports). Wired into `GeometryOps.jl`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add `test/methods/clipping/overlayng/noding.jl` covering the design §2.9 gate list: the `NodedArrangement` invariants on constructed cases (crossing quads, degree-6 tier-2 merge, crossing-on-a-vertex, collinear shared boundary, a–b–a spike), the dense-comb ordering cross-check against the exact authority on both manifolds, the certified emission audit (planar certified == rational for every node; spherical direction within bound of exact), and the rounded-arrangement + classification censuses on a small Natural Earth subset. Registered in `test/runtests.jl`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tier-2 sweep confirms zero coincidences on all real data and on the dense synthetic (S1), so the O(n) key-rehash compaction was pure overhead there (~20 ms of a 50 ms synthetic build). Return the merge count from the sweep and take a fast path that only dedups the interior lists when nothing merged. Also defer the output-coordinate cache allocation to a single post-split `_ensure_coord_cache!` instead of growing it per interned node, since it is an emission concern that noding never touches. Synthetic 250×250 build 50 → 30 ms; emission unchanged at 0.026 µs/node. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`@autodocs Modules = [GeometryOps]` renders unexported docstrings, so an `@ref` to an internal name without its own rendered docstring (`NodeTable`, `NodedEdge`) would fail the docs cross-reference check. Reference internal names with plain backticks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1 of the OverlayNG port: the noding substrate — from two geometries to an exact noded arrangement, plus coordinate emission. Stacked on
relateng(#416); merge after it. Design doc:docs/plans/2026-07-16-overlayng-noding-substrate.md(first commit on this branch), which also records the survey + spike evidence base (S1–S4) behind every decision here.Design in one paragraph
Overlay is computed as an exact arrangement with symbolic nodes, rounded once at emission — the constructive extension of RelateNG's design D2. There is no snapping, no snap-rounding, no precision model, and no retry ladder, permanently: that JTS machinery patches an inexact-noding substrate this engine doesn't have. No constructed coordinate ever enters a decision; Float64 appears only inside certified filters (which escalate to the exact kernel predicates on uncertainty) and at final emission. The pipeline keeps JTS OverlayNG's shape (node → graph → label → build) so later phases stay file-by-file diffable against Java.
What's here
src/methods/clipping/overlayng/noding/(~600 SLOC, all internal, nothing exported):noded_arrangement.jl—NodedArrangement{P}/NodedEdge: noded edges are(string, segment, node_lo, node_hi)references; a noded edge carries no geometry, so source metadata cannot desynchronize.collect.jl— candidate enumeration via the existing payloadRTree+dual_depth_first_search, classification viark_classify_intersection; proper crossings become symbolic nodes on both parents, touch/collinear incidences become input-vertex nodes (asserted, not assumed). Accepts optional prebuilt trees (a prepared geometry's edge index is the same structure).node_identity.jl— two-tier node identity: egalNodeKeyDict, then a float-sweep with certified radii proposing candidate coincidences confirmed byrk_nodes_coincide, union-find over confirmed pairs only (zero on all real data measured; exercised by degree-6 constructed cases).split.jl— per-segment ordered/deduped interior node lists → noded edges, zero-length guarded.emit.jl— the only lossy step, memoized: planar crossings via a certified double-double fast path (accepted iff provably correctly rounded,Rational{BigInt}fallback); spherical crossings via a conditioning-gated float direction (exact_sph_crossing_dirfallback); vertex nodes pass through bit-exact.rk_compare_along_segment— newrk_predicate ordering nodes along a segment: certified float stage, lazy exact fallback (S1 measured the float stage resolving 100% of comparisons on real data, 240–590× vs exact-always in dense regimes)._ring_material_interior_on_left— the material-interior orientation authority (the hole-side flip exists exactly once, next to_ring_interior_on_left), which phase 2'sdepth_deltaderivation consumes.Validation
test/methods/clipping/overlayng/noding.jl) + 422 (test/methods/relateng/kernel_along_segment.jl): the five arrangement invariants on constructed cases (degree-6 coincident node, crossing-on-third-string-vertex, vertex-identical shared borders → zero phantom crossings, a–b–a spikes), float-vs-exact-always ordering cross-check, emission certificate audit (certified result == rational result on every node, >7,000 nodes), and an env-gated NE-110m real-data subset asserting the invariants plus the rounded-arrangement audit (zero rounding-introduced crossings, both manifolds).Not in this PR (phase 2/3, per the design doc)
Half-edge graph,
OverlayLabel/labeller, ring builders (phase 2); the ops,symdifference, mixed dimensions, and the public opt-inOverlayNG{M}algorithm with differential validation vs GEOS and s2 (phase 3). Existing clipping behavior is completely untouched.🤖 Generated with Claude Code