//! Delete Face: a fillet, a hole and a chamfer taken off, healed from the neighbouring planes. use serde_json::{Value, json}; use crate::Session; fn run(s: &mut Session, id: &str, p: Value) -> Value { match s.execute(id, &p) { Ok(v) => v, Err(e) => panic!("{id} {p}: {e}"), } } fn volume(s: &mut Session, b: &str) -> f64 { run(s, "inspect.measure", json!({ "bodies": [b] }))["bodies"][0]["volume_mm3"].as_f64().unwrap_or(0.0) } #[test] fn delete_a_fillet_face() { let mut s = Session::default(); run(&mut s, "solid.box", json!({"length": 40, "width": 30, "height": 20, "body_name": "B"})); run(&mut s, "solid.fillet", json!({"edges": [[40, 15, 20]], "radius": 5})); assert!(volume(&mut s, "B") < 24000.0 - 1.0); // A point on the fillet's surface: 45° round from its axis (35, ·, 15). let h = 5.0 * std::f64::consts::FRAC_1_SQRT_2; let r = run(&mut s, "face.delete", json!({"faces": [[35.0 + h, 15, 15.0 + h]]})); assert!(r["feature"].is_u64(), "{r}"); assert!((volume(&mut s, "B") - 24000.0).abs() < 1e-3 * 24000.0, "{}", volume(&mut s, "B")); // Undo-able as a timeline feature, and named after its kind. let f = s.doc.features.last().unwrap(); assert_eq!(f.kind.type_name(), "DeleteFaceFeature"); } /// A through hole picked in the Delete selection: both halves of its wall go, and the plate /// closes up. #[test] fn delete_a_hole_through_the_selection() { let mut s = Session::default(); run(&mut s, "solid.box", json!({"length": 50, "width": 30, "height": 10, "body_name": "Plate"})); run(&mut s, "solid.cylinder", json!({"base": [25, 15, -1], "radius": 4, "height": 12, "body_name": "Drill"})); run(&mut s, "solid.combine", json!({"target": "Plate", "tools": ["Drill"], "operation": "cut"})); let v = volume(&mut s, "Plate"); assert!(v < 15000.0 - 100.0, "{v}"); run(&mut s, "selection.delete", json!({"items": [{"type": "face", "body": "Plate", "index": 0, "point": [29, 15, 5]}]})); assert!((volume(&mut s, "Plate") - 15000.0).abs() < 1e-3 * 15000.0, "{}", volume(&mut s, "Plate")); } /// A face whose neighbours can't close the gap is refused, and the design is unchanged. #[test] fn a_box_face_cannot_be_deleted() { let mut s = Session::default(); run(&mut s, "solid.box", json!({"length": 10, "width": 10, "height": 10, "body_name": "B"})); let n = s.doc.features.len(); let e = s.execute("face.delete", &json!({"faces": [[5, 5, 10]]})).unwrap_err().to_string(); assert!(e.contains("Delete Face"), "{e}"); assert_eq!(s.doc.features.len(), n); }