Skip to content

VoronoiDiagramBuilder: tolerance-based dedup + safe cell construction (stacked on #1212)#1213

Closed
grootstebozewolf wants to merge 0 commit into
locationtech:masterfrom
grootstebozewolf:stacked-on-1212-voronoi-deduplication
Closed

VoronoiDiagramBuilder: tolerance-based dedup + safe cell construction (stacked on #1212)#1213
grootstebozewolf wants to merge 0 commit into
locationtech:masterfrom
grootstebozewolf:stacked-on-1212-voronoi-deduplication

Conversation

@grootstebozewolf

Copy link
Copy Markdown
Contributor

Stacked PR on top of #1212

Suggested title:
VoronoiDiagramBuilder: tolerance-based dedup + safe cell construction (stacked on #1212)

Base: the head of PR #1212 (or micycle1:fixup / the PR branch once merged).

Summary

This is a stacked PR built directly on top of the great work in #1212.

PR #1212 delivers:

  • A fast Shewchuk-style error-bounded isInCircleRobust (double fast-path + DD fallback)
  • Orientation.index for Vertex.isCCW
  • Broader robustness tests

This change adds the pieces required to fully resolve the original #20 report for the public VoronoiDiagramBuilder API:

  • Tolerance-based deduplication using KdTree when setTolerance(tol > 0)
  • Public helper DelaunayTriangulationBuilder.unique(Coordinate[], double)
  • Defensive LinearRing construction in getVoronoiCellPolygon (guarantees a valid ≥4-point ring and that cell count always matches the number of unique sites)
  • Strict regression test using the exact 7-point WKB from the issue + setTolerance(0.1), asserting isValid() + exactly 4 cells
  • Full documentation + reference to the Rocq/Flocq formal verification (doc/issue20-verification.md)

Why this stack?

The predicate improvements in #1212 are an excellent foundation for the whole triangulation stack.

For the specific scenario reported in #20 (VoronoiDiagramBuilder + positive tolerance on near-coincident sites), we also need upstream prevention and downstream safety:

  • Users reasonably expect setTolerance(0.1) to collapse near-coincident sites and produce the correct number of cells.
  • Even with stronger predicates, the Voronoi dual walk can still produce degenerate rings for certain configurations.

This work provides exactly that defense-in-depth on top of the predicate improvements.

Relationship to #1212

  • Complementary, not competing.
  • The isInCircleRobust filter from Improve triangulation robustness #1212 becomes the new robust implementation.
  • This PR supplies the higher-level input sanitization and output guarantees that make the reported reproducer (and the documented setTolerance behavior) actually work.

Testing & verification

  • The new VoronoiDiagramBuilderTest#testRobustnessIssue20NearCoincidentPoints (literal WKB + setTolerance(0.1)) passes and asserts the expected 4 cells.
  • Full Voronoi + Delaunay test suites continue to pass.
  • Formal verification reference for the orientation predicate via NetTopologySuite.Proofs (Rocq + Flocq).

Request to the author / maintainers

@micycler1 — I really like the direction in #1212. The bounded fast-path incircle predicate is a nice improvement.

I put this together as a stack on top because the original #20 issue (and many real-world Voronoi users) specifically exercise VoronoiDiagramBuilder.setTolerance(...). Would you be open to reviewing this, or folding the relevant parts (dedup + cell safety) into the base PR? I'm very happy to rebase, adjust scope, or change anything to make the overall contribution stronger.

The only goal here is to make JTS more robust for everyone.

Happy to chat about any trade-offs.

Thanks again for pushing on this area!

#MakeJTSStronger

High-level diff

  • DelaunayTriangulationBuilder / VoronoiDiagramBuilder: dedup via KdTree + unique(..., tolerance)
  • QuadEdgeSubdivision: safe getVoronoiCellPolygon (tiny valid ring synthesis + count invariant)
  • VoronoiDiagramBuilderTest: exact Robustness failure in VoronoiDiagramBuilder #20 repro test with count assertion
  • doc/: verification report + history entry

How to publish this stacked PR (copy-paste these steps):

# 1. Make sure you have the stacked branch based on the PR
git checkout stacked-on-1212-voronoi-deduplication

# 2. Push the branch to your fork
git push -u origin stacked-on-1212-voronoi-deduplication

# 3. On GitHub:
#    - Go to your fork → "Compare & pull request"
#    - **Change the base** to the branch from PR #1212 (usually `micycle1:fixup` or the PR head)
#    - Use the title and body below
#    - Create PR

Ready-to-paste PR title + body:

VoronoiDiagramBuilder: tolerance-based dedup + safe cell construction (stacked on #1212)

This is a stacked PR built directly on top of the great work in #1212.

PR #1212 delivers:
- A fast Shewchuk-style error-bounded `isInCircleRobust` (double fast-path + DD fallback)
- `Orientation.index` for `Vertex.isCCW`
- Broader robustness tests

This change adds the pieces required to fully resolve the original #20 report for the public `VoronoiDiagramBuilder` API:

- Tolerance-based deduplication using `KdTree` when `setTolerance(tol > 0)`
- Public helper `DelaunayTriangulationBuilder.unique(Coordinate[], double)`
- Defensive `LinearRing` construction in `getVoronoiCellPolygon` (guarantees a valid ≥4-point ring and correct cell count)
- Strict regression test using the exact 7-point WKB + `setTolerance(0.1)` asserting exactly 4 cells + isValid()
- Documentation + Rocq/Flocq formal verification reference

The predicate improvements in #1212 are an excellent foundation. This layers the upstream prevention and downstream safety that make the reported reproducer (and the documented tolerance behavior) actually work.

@micycler1 — really like the direction in #1212. Would you be open to reviewing this stack, or folding the dedup + cell safety pieces in? Happy to adapt anything. Goal is simply to make JTS stronger.

#MakeJTSStronger

(Also see stacked-pr-setup-commands.txt for the full setup commands.)

@grootstebozewolf grootstebozewolf force-pushed the stacked-on-1212-voronoi-deduplication branch 2 times, most recently from 14e9a97 to d5d5dab Compare July 12, 2026 09:46
@grootstebozewolf grootstebozewolf force-pushed the stacked-on-1212-voronoi-deduplication branch from d5d5dab to 07833d3 Compare July 12, 2026 10:07
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.

1 participant