Skip to content

Improve triangulation robustness - #1212

Open
micycle1 wants to merge 2 commits into
locationtech:masterfrom
micycle1:fixup
Open

Improve triangulation robustness#1212
micycle1 wants to merge 2 commits into
locationtech:masterfrom
micycle1:fixup

Conversation

@micycle1

@micycle1 micycle1 commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

isInCircleRobust now computes the in-circle determinant in doubles with a Shewchuk-style error bound: if the magnitude clears the bound, the sign is provably correct and returned at full speed; otherwise it falls back to the existing isInCircleDDNormalized extended-precision evaluation.

Vertex.isCCW now uses Orientation.index.

~12% slower on a 200k random-point triangulation.

Closes #20, #298, #310, #1190 (and therefore #1138), GEOS #1286, and supersedes PR #311.

@grootstebozewolf

Copy link
Copy Markdown
Contributor

Thanks for this — differential check from the NetTopologySuite.Proofs side (mesh / Delaunay lane).

Method

  • Oracle: extracted b64_inCircle via INCIRCLE_SIGN (same kernel as in-process nts_rocq_in_circle; Shewchuk sign: POS ⇔ CCW triangle and P strictly inside).
  • Stage A mirror: pure double of this PR’s isInCircleRobust filter (iccerrboundA = (10 + 96·ε)·ε, permanent-scaled; CERTAIN iff |disc| > errbound).
  • We did not re-run the full Maven suite or claim bit-identity of the DD fallback with the oracle.

Vectors / generator: jts-1212-incircle-lane (table in oracle/jts1212_incircle_vectors.txt).

Results (29 vectors)

Check Result
Certified pin failures (EXPECTED set) 0
Stage A CERTAIN vs oracle sign conflicts 0
Stage A UNCERTAIN (correct declines) 11

Pins that should hit the DD path (oracle ZERO, Stage A UNCERTAIN): vertex-on-circumcircle (incl. your #1190 constrained triangle sites) and exact cocircular square diagonals. That is expected: |disc| = 0 never clears a positive permanent bound.

Decisive non-zero pins (CERTAIN match): knife-edge ±, flip witness A=(0,0),B=(2,0),C=(1,1),P=(1,-½) → POS, outside-disk witness → NEG, scaled flip (homothety) → POS.

Your regression sites (sample)

Case Oracle Stage A
#1190 triangle constraint vertices ZERO UNCERTAIN
testCircle sample quads NEG CERTAIN
GEOS#1040 / JTS#1171 near-cocircular quad NEG CERTAIN
JTS#1171 ex.2 (GEOS 955 subset) POS ZERO · UNCERTAIN
JTS#20 near-coincident (first 4 WKB sites) NEG CERTAIN

The GEOS 955 subset is the useful illustration that Stage A alone is not enough:

A = (18.68285714285716, 100.105)
B = (13.41, 104.82100000000001)
C = (13.41, 107.179)
P = (18.682857142857145, 111.89500000000001)
  • Stage A double: disc classifies as ZERO, filter UNCERTAIN
  • Oracle b64_inCircle: POS (strictly inside)

A bare disc > 0 without the uncertain→DD branch would return false here; the fallback path is doing real work. That matches the design of this PR.

Bottom line

Filter shape looks right relative to an independent extracted in-circle kernel: CERTAIN doubles never disagreed with the oracle on this table, and the cases that must use DD (exact zeros + the 955 subset) are correctly marked UNCERTAIN. Happy to re-run if you add more quads to the test suite.

(Affiliation: NetTopologySuite.Proofs — formal mesh/predicate companion, not a JTS committer review.)

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.

Robustness failure in VoronoiDiagramBuilder

2 participants