Observed
UX on TestBuilder RC2 (7cd60011).
CIRCULARSTRING (160 580, 270 790, 510 720, 430 390, 810 430) -- 2 arcs
CIRCULARSTRING (137 675, 300 560, 395 711, 340 870, 530 900, 730 740, 680 580, 470 410, 230 360, 220 460, 110 480) -- 5 arcs
| Call |
Result |
Buffer.buffer(CS[3], 10) |
CurvePolygon[9] (laser) + CurveOps.linearise log |
Buffer.bufferAndInverse(CS[3], 10) |
MultiPolygon[1576] (chainsaw) |
Buffer.buffer(CS[5], 10) |
Polygon[2575] (chainsaw) |
OffsetCurve.offsetCurve(CS[3], 10) |
CircularString[3] (laser) |
OffsetCurve.offsetCurve(CS[11], 10) |
LineString[44] (wrong) |
Diagnosis (not self-intersection)
Clearance of the 5-arc case is 86.8 vs 20 required (curve_ring_simple_of_clearance). The offset ring should be simple. The bug is order of operations: densify chords then offset, so LineString[44] (~8.8 pts/arc) sits ~10 from the chords, not from the arcs (sagitta ~2 at r≈130 → sample distance 8–10 instead of constant 10).
Every CircularString join is a corner (shared endpoint, not G1). Samples: 42.9°–117.8° kinks, S-curve sign flips, major arcs (one −278.7°). Preservation dies at two arcs because OFF only handles a single 3-pt triple. Round-join edges are required (CurveRingOffset / Bible §7).
Expected
- Multi-arc offset:
COMPOUNDCURVE of concentric CIRCULARSTRING pieces plus round-join CIRCULARSTRINGs at corners. Not LINESTRING.
- Sampled offset points: distance to the arcs is |d| (10), not 8–10.
- Multi-arc buffer:
CURVEPOLYGON corridor (BUF-N / bufferOpenCompound), not POLYGON[2575].
- No
CurveOps.linearise flood on those calls.
Not
Observed
UX on TestBuilder RC2 (
7cd60011).Buffer.buffer(CS[3], 10)CurvePolygon[9](laser) +CurveOps.lineariselogBuffer.bufferAndInverse(CS[3], 10)MultiPolygon[1576](chainsaw)Buffer.buffer(CS[5], 10)Polygon[2575](chainsaw)OffsetCurve.offsetCurve(CS[3], 10)CircularString[3](laser)OffsetCurve.offsetCurve(CS[11], 10)LineString[44](wrong)Diagnosis (not self-intersection)
Clearance of the 5-arc case is 86.8 vs 20 required (
curve_ring_simple_of_clearance). The offset ring should be simple. The bug is order of operations: densify chords then offset, soLineString[44](~8.8 pts/arc) sits ~10 from the chords, not from the arcs (sagitta ~2 at r≈130 → sample distance 8–10 instead of constant 10).Every CircularString join is a corner (shared endpoint, not G1). Samples: 42.9°–117.8° kinks, S-curve sign flips, major arcs (one −278.7°). Preservation dies at two arcs because OFF only handles a single 3-pt triple. Round-join edges are required (
CurveRingOffset/ Bible §7).Expected
COMPOUNDCURVEof concentricCIRCULARSTRINGpieces plus round-joinCIRCULARSTRINGs at corners. NotLINESTRING.CURVEPOLYGONcorridor (BUF-N /bufferOpenCompound), notPOLYGON[2575].CurveOps.lineariseflood on those calls.Not