Trim and Break on ellipses, splines and conics: cut at the exact crossings (alternating projection onto both curves), pieces stay exact (Bézier spans as single-span control splines, conic arcs as conics); geom Seg2::split_at and closest_param
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
097217a3f3
commit
d285cedd73
6 files changed
+371
No files matched your search
@@ -342,3 +342,43 @@ fn free_form_profiles_extrude_exactly() {
|
||||
let m = run(&mut s, "MeasureCommand", json!({}));
|
||||
assert!(m["bodies"][0]["faces"].as_u64().unwrap() <= 5, "{m}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trim_and_break_free_form_curves_exactly() {
|
||||
let pi = std::f64::consts::PI;
|
||||
let mut s = new_sketch();
|
||||
// An ellipse cut by a line through its centre: trimming the lower half leaves the upper
|
||||
// half, which closes with the line into half the ellipse.
|
||||
let e = ids(&run(&mut s, "CircleElipse", json!({"center": [0, 0], "major": [10, 0], "minor_radius": 4}))["curves"])[0].clone();
|
||||
let l = ids(&run(&mut s, "DrawPolyline", json!({"points": [[-15, 0], [15, 0]]}))["curves"])[0].clone();
|
||||
let r = run(&mut s, "TrimSketchCmd", json!({"curve": e, "at": [0, -4]}));
|
||||
assert!(!r["result"]["pieces"].as_array().unwrap().is_empty(), "{r}");
|
||||
let a = profiles(&s);
|
||||
assert_eq!(a.len(), 1, "{a:?}");
|
||||
assert!((a[0] - pi * 20.0).abs() < 1e-6, "{a:?}");
|
||||
let _ = l;
|
||||
// A fit spline broken where a line crosses it: two pieces that still trace the curve.
|
||||
let mut s = new_sketch();
|
||||
let sp = ids(&run(&mut s, "DrawSpline", json!({"points": [[0, 0], [10, 10], [20, 0], [30, 5]]}))["curves"])[0].clone();
|
||||
let before = sketch(&s).polyline(sketch(&s).curve_index(&sp).unwrap());
|
||||
run(&mut s, "DrawPolyline", json!({"points": [[15, -10], [15, 20]]}));
|
||||
let r = run(&mut s, "BreakSketchCmd", json!({"curve": sp, "at": [15, 5]}));
|
||||
let pieces = ids(&r["curves"]);
|
||||
assert_eq!(pieces.len(), 4, "three Béziers, the middle one split: {r}");
|
||||
let sk = sketch(&s);
|
||||
// Every original sample lies on one of the pieces.
|
||||
let polys: Vec<Vec<Vec2>> = pieces.iter().map(|id| sk.polyline(sk.curve_index(id).unwrap())).collect();
|
||||
for q in before.iter().step_by(5) {
|
||||
let d = polys
|
||||
.iter()
|
||||
.flat_map(|p| {
|
||||
p.windows(2).map(|w| {
|
||||
let (a, b) = (w[0], w[1]);
|
||||
let t = ((*q - a).dot(b - a) / (b - a).len2()).clamp(0.0, 1.0);
|
||||
q.dist(a + (b - a) * t)
|
||||
})
|
||||
})
|
||||
.fold(f64::INFINITY, f64::min);
|
||||
assert!(d < 0.05, "{q:?} {d}");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user