Exact profiles for splines of any degree (a degree-4…7 Bézier segment kind, Seg2::Bezier, extruded as B-spline edges) and for free-form curves cut by crossings (exact sub-curves whose ends are moved to the true crossing, found by Newton; polylines only where that fails)
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
f79b5c1045
commit
b9bc75670c
11 files changed
+389
-34
No files matched your search
@@ -153,6 +153,15 @@ fn add_pieces(sk: &mut Sketch, segs: &[Seg2], start: Option<usize>, end: Option<
|
||||
let x = sk.add_point(apex, None)?;
|
||||
CurveKind::Conic { a: prev, b: to, apex: x, rho: w / (1.0 + w) }
|
||||
}
|
||||
Seg2::Bezier { n, p } => {
|
||||
let k = (n as usize).clamp(1, solvecraft_geom::MAX_BEZIER_DEGREE);
|
||||
let mut pts = vec![prev];
|
||||
for q in p.iter().take(k).skip(1) {
|
||||
pts.push(sk.add_point(*q, None)?);
|
||||
}
|
||||
pts.push(to);
|
||||
CurveKind::Spline { pts, control: true, degree: n }
|
||||
}
|
||||
Seg2::Arc { .. } => return Err(bad("trim", "unexpected arc piece")),
|
||||
};
|
||||
let c = sk.add_curve(kind, None)?;
|
||||
|
||||
@@ -343,6 +343,35 @@ fn free_form_profiles_extrude_exactly() {
|
||||
assert!(m["bodies"][0]["faces"].as_u64().unwrap() <= 5, "{m}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn degree_five_and_cut_free_form_profiles_extrude_exactly() {
|
||||
let vol = |s: &mut Session| run(s, "MeasureCommand", json!({}))["total"]["volume_mm3"].as_f64().unwrap();
|
||||
// A degree-5 control spline closed by a line: one B-spline side face.
|
||||
let mut s = new_sketch();
|
||||
let sp = ids(&run(&mut s, "DrawCVMSpline5D", json!({"points": [[0, 0], [4, 10], [10, 12], [16, 12], [22, 10], [26, 0]]}))["curves"])[0].clone();
|
||||
run(&mut s, "DrawPolyline", json!({"points": [format!("{sp}.end"), format!("{sp}.start")]}));
|
||||
let a = profiles(&s)[0];
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "Extrude", json!({"distance": 3}));
|
||||
let v = vol(&mut s);
|
||||
assert!((v - a * 3.0).abs() / (a * 3.0) < 2e-4, "{v} vs {}", a * 3.0);
|
||||
let m = run(&mut s, "MeasureCommand", json!({}));
|
||||
assert_eq!(m["bodies"][0]["faces"], 4, "{m}");
|
||||
// A fit spline arch cut by a line: both sides extrude with exact curved faces.
|
||||
let mut s = new_sketch();
|
||||
let sp = ids(&run(&mut s, "DrawSpline", json!({"points": [[0, 0], [6, 9], [14, 9], [20, 0]]}))["curves"])[0].clone();
|
||||
run(&mut s, "DrawPolyline", json!({"points": [format!("{sp}.end"), format!("{sp}.start")]}));
|
||||
run(&mut s, "DrawPolyline", json!({"points": [[10, -5], [10, 20]]}));
|
||||
let areas = profiles(&s);
|
||||
assert_eq!(areas.len(), 2, "{areas:?}");
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "Extrude", json!({"distance": 2, "profiles": [0]}));
|
||||
let v = vol(&mut s);
|
||||
assert!((v - areas[0] * 2.0).abs() / (areas[0] * 2.0) < 2e-4, "{v} vs {}", areas[0] * 2.0);
|
||||
let m = run(&mut s, "MeasureCommand", json!({}));
|
||||
assert!(m["bodies"][0]["faces"].as_u64().unwrap() <= 7, "no polyline facets: {m}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trim_and_break_free_form_curves_exactly() {
|
||||
let pi = std::f64::consts::PI;
|
||||
|
||||
Reference in new issue
Block a user