fix: prevent GeometryOptimizer from merging semicircular arcs into invalid arc
After splitting a drawing with a circular hole, CadConverterForm writes the split piece to DXF and re-imports it. The circle (decomposed into two semicircular arcs by DrawingSplitter) was being incorrectly merged back into a single zero-sweep arc by GeometryOptimizer.TryJoinArcs during reimport. Root cause: TryJoinArcs mutated input arc angles in-place and didn't guard against merging two arcs that together form a full circle. When arc2 had startAngle=π, endAngle=0 (DXF wrap-around from 360°→0°), the mutation produced startAngle=-π, and the merge created an arc with startAngle=π, endAngle=π (zero sweep), losing half the hole. Fix: use local variables instead of mutating inputs, require arcs to be adjacent (endpoints touching) rather than just overlapping, and refuse to merge when the combined sweep would be a full circle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -133,17 +133,30 @@ namespace OpenNest.Geometry
|
||||
if (!arc1.Radius.IsEqualTo(arc2.Radius))
|
||||
return false;
|
||||
|
||||
if (arc1.StartAngle > arc1.EndAngle)
|
||||
arc1.StartAngle -= Angle.TwoPI;
|
||||
var start1 = arc1.StartAngle;
|
||||
var end1 = arc1.EndAngle;
|
||||
var start2 = arc2.StartAngle;
|
||||
var end2 = arc2.EndAngle;
|
||||
|
||||
if (arc2.StartAngle > arc2.EndAngle)
|
||||
arc2.StartAngle -= Angle.TwoPI;
|
||||
if (start1 > end1)
|
||||
start1 -= Angle.TwoPI;
|
||||
|
||||
if (arc1.EndAngle < arc2.StartAngle || arc1.StartAngle > arc2.EndAngle)
|
||||
if (start2 > end2)
|
||||
start2 -= Angle.TwoPI;
|
||||
|
||||
// Check that arcs are adjacent (endpoints touch), not overlapping
|
||||
var touch1 = end1.IsEqualTo(start2) || (end1 + Angle.TwoPI).IsEqualTo(start2);
|
||||
var touch2 = end2.IsEqualTo(start1) || (end2 + Angle.TwoPI).IsEqualTo(start1);
|
||||
if (!touch1 && !touch2)
|
||||
return false;
|
||||
|
||||
var startAngle = arc1.StartAngle < arc2.StartAngle ? arc1.StartAngle : arc2.StartAngle;
|
||||
var endAngle = arc1.EndAngle > arc2.EndAngle ? arc1.EndAngle : arc2.EndAngle;
|
||||
var startAngle = start1 < start2 ? start1 : start2;
|
||||
var endAngle = end1 > end2 ? end1 : end2;
|
||||
|
||||
// Don't merge if the result would be a full circle (start == end)
|
||||
var sweep = endAngle - startAngle;
|
||||
if (sweep >= Angle.TwoPI - Tolerance.Epsilon)
|
||||
return false;
|
||||
|
||||
if (startAngle < 0) startAngle += Angle.TwoPI;
|
||||
if (endAngle < 0) endAngle += Angle.TwoPI;
|
||||
|
||||
Reference in New Issue
Block a user