Sheet metal: a whole circle in the outline is sewn as its two exact halves

Since 09c979a4b a circle in a profile is one closed arc (Loop2::circle). The sheet's
faces passed it to the sew as one arc edge from a point back to itself, which the sew
refuses ("sew: a degenerate edge"): a sewn edge runs between two vertices, and an arc
edge is the circle through its ends and middle. A disc's flange failed (first with the
4-face minimum, then with the degenerate edge). Each closed curve of a cell is now split
into its two exact halves (Seg2::split_half) where the cell's edges are prepared, as a
hole's wall already came out: a disc is two caps and two half walls.

sheet::tests::tiny_cut_inside_exact_circle_survives_unfold_refold_and_dxf now builds the
disc flange and fails later, on SMLib's extrude of the 50 nm tool (an SMLib tolerance
defect, reported separately).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-29 22:53:55 -04:00
committed by Irakli Kourtis
parent beaed5b351
commit 41206c065b
+15 -4
View File
@@ -1420,11 +1420,22 @@ impl SheetBody {
let mut v = Vec::new();
for e in segs {
let Seg2::Line { a, b } = *e else {
split_edges += 1;
if split_edges > MAX_FLAT_POINTS {
return Err(flat_budget_error());
// A closed curve (a whole circle is one arc, `Loop2::circle`) in its two
// exact halves: a sewn edge runs between two vertices, and an arc's wall is
// the cylinder through its ends and middle.
let halves = if e.start().dist(e.end()) < LINEAR_TOL {
let (h0, h1) = e.split_half();
vec![h0, h1]
} else {
vec![*e]
};
for h in halves {
split_edges += 1;
if split_edges > MAX_FLAT_POINTS {
return Err(flat_budget_error());
}
v.push(h);
}
v.push(*e);
continue;
};
let d = b - a;