Fix construction-plane references in mirror, section, and sketches (#99)
Accept construction planes by name or feature ID, preserve parametric mirror references, and reject invalid plane inputs. Retain both mirror-plane and primitive-point regression test modules after resolving the conflict with main. Validation: cargo xtask ci passed, including 282 engine tests, 138 UI tests, 62 UI scenarios, and WebAssembly.
This commit is contained in:
1 parent
1a1838c114
commit
e575bded0e
5 files changed
+109
-37
No files matched your search
@@ -0,0 +1,65 @@
|
||||
//! Commands that take a plane accept construction planes by name or id, like the origin planes
|
||||
//! (user report: `solid.mirror` refused a construction plane although its docs list plane
|
||||
//! names).
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use super::run;
|
||||
use crate::*;
|
||||
|
||||
fn min_x(s: &Session, body: &str) -> f64 {
|
||||
let b = s.model.state().body(body).map(|b| b.body.clone()).unwrap();
|
||||
solvecraft_kernel::measure(&b).unwrap().bbox.min.x
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mirror_across_a_construction_plane_follows_it() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "parameters.change", json!({"name": "w", "expression": "100 mm"}));
|
||||
let pl = run(&mut s, "construct.plane.offset", json!({"base": "YZ", "offset": "w / 2", "name": "Mid"}));
|
||||
run(&mut s, "solid.box", json!({"length": 10, "width": 10, "height": 10, "body_name": "Ledger"}));
|
||||
let before = s.model.state().bodies.len();
|
||||
// By name: the copy lands at x = 90…100.
|
||||
run(&mut s, "solid.mirror", json!({"bodies": ["Ledger"], "plane": "Mid"}));
|
||||
let st = s.model.state();
|
||||
assert_eq!(st.bodies.len(), before + 1);
|
||||
let copy = st.bodies.last().map(|b| b.name.clone()).unwrap();
|
||||
assert!((min_x(&s, ©) - 90.0).abs() < 1e-6, "{}", min_x(&s, ©));
|
||||
// Parametric: moving the plane moves the copy.
|
||||
run(&mut s, "parameters.change", json!({"name": "w", "expression": "60 mm"}));
|
||||
assert!((min_x(&s, ©) - 50.0).abs() < 1e-6, "{}", min_x(&s, ©));
|
||||
// By id, and case-insensitively by name.
|
||||
let id = pl["feature"].as_u64().unwrap();
|
||||
run(&mut s, "solid.mirror", json!({"bodies": ["Ledger"], "plane": id.to_string()}));
|
||||
run(&mut s, "solid.mirror", json!({"bodies": ["Ledger"], "plane": "mid"}));
|
||||
let st = s.model.state();
|
||||
assert_eq!(st.bodies.len(), before + 3);
|
||||
for b in st.bodies.iter().skip(before) {
|
||||
assert!((min_x(&s, &b.name) - 50.0).abs() < 1e-6, "{}", b.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_mirror_planes_are_refused_with_the_choices() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "solid.box", json!({"length": 10, "width": 10, "height": 10, "body_name": "B"}));
|
||||
let e = s.execute("solid.mirror", &json!({"bodies": ["B"], "plane": "Nope"})).unwrap_err().to_string();
|
||||
assert!(e.contains("Nope"), "{e}");
|
||||
let e = s.execute("solid.mirror", &json!({"bodies": ["B"], "plane": 5})).unwrap_err().to_string();
|
||||
assert!(e.contains("construction plane"), "{e}");
|
||||
// A plane object with an unreadable origin is refused, not put at the world origin.
|
||||
assert!(s.execute("solid.mirror", &json!({"bodies": ["B"], "plane": {"origin": ["x", 0, 0], "normal": [1, 0, 0]}})).is_err());
|
||||
// A feature that is not a plane is no plane.
|
||||
assert!(s.execute("solid.mirror", &json!({"bodies": ["B"], "plane": "Box1"})).is_err());
|
||||
assert_eq!(s.model.state().bodies.len(), 1);
|
||||
}
|
||||
|
||||
/// Section Analysis cuts along a construction plane too.
|
||||
#[test]
|
||||
fn section_by_a_construction_plane() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "construct.plane.offset", json!({"base": "XY", "offset": 7, "name": "Cut"}));
|
||||
let r = run(&mut s, "inspect.section", json!({"plane": "Cut"}));
|
||||
assert_eq!(r["section"]["origin"][2].as_f64(), Some(7.0), "{r}");
|
||||
assert!(s.execute("inspect.section", &json!({"plane": "Nope"})).is_err());
|
||||
}
|
||||
Reference in new issue
Block a user