Thanks @DuBearte.
This commit is contained in:
1 parent
dc6eca6830
commit
6f270f6259
12 files changed
+145
-11
No files matched your search
@@ -105,7 +105,7 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
CommandSpec::new("solid.split_body", "Split Body", split_body)
|
||||
.at("SOLID", "MODIFY")
|
||||
.icon("split")
|
||||
.params("body: name; plane: XY|XZ|YZ|plane name|{origin, normal} — or tool: {body, point} (a face of a body, its surface extended)"),
|
||||
.params("body: name; plane: XY|XZ|YZ|plane name|{origin, normal} — or tool: {body, point} (a face of a body, its surface extended) — or sketch: id, line: curve id (a straight sketch line, along the sketch's normal)"),
|
||||
CommandSpec::new("solid.press_pull", "Press Pull", press_pull)
|
||||
.at("SOLID", "MODIFY")
|
||||
.icon("presspull")
|
||||
@@ -1472,6 +1472,27 @@ fn split_body(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if s.model.state().body(&body).is_none() {
|
||||
return Err(bad(cmd, format!("no body `{body}`")));
|
||||
}
|
||||
// A straight sketch line as the tool: `sketch` and `line` (#1552).
|
||||
if p.get("sketch").is_some_and(|v| !v.is_null()) || p.get("line").is_some_and(|v| !v.is_null()) {
|
||||
let sketch = p.get("sketch").and_then(Value::as_u64).ok_or_else(|| bad(cmd, "`sketch` must be a sketch feature id"))?;
|
||||
let line = str_(p, "line").ok_or_else(|| bad(cmd, "`line` must name a line of the sketch"))?.to_string();
|
||||
let st = s.model.state();
|
||||
if st.sketch(sketch).is_none() {
|
||||
return Err(bad(cmd, format!("no sketch {sketch}")));
|
||||
}
|
||||
solidcraft_doc::sketch_line_plane(&st, sketch, &line).map_err(|e| bad(cmd, e.to_string()))?;
|
||||
return add_feature(
|
||||
s,
|
||||
p,
|
||||
FeatureKind::Split {
|
||||
body: BodyName(body),
|
||||
plane: solidcraft_doc::PlaneRef::Origin { name: "XY".into() },
|
||||
tool: None,
|
||||
sketch: Some(solidcraft_doc::SketchId(sketch)),
|
||||
line: Some(line),
|
||||
},
|
||||
);
|
||||
}
|
||||
// A face as the tool: `tool: {body, point}` (its surface extended); else a plane.
|
||||
if let Some(t) = p.get("tool").filter(|t| !t.is_null()) {
|
||||
let tb = t.get("body").and_then(Value::as_str).ok_or_else(|| bad(cmd, "`tool.body` must name a body"))?.to_string();
|
||||
@@ -1488,11 +1509,13 @@ fn split_body(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
body: BodyName(body),
|
||||
plane: solidcraft_doc::PlaneRef::Origin { name: "XY".into() },
|
||||
tool: Some(solidcraft_doc::FaceAt { body: BodyName(tb), point: Position(point) }),
|
||||
sketch: None,
|
||||
line: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
let plane = plane_param(s, p.get("plane"), cmd)?;
|
||||
add_feature(s, p, FeatureKind::Split { body: BodyName(body), plane, tool: None })
|
||||
add_feature(s, p, FeatureKind::Split { body: BodyName(body), plane, tool: None, sketch: None, line: None })
|
||||
}
|
||||
|
||||
/// ISO 273 clearance hole diameters (close, normal, loose fit) for metric bolts.
|
||||
|
||||
@@ -1804,6 +1804,47 @@ fn split_body_by_a_face() {
|
||||
assert!(s.execute("solid.split_body", &json!({"body": "Block", "tool": {"body": "Tool", "point": [100, 0, 0]}})).is_err());
|
||||
}
|
||||
|
||||
/// Split Body by a sketch line (#1552): the plane through the line along the sketch's normal
|
||||
/// splits a box; the split follows the line when the sketch changes, the design saves the line,
|
||||
/// and anything but a straight line of a sketch is refused.
|
||||
#[test]
|
||||
fn split_body_by_a_sketch_line() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "solid.box", json!({"length": 10, "width": 20, "height": 30, "body_name": "Block"}));
|
||||
let sk = run(&mut s, "sketch.create", json!({"plane": "XY"}))["sketch"].as_u64().unwrap();
|
||||
run(&mut s, "sketch.line", json!({"points": [[4, -5], [4, 25]], "ids": ["cut"]}));
|
||||
run(&mut s, "sketch.circle.center", json!({"center": [50, 50], "radius": 2, "id": "c"}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let volumes = |s: &Session| {
|
||||
let st = s.world_state();
|
||||
let mut v: Vec<f64> =
|
||||
st.bodies.iter().filter(|b| b.name.starts_with("Block")).map(|b| solidcraft_kernel::measure(&b.body).unwrap().volume).collect();
|
||||
v.sort_by(f64::total_cmp);
|
||||
v
|
||||
};
|
||||
for bad in [
|
||||
json!({"body": "Block", "sketch": sk, "line": "c"}),
|
||||
json!({"body": "Block", "sketch": sk}),
|
||||
json!({"body": "Block", "sketch": 999, "line": "cut"}),
|
||||
] {
|
||||
assert!(s.execute("solid.split_body", &bad).is_err(), "{bad}");
|
||||
}
|
||||
run(&mut s, "solid.split_body", json!({"body": "Block", "sketch": sk, "line": "cut"}));
|
||||
let v = volumes(&s);
|
||||
assert!(v.len() == 2 && rel(v[0], 2400.0) < 1e-6 && rel(v[1], 3600.0) < 1e-6, "{v:?}");
|
||||
// The split follows the line.
|
||||
run(&mut s, "sketch.edit", json!({"sketch": sk}));
|
||||
run(&mut s, "sketch.move_point", json!({"point": "cut.start", "to": [2, -5]}));
|
||||
run(&mut s, "sketch.move_point", json!({"point": "cut.end", "to": [2, 25]}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let v = volumes(&s);
|
||||
assert!(v.len() == 2 && rel(v[0], 1200.0) < 1e-6 && rel(v[1], 4800.0) < 1e-6, "{v:?}");
|
||||
// The design keeps the sketch and the line.
|
||||
let saved: Value = serde_json::from_str(&s.doc.to_json()).unwrap();
|
||||
let split = saved["features"].as_array().and_then(|f| f.iter().find(|f| f["type"] == "split")).cloned().unwrap();
|
||||
assert_eq!((split["sketch"].as_u64(), split["line"].as_str()), (Some(sk), Some("cut")), "{split}");
|
||||
}
|
||||
|
||||
/// Fillet types: chord length (radius from the face angle) and a radius varying along the
|
||||
/// edge; volumes from the removed material.
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user