Skip to content

P2.5.7 package-private curve DCEL (Option C, OV-P2 / Bar 2) - #38

Open
grootstebozewolf wants to merge 6 commits into
cursor/p256-mixed-overlay-17abfrom
cursor/curve-dcel-16ed
Open

P2.5.7 package-private curve DCEL (Option C, OV-P2 / Bar 2)#38
grootstebozewolf wants to merge 6 commits into
cursor/p256-mixed-overlay-17abfrom
cursor/curve-dcel-16ed

Conversation

@grootstebozewolf

@grootstebozewolf grootstebozewolf commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Stacked on #37 (cursor/p256-mixed-overlay-17ab @ bb566aa). OV-P2 / Bar 2. Option C only. Do not stack on #27 (OverlayNG-for-circles / public SegmentKind is a dead-end draft). Do not merge this into #7. Does not merge #12 / #13 / #15 / #16 / #17 / #18 / #19 / #20 / #23 / #24 / #25 / #37 / #7. Does not push to feature/sfa-curve-rgr or master. Does not rebase #7 onto locationtech. Does not pick core HalfEdge.java / Quadrant.java.

Sentence

Curve DCEL for PLG/COV. Not a noder. Not OverlayNG-for-circles. Not public. Not a merge into #7.

PLG and COV do not need a noder (public or curve). They need an arrangement structure: half-edges, twins, next/prev, incident face, on CurveSegmentString members (an arc stays an arc). CurveSegmentNoder already names leftover edges for overlay kits. That is a different product. This PR is the DCEL.

SIGN retip (this tip)

CurveSegmentDcel.onString stays in R². Supersedes the HOLD on the hypot rewrite. Not a new rung. Not full curve noding. No public noder. Option C HOLDS (package-private in jts-curve).

  • Arc: compare (dx²+dy²) to with tolerance eps², floored at 1 ulp of the two squares so a representable on-circle node is not rejected. Not hypot(d) − R. Not a length eps on . Do not take sqrt(R). Do not divide by sagitta for the decision.
  • Chord: the same squared residual (dx²+dy² ≤ eps²).
  • CurveSegmentDcelTest pins extreme sagittas in R²: flat sagitta → 0, and a high-sagitta case.
  • leaveAngle / compareLeave HOLD (endpoint quadrant + Orientation.index; atan2 only 1e-8 window / sweep sense). Untouched.

Tip: 2ef0bc6b.

What this is

Package-private CurveSegmentDcel in jts-curve. Built from CurveSegmentString members plus the P2.5.2 node set and already-named MIXED / shared-edge ends. Cycle order is the Faces left-most / next-outgoing walk, persisted as links (left face, CCW interiors). CurveSegmentFaces now assembles Geometry from the DCEL's bounded faces; it is a consumer, not this product.

Leave-angle robustness (locationtech locationtech#1224 / locationtech#1226)

This DCEL does not use core HalfEdge or Quadrant. It sorts its own Half leave direction and stamps TANGENT_LEAVE_ANGLE. Those locationtech fixes are ported into that walk only:

DEVELOPING.md and version history are untouched. Core HalfEdge.java / Quadrant.java are untouched.

Honesty lock

Generic walk-on-nodes==null is unsafe: a MIXED abort can hide a real crossing (HALF_DISC × HALF_CROSSING_UPPER). That pair stamps MIXED_HIDES_CROSSING and stops. A coincident leave-angle is snap-rounding (TANGENT_LEAVE_ANGLE). Pinch / kiss / holed Geometry-level stay null. No invented noder. No densify-then-snap flagged exact. No core SegmentString / HotPixel / noding.snapround.

Cells

Cell Product
R1.5 two-disc crossing DCEL: twins, next/prev, 3 bounded faces (lens + crescents)
H-SHELL-N-MIXED (named diameter) DCEL: T-junctions at (±1, 0), inner + bite
HALF_DISC × HALF_HANGING × STADIUM_FOUR DCEL: nine bounded faces, same cells Faces already named
P2.5.4 HALF_DISC × HALF_HANGING × STADIUM_ODD named stamp TANGENT_LEAVE_ANGLE
locationtech#1224-style distinct direction points leave compare ≠ 0; not a TANGENT stamp
HALF_DISC × HALF_CROSSING_UPPER named stamp MIXED_HIDES_CROSSING
Pinch / TOUCH-ext / holed Geometry null
Flat sagitta / high-sagitta onString R² residual (eps²); hypot HOLD superseded

What this is not

Pins

  • Twins and cycle links, not just "we got a Geometry back".
  • Members stay CurveSegmentString (arc stays arc, chord stays chord).
  • Slack 15%. OverlayNGCurve never Curved. Java 8, Checkstyle, PMD (AvoidBranchingStatementAsLastInLoop).
  • No new public API. No circular noder in jts-core.
  • onString extreme sagittas in R² (flat → 0, high-sagitta). leaveAngle / compareLeave unchanged.

Verify

mvn -pl modules/curve -am test -DfailIfNoTests=false -Dcheckstyle.skip=true -Dpmd.skip=true \
  -Dtest=CurveSegmentDcelTest,CurveSegmentStringTest,CompoundCurveShellOverlayTest,CircularArcOverlayTest,CircularDiscOverlayTest,CircularDiscPolygonOverlayTest,CircularLineOverlayTest,OverlayNGCurvePhase0Test,OverlayNGCurveRatchetTest,OverlayNGCurvePerfGateTest
bash dev/check-no-curved.sh
mvn -pl modules/curve checkstyle:check
mvn -pl modules/curve pmd:check

All green after this revision (2ef0bc6b):

  • CurveSegmentDcelTest 10 / 0 (twins / next / face; P2.5.4 stamp; Make HalfEdge.compareAngularDirection more robust locationtech/jts#1224 leave-compare pin; extreme sagittas in R²)
  • CurveSegmentStringTest 24 / 0
  • CompoundCurveShellOverlayTest 28 / 0
  • CircularArcOverlayTest 11 / 0
  • CircularDiscOverlayTest 12 / 0
  • CircularDiscPolygonOverlayTest 7 / 0
  • CircularLineOverlayTest 7 / 0
  • OverlayNGCurvePhase0Test 19 / 0
  • OverlayNGCurveRatchetTest 50 / 0
  • OverlayNGCurvePerfGateTest 84 / 0 at 15% slack
  • bash dev/check-no-curved.sh OK
  • Checkstyle 0 / PMD clean on jts-curve
Open in Web Open in Cursor 

cursoragent and others added 2 commits August 16, 2026 12:42
Half-edges, twins, next/prev, and incident faces on
CurveSegmentString members. Faces assemble Geometry from the
DCEL. Stamp coincident leave-angles and MIXED-hides-crossing.
Not a noder, not OverlayNG-for-circles, not a public API.

Co-authored-by: Jeroen Bloemscheer <grootstebozewolf@users.noreply.github.com>
atan2-sorted outgoing is CCW; the next slot after the twin is a
right turn. Wire the previous slot so interiors sit on the left.

Co-authored-by: Jeroen Bloemscheer <grootstebozewolf@users.noreply.github.com>
@grootstebozewolf
grootstebozewolf marked this pull request as ready for review August 16, 2026 12:49
grootstebozewolf added a commit that referenced this pull request Aug 16, 2026
cursoragent and others added 2 commits August 16, 2026 16:02
…cationtech#1226)

Order outgoing halves by endpoint quadrant and orientation, not
atan2 of subtracted direction vectors. Stamp TANGENT_LEAVE_ANGLE
when that order ties, so distinct direction points do not collapse.

Co-authored-by: Jeroen Bloemscheer <grootstebozewolf@users.noreply.github.com>
Chord coincidence stays on endpoint quadrant + orientation so
locationtech#1224 distinct direction points do not collapse. Arc leaves still
use the 1e-8 window: a rebuilt circumcircle can put an on-axis
tangent in either adjacent quadrant.

Co-authored-by: Jeroen Bloemscheer <grootstebozewolf@users.noreply.github.com>
cursoragent and others added 2 commits August 16, 2026 16:52
Arc and chord membership compare dx²+dy² to R² / the projection
with tolerance eps². Supersedes the hypot rewrite HOLD. leaveAngle
and compareLeave are untouched.

Co-authored-by: Jeroen Bloemscheer <grootstebozewolf@users.noreply.github.com>
eps² can sit below 1 ulp of R² (N=3 stadium nodes). Floor the
squared compare at the representable gap of the two squares so
hypot-exact nodes still sew. Still no hypot, no sagitta quotient.

Co-authored-by: Jeroen Bloemscheer <grootstebozewolf@users.noreply.github.com>
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.

2 participants