mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-13 05:42:38 +00:00
M4: round_corners: each contour's own size sets its weld tolerance (#2222)
The tolerance that drops the sweep's slivers came from the whole path's bounding box, so a contour a million units wide welded away the real half-unit edges of a separate small contour. Each closed subpath now sets its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Model-Effort: Opus 5.5 drove and wrote
This commit is contained in:
1 parent
ec105d0f56
commit
4c91f9084b
2 files changed
+22
-2
No files matched your search
@@ -114,10 +114,12 @@ pub fn round_corners(path: &BezPath, radius: f64, smoothing: f64) -> BezPath {
|
||||
return path.clone();
|
||||
}
|
||||
let smoothing = if smoothing.is_finite() { smoothing.clamp(0.0, 1.0) } else { 0.0 };
|
||||
let bb = path.bounding_box();
|
||||
let weld = (bb.width().max(bb.height()) * 1e-6).max(1e-9);
|
||||
let mut out = BezPath::new();
|
||||
for sub in figcraft_geom::split_subpaths(path) {
|
||||
// Each contour's own size sets its cleanup tolerance, so a large contour can't weld away
|
||||
// the real short edges of a small island or hole beside it.
|
||||
let bb = sub.bounding_box();
|
||||
let weld = (bb.width().max(bb.height()) * 1e-6).max(1e-9);
|
||||
let closed = matches!(sub.elements().last(), Some(PathEl::ClosePath));
|
||||
match closed.then(|| round_subpath(&sub, radius, smoothing, weld)).flatten() {
|
||||
Some(p) => out.extend(p.elements().iter().copied()),
|
||||
|
||||
@@ -236,3 +236,21 @@ fn junk_never_panics() {
|
||||
zig.close_path();
|
||||
assert!(all_finite(&round_corners(&zig, 2.0, 0.0)));
|
||||
}
|
||||
|
||||
/// The cleanup tolerance is each contour's own: a contour a million units wide doesn't weld away
|
||||
/// the half-unit notch of a separate small contour in the same path.
|
||||
#[test]
|
||||
fn a_large_contour_does_not_weld_a_small_ones_short_edges() {
|
||||
let mut p = rect(0.0, 0.0, 1e6, 1e6);
|
||||
let x = 2e6;
|
||||
for (i, (dx, y)) in [(0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (5.5, 10.0), (5.5, 9.5), (5.0, 9.5), (5.0, 10.0), (0.0, 10.0)].into_iter().enumerate()
|
||||
{
|
||||
if i == 0 { p.move_to((x + dx, y)) } else { p.line_to((x + dx, y)) }
|
||||
}
|
||||
p.close_path();
|
||||
let out = round_corners(&p, 0.001, 0.0);
|
||||
let reaches = |q: Point| {
|
||||
out.elements().iter().any(|el| matches!(el, PathEl::MoveTo(e) | PathEl::LineTo(e) | PathEl::CurveTo(_, _, e) if (*e - q).hypot() < 0.01))
|
||||
};
|
||||
assert!(reaches(pt(x + 5.0, 9.5)) && reaches(pt(x + 5.5, 9.5)), "the notch's floor is kept");
|
||||
}
|
||||
Reference in new issue
Block a user