From 5eb7fd452a00bba1cfe211017cd84e76e893d5b1 Mon Sep 17 00:00:00 2001 From: Valentin Klein Date: Sat, 10 Oct 2026 21:33:31 +0200 Subject: [PATCH] Programmatic SPLINE limits the degree to 1..10 (fixes #268) (#269) spline {control, degree} took any degree up to the control-point count minus one; tessellation and extents grow with its square, so a few thousand control points with a high degree hung the app on every redraw. The Degree prompt, spline.cv and DXF input already limit it to 1..10. Co-authored-by: Claude Opus 5.5 --- crates/engine/src/cmd/draw.rs | 4 +++- crates/engine/tests/spline_degree.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 crates/engine/tests/spline_degree.rs diff --git a/crates/engine/src/cmd/draw.rs b/crates/engine/src/cmd/draw.rs index 99a7d231..885635bf 100644 --- a/crates/engine/src/cmd/draw.rs +++ b/crates/engine/src/cmd/draw.rs @@ -245,7 +245,9 @@ fn run_spline(s: &mut Session, p: &Value) -> Result { if c.len() < 2 { return Err(bad("spline", "need 2+ control points")); } - Spline::from_control(c, p.get("degree").and_then(Value::as_u64).unwrap_or(3) as usize) + // Degree 1..=10 as at the Degree prompt, `spline.cv` and DXF input (tessellation grows + // with its square). + Spline::from_control(c, p.get("degree").and_then(Value::as_u64).unwrap_or(3).clamp(1, 10) as usize) } else { return Err(bad("spline", "`fit` or `control` points are required")); }; diff --git a/crates/engine/tests/spline_degree.rs b/crates/engine/tests/spline_degree.rs new file mode 100644 index 00000000..a525d137 --- /dev/null +++ b/crates/engine/tests/spline_degree.rs @@ -0,0 +1,20 @@ +//! Programmatic SPLINE keeps the degree within 1..=10 like the Degree prompt (issue #268): a high +//! degree on many control points made tessellation and extents take minutes. + +use cadcraft_engine::Session; +use cadcraft_engine::doc::EntityKind; +use serde_json::json; + +#[test] +fn programmatic_spline_degree_is_limited() { + let control: Vec<[f64; 2]> = (0..3000).map(|i| [f64::from(i), f64::from(i % 7)]).collect(); + for (degree, want) in [(json!(2_147_483_647), 10), (json!(2999), 10), (json!(11), 10), (json!(0), 1), (json!(4), 4)] { + let mut s = Session::new(); + s.execute("spline", &json!({ "control": control, "degree": degree })).unwrap(); + let d = s.doc().unwrap(); + let Some(EntityKind::Spline(sp)) = d.model.iter().last().map(|e| &e.kind) else { panic!("no spline") }; + assert_eq!(sp.degree, want); + let ext = d.extents(&s.space()); + assert!(ext.min.x <= 0.0 && ext.max.x >= 2999.0, "{ext:?}"); + } +}