Command ids are SolveCraft's own: 173 ids that were another product's internal command ids become dotted, lower-case ids (<area>.<thing>[.<variant>]: solid.extrude, sketch.rectangle.two_point, sheet.flange, joint.drive, ...), in the registry, toolbar, dialogs, shortcuts, palette, control channel, MCP, examples, scenarios and docs
The old ids live only in crates/engine/src/legacy_ids.rs (the legacy migration table): find_command maps them, so old scripts, recipes and control calls keep working, and saved shortcuts, recent and pinned commands are migrated on load (designs store no command ids). Parity maps the observed catalog ids to ours through xtask/data/fusion-ids.tsv. The agent rule now reads: our own dotted id, never another product's. Cargo.toml's repository points at github.com/bherbruck/solvecraft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
740360d7c3
commit
d10312b7fd
158 files changed
+3611
-3205
No files matched your search
@@ -15,20 +15,20 @@ fn ids(v: &Value) -> Vec<String> {
|
||||
|
||||
/// A 40 x 30 x 20 box from a sketch whose width is the user parameter `width`.
|
||||
fn box_part(s: &mut Session) {
|
||||
run(s, "ChangeParameterCommand", json!({"name": "width", "expression": "40 mm"}));
|
||||
run(s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(s, "ShapeRectangleTwoPoint", json!({"p0": [0, 0], "p1": [40, 30]}));
|
||||
run(s, "parameters.change", json!({"name": "width", "expression": "40 mm"}));
|
||||
run(s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(s, "sketch.rectangle.two_point", json!({"p0": [0, 0], "p1": [40, 30]}));
|
||||
let l = ids(&r["curves"]);
|
||||
let sk = s.doc.sketch(s.active_sketch.unwrap()).unwrap();
|
||||
let start = match sk.curves[0].kind {
|
||||
solvecraft_sketch::CurveKind::Line { a, .. } => sk.points[a].id.clone(),
|
||||
_ => panic!(),
|
||||
};
|
||||
run(s, "ConstraintCoincident", json!({"a": start, "b": "origin"}));
|
||||
run(s, "SketchDimension", json!({"entities": [l[0]], "value": "width"}));
|
||||
run(s, "SketchDimension", json!({"entities": [l[1]], "value": 30}));
|
||||
run(s, "SketchStop", json!({}));
|
||||
run(s, "Extrude", json!({"distance": 20}));
|
||||
run(s, "sketch.constraint.coincident", json!({"a": start, "b": "origin"}));
|
||||
run(s, "sketch.dimension", json!({"entities": [l[0]], "value": "width"}));
|
||||
run(s, "sketch.dimension", json!({"entities": [l[1]], "value": 30}));
|
||||
run(s, "sketch.finish", json!({}));
|
||||
run(s, "solid.extrude", json!({"distance": 20}));
|
||||
}
|
||||
|
||||
fn inspect(s: &mut Session) -> Value {
|
||||
@@ -43,7 +43,7 @@ fn linked_curves(si: &Value) -> Vec<Value> {
|
||||
fn sketch_on_face_projects_its_edges_and_follows_edits() {
|
||||
let mut s = Session::default();
|
||||
box_part(&mut s);
|
||||
let r = run(&mut s, "SketchCreate", json!({"plane": {"face": [20, 15, 20]}}));
|
||||
let r = run(&mut s, "sketch.create", json!({"plane": {"face": [20, 15, 20]}}));
|
||||
assert!(r["projected"].is_string(), "{r}");
|
||||
let si = inspect(&mut s);
|
||||
let lc = linked_curves(&si);
|
||||
@@ -55,16 +55,16 @@ fn sketch_on_face_projects_its_edges_and_follows_edits() {
|
||||
// Projected geometry is fixed: the sketch has no degrees of freedom.
|
||||
assert_eq!(si["dof"], 0, "{si}");
|
||||
// A circle on the face, dimensioned to a projected edge.
|
||||
let c = run(&mut s, "CircleCenterRadius", json!({"center": [10, 10], "radius": 3}));
|
||||
let c = run(&mut s, "sketch.circle.center", json!({"center": [10, 10], "radius": 3}));
|
||||
let cid = ids(&c["curves"])[0].clone();
|
||||
let e = lc.iter().find(|c| c["start_at"][1].as_f64().unwrap().abs() < 1e-9 && c["end_at"][1].as_f64().unwrap().abs() < 1e-9).unwrap();
|
||||
run(&mut s, "SketchDimension", json!({"entities": [format!("{cid}.center"), e["id"]], "value": 8}));
|
||||
run(&mut s, "sketch.dimension", json!({"entities": [format!("{cid}.center"), e["id"]], "value": 8}));
|
||||
let si = inspect(&mut s);
|
||||
let center = si["points"].as_array().unwrap().iter().find(|p| p["id"] == format!("{cid}.center")).unwrap();
|
||||
assert!((center["at"][1].as_f64().unwrap() - 8.0).abs() < 1e-7, "{center}");
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
// Widen the box: the projected loop follows.
|
||||
run(&mut s, "ChangeParameterCommand", json!({"name": "width", "expression": "50 mm"}));
|
||||
run(&mut s, "parameters.change", json!({"name": "width", "expression": "50 mm"}));
|
||||
let st = s.model.state();
|
||||
let ss = st.sketches.last().unwrap();
|
||||
assert_eq!(ss.profiles.len(), 2);
|
||||
@@ -78,11 +78,11 @@ fn sketch_on_face_projects_its_edges_and_follows_edits() {
|
||||
fn auto_project_can_be_turned_off() {
|
||||
let mut s = Session::default();
|
||||
box_part(&mut s);
|
||||
let r = run(&mut s, "SketchCreate", json!({"plane": {"face": [20, 15, 20]}, "project_edges": false}));
|
||||
let r = run(&mut s, "sketch.create", json!({"plane": {"face": [20, 15, 20]}, "project_edges": false}));
|
||||
assert!(r["projected"].is_null());
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "sketch.auto_project", json!({"value": false}));
|
||||
let r = run(&mut s, "SketchCreate", json!({"plane": {"face": [20, 15, 20]}}));
|
||||
let r = run(&mut s, "sketch.create", json!({"plane": {"face": [20, 15, 20]}}));
|
||||
assert!(r["projected"].is_null());
|
||||
}
|
||||
|
||||
@@ -90,10 +90,10 @@ fn auto_project_can_be_turned_off() {
|
||||
fn project_edges_bodies_sketches_and_origin() {
|
||||
let mut s = Session::default();
|
||||
box_part(&mut s);
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [80, 0, 5], "radius": 6, "height": 10}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [80, 0, 5], "radius": 6, "height": 10}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
// An edge on the top face projects to a line on XY.
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"edge": [20, 30, 20]}]}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"edge": [20, 30, 20]}]}));
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == r["links"][0]["curves"][0]).unwrap().clone();
|
||||
assert_eq!(c["type"], "line");
|
||||
@@ -101,7 +101,7 @@ fn project_edges_bodies_sketches_and_origin() {
|
||||
assert!(ys.iter().all(|y| (y - 30.0).abs() < 1e-9), "{c}");
|
||||
// The cylinder's silhouette seen from above is its circle, exactly.
|
||||
let name = s.model.state().bodies[1].name.clone();
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"body": name}]}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"body": name}]}));
|
||||
let cid = r["links"][0]["curves"][0].clone();
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == cid).unwrap().clone();
|
||||
@@ -109,34 +109,34 @@ fn project_edges_bodies_sketches_and_origin() {
|
||||
assert!((c["radius"].as_f64().unwrap() - 6.0).abs() < 1e-6, "{c}");
|
||||
assert!((c["center_at"][0].as_f64().unwrap() - 80.0).abs() < 1e-6, "{c}");
|
||||
// Origin, the Y axis and the YZ plane.
|
||||
run(&mut s, "ProjectNewCmd", json!({"refs": ["origin", {"axis": "Y"}, {"plane": "YZ"}]}));
|
||||
run(&mut s, "sketch.project", json!({"refs": ["origin", {"axis": "Y"}, {"plane": "YZ"}]}));
|
||||
// The box silhouette from above is its 40 x 30 outline.
|
||||
let b0 = s.model.state().bodies[0].name.clone();
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"body": b0}]}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"body": b0}]}));
|
||||
assert_eq!(r["links"][0]["curves"].as_array().unwrap().len(), 4, "{r}");
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let first = s.active_sketch;
|
||||
assert!(first.is_none());
|
||||
let sk1 = s.doc.features.last().unwrap().id;
|
||||
// Another sketch projects a curve of the first one.
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": 50}));
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"sketch": sk1, "curve": cid}]}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": 50}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"sketch": sk1, "curve": cid}]}));
|
||||
let c2 = r["links"][0]["curves"][0].clone();
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == c2).unwrap().clone();
|
||||
assert_eq!(c["type"], "circle");
|
||||
// Bad references fail cleanly.
|
||||
assert!(s.execute("ProjectNewCmd", &json!({"refs": [{"edge": [1000, 1000, 1000]}]})).is_err());
|
||||
assert!(s.execute("ProjectNewCmd", &json!({"refs": [{"plane": "XY"}]})).is_err(), "parallel plane projects to nothing");
|
||||
assert!(s.execute("sketch.project", &json!({"refs": [{"edge": [1000, 1000, 1000]}]})).is_err());
|
||||
assert!(s.execute("sketch.project", &json!({"refs": [{"plane": "XY"}]})).is_err(), "parallel plane projects to nothing");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intersect_cuts_a_body_with_the_sketch_plane() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [0, 0, 0], "radius": 7, "height": 30}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": 12}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [0, 0, 0], "radius": 7, "height": 30}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": 12}));
|
||||
let name = s.model.state().bodies[0].name.clone();
|
||||
let r = run(&mut s, "IntersectCmd", json!({"refs": [{"body": name}]}));
|
||||
let r = run(&mut s, "sketch.intersect", json!({"refs": [{"body": name}]}));
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == r["links"][0]["curves"][0]).unwrap().clone();
|
||||
assert_eq!(c["type"], "circle", "{c}");
|
||||
@@ -148,7 +148,7 @@ fn intersect_cuts_a_body_with_the_sketch_plane() {
|
||||
fn break_link_makes_normal_geometry() {
|
||||
let mut s = Session::default();
|
||||
box_part(&mut s);
|
||||
let r = run(&mut s, "SketchCreate", json!({"plane": {"face": [20, 15, 20]}}));
|
||||
let r = run(&mut s, "sketch.create", json!({"plane": {"face": [20, 15, 20]}}));
|
||||
let link = r["projected"].as_str().unwrap().to_string();
|
||||
run(&mut s, "sketch.break_link", json!({"link": link}));
|
||||
let si = inspect(&mut s);
|
||||
@@ -162,11 +162,11 @@ fn break_link_makes_normal_geometry() {
|
||||
#[test]
|
||||
fn lost_reference_keeps_geometry_with_a_warning() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveBox", json!({"length": 10, "width": 10, "height": 10}));
|
||||
run(&mut s, "solid.box", json!({"length": 10, "width": 10, "height": 10}));
|
||||
let boxf = s.doc.features.last().unwrap().id;
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
run(&mut s, "ProjectNewCmd", json!({"refs": [{"edge": [5, 0, 10]}]}));
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
run(&mut s, "sketch.project", json!({"refs": [{"edge": [5, 0, 10]}]}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "timeline.suppress", json!({"feature": boxf, "suppressed": true}));
|
||||
let st = s.model.state();
|
||||
let ss = st.sketches.last().unwrap();
|
||||
@@ -180,8 +180,8 @@ fn lost_reference_keeps_geometry_with_a_warning() {
|
||||
fn drawing_on_a_model_vertex_projects_it() {
|
||||
let mut s = Session::default();
|
||||
box_part(&mut s);
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "DrawPolyline", json!({"points": ["vertex:40,30,20", [60, 45]]}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "sketch.line", json!({"points": ["vertex:40,30,20", [60, 45]]}));
|
||||
let l = ids(&r["curves"])[0].clone();
|
||||
let si = inspect(&mut s);
|
||||
let start = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == l).unwrap()["start"].clone();
|
||||
@@ -190,7 +190,7 @@ fn drawing_on_a_model_vertex_projects_it() {
|
||||
assert_eq!(p["fixed"], true);
|
||||
assert!((p["at"][0].as_f64().unwrap() - 40.0).abs() < 1e-9);
|
||||
// Snapping onto an edge projects it and keeps the point on it.
|
||||
let r = run(&mut s, "DrawPolyline", json!({"points": [{"on_edge": [20, 0, 20]}, [20, -15]]}));
|
||||
let r = run(&mut s, "sketch.line", json!({"points": [{"on_edge": [20, 0, 20]}, [20, -15]]}));
|
||||
assert_eq!(ids(&r["curves"]).len(), 1);
|
||||
let si = inspect(&mut s);
|
||||
assert!(si["constraints"].as_array().unwrap().iter().any(|c| c["type"] == "point_on_curve"), "{si}");
|
||||
@@ -199,41 +199,41 @@ fn drawing_on_a_model_vertex_projects_it() {
|
||||
#[test]
|
||||
fn fit_curves_to_a_mesh_section() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [0, 0, 0], "radius": 7, "height": 30}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": 10}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [0, 0, 0], "radius": 7, "height": 30}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": 10}));
|
||||
let name = s.model.state().bodies[0].name.clone();
|
||||
let r = run(&mut s, "FitCurvesToSectionCommand", json!({"body": name}));
|
||||
let r = run(&mut s, "sketch.fit_curves_to_section", json!({"body": name}));
|
||||
assert_eq!(r["curves"].as_array().unwrap().len(), 1, "{r}");
|
||||
let si = inspect(&mut s);
|
||||
assert!(si["links"].as_array().unwrap().is_empty());
|
||||
let c = &si["curves"][0];
|
||||
assert_eq!(c["type"], "circle");
|
||||
assert!(c.get("link").is_none());
|
||||
assert!(s.execute("FitCurvesToSectionCommand", &json!({"body": "nope"})).is_err());
|
||||
assert!(s.execute("sketch.fit_curves_to_section", &json!({"body": "nope"})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn three_d_sketch_curves() {
|
||||
let mut s = Session::default();
|
||||
// Include keeps an out-of-plane edge 3D.
|
||||
run(&mut s, "PrimitiveBox", json!({"length": 10, "width": 10, "height": 10}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "Include3DGeometry", json!({"refs": [{"edge": [10, 10, 5]}]}));
|
||||
run(&mut s, "solid.box", json!({"length": 10, "width": 10, "height": 10}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "sketch.include_3d", json!({"refs": [{"edge": [10, 10, 5]}]}));
|
||||
let st = s.model.state();
|
||||
let sk = &st.sketch(s.active_sketch.unwrap()).unwrap().sketch;
|
||||
assert_eq!(sk.wires.len(), 1, "{r}");
|
||||
assert!((sk.wires[0].pts.iter().map(|p| p.z).fold(0.0, f64::max) - 10.0).abs() < 1e-9);
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
|
||||
// Project a line onto a sphere along the sketch normal.
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveSphere", json!({"center": [0, 0, 0], "radius": 20}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": 50}));
|
||||
let l = ids(&run(&mut s, "DrawPolyline", json!({"points": [[-10, 0], [10, 0]]}))["curves"])[0].clone();
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "solid.sphere", json!({"center": [0, 0, 0], "radius": 20}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": 50}));
|
||||
let l = ids(&run(&mut s, "sketch.line", json!({"points": [[-10, 0], [10, 0]]}))["curves"])[0].clone();
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let src = s.doc.features.last().unwrap().id;
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "ProjectToSurface", json!({"curves": [{"sketch": src, "curve": l}], "face": [0, 0, 20]}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "sketch.project_to_surface", json!({"curves": [{"sketch": src, "curve": l}], "face": [0, 0, 20]}));
|
||||
let wid = r["links"][0]["wires"][0].as_str().unwrap().to_string();
|
||||
let st = s.model.state();
|
||||
let sk = &st.sketch(s.active_sketch.unwrap()).unwrap().sketch;
|
||||
@@ -246,16 +246,16 @@ fn three_d_sketch_curves() {
|
||||
// Delete the wire.
|
||||
run(&mut s, "sketch.delete", json!({"entities": [wid]}));
|
||||
assert!(s.model.state().sketch(s.active_sketch.unwrap()).unwrap().sketch.wires.is_empty());
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
|
||||
// Two crossing cylinders meet in 3D curves.
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [0, 0, -20], "radius": 5, "height": 40}));
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [-20, 0, 0], "axis": [1, 0, 0], "radius": 4, "height": 40, "operation": "new"}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [0, 0, -20], "radius": 5, "height": 40}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [-20, 0, 0], "axis": [1, 0, 0], "radius": 4, "height": 40, "operation": "new"}));
|
||||
let names: Vec<String> = s.model.state().bodies.iter().map(|b| b.name.clone()).collect();
|
||||
assert_eq!(names.len(), 2, "{names:?}");
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "IntersectionCurve", json!({"a": {"body": names[0]}, "b": {"body": names[1]}}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "sketch.intersection_curve", json!({"a": {"body": names[0]}, "b": {"body": names[1]}}));
|
||||
assert!(!r["wires"].as_array().unwrap().is_empty(), "{r}");
|
||||
let st = s.model.state();
|
||||
let sk = &st.sketch(s.active_sketch.unwrap()).unwrap().sketch;
|
||||
@@ -265,14 +265,14 @@ fn three_d_sketch_curves() {
|
||||
assert!(((p.y * p.y + p.z * p.z).sqrt() - 4.0).abs() < 0.1, "{p:?}");
|
||||
}
|
||||
}
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
|
||||
// Spun profile of a cylinder about Z, on the XZ plane: a straight outline 6 from the axis.
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [0, 0, 0], "radius": 6, "height": 20}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [0, 0, 0], "radius": 6, "height": 20}));
|
||||
let name = s.model.state().bodies[0].name.clone();
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XZ"}));
|
||||
let r = run(&mut s, "SpunProfileCmd", json!({"body": name, "axis": "Z"}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XZ"}));
|
||||
let r = run(&mut s, "sketch.spun_profile", json!({"body": name, "axis": "Z"}));
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == r["curves"][0]).unwrap().clone();
|
||||
assert_eq!(c["type"], "line", "{c}");
|
||||
@@ -282,15 +282,15 @@ fn three_d_sketch_curves() {
|
||||
#[test]
|
||||
fn isoparametric_curves_of_a_cylinder() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [0, 0, 0], "radius": 6, "height": 20}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [0, 0, 0], "radius": 6, "height": 20}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
// u: around (a circle at z = 10); v: along (a line from z 0 to 20).
|
||||
let r = run(&mut s, "SketchIsoparametricCurve", json!({"face": [6, 0, 10]}));
|
||||
let r = run(&mut s, "sketch.isoparametric_curve", json!({"face": [6, 0, 10]}));
|
||||
let st = s.model.state();
|
||||
let sk = &st.sketch(s.active_sketch.unwrap()).unwrap().sketch;
|
||||
let w = &sk.wires[sk.wire_index(r["wires"][0].as_str().unwrap()).unwrap()];
|
||||
assert!(w.pts.iter().all(|p| (p.z - 10.0).abs() < 1e-6 && ((p.x * p.x + p.y * p.y).sqrt() - 6.0).abs() < 1e-3), "{:?}", &w.pts[..3]);
|
||||
let r = run(&mut s, "SketchIsoparametricCurve", json!({"face": [6, 0, 10], "direction": "v"}));
|
||||
let r = run(&mut s, "sketch.isoparametric_curve", json!({"face": [6, 0, 10], "direction": "v"}));
|
||||
let st = s.model.state();
|
||||
let sk = &st.sketch(s.active_sketch.unwrap()).unwrap().sketch;
|
||||
let w = &sk.wires[sk.wire_index(r["wires"][0].as_str().unwrap()).unwrap()];
|
||||
@@ -302,10 +302,10 @@ fn isoparametric_curves_of_a_cylinder() {
|
||||
#[test]
|
||||
fn tilted_circles_project_to_exact_ellipses_and_splines_stay_splines() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveCylinder", json!({"base": [0, 0, 0], "axis": [1, 0, 1], "radius": 5, "height": 20}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": -10}));
|
||||
run(&mut s, "solid.cylinder", json!({"base": [0, 0, 0], "axis": [1, 0, 1], "radius": 5, "height": 20}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": -10}));
|
||||
// The base circle (centred at the origin) seen from above.
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"edge": [0, 5, 0]}]}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"edge": [0, 5, 0]}]}));
|
||||
// One seam half: exact conics (rational quadratic arcs).
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == r["links"][0]["curves"][0]).unwrap().clone();
|
||||
@@ -320,7 +320,7 @@ fn tilted_circles_project_to_exact_ellipses_and_splines_stay_splines() {
|
||||
}
|
||||
}
|
||||
// The whole face (both halves of its rim, plus its seam) gives the full ellipse.
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"face": [0, 0, 0]}]}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"face": [0, 0, 0]}]}));
|
||||
let si = inspect(&mut s);
|
||||
let types: Vec<String> = r["links"][0]["curves"]
|
||||
.as_array()
|
||||
@@ -329,7 +329,7 @@ fn tilted_circles_project_to_exact_ellipses_and_splines_stay_splines() {
|
||||
.map(|id| si["curves"].as_array().unwrap().iter().find(|c| c["id"] == *id).unwrap()["type"].as_str().unwrap().to_string())
|
||||
.collect();
|
||||
assert!(types.iter().all(|t| t == "conic" || t == "ellipse"), "{types:?}");
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"edge": [0, -5, 0]}]}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"edge": [0, -5, 0]}]}));
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == r["links"][0]["curves"][0]).unwrap().clone();
|
||||
if c["type"] == "ellipse" {
|
||||
@@ -337,14 +337,14 @@ fn tilted_circles_project_to_exact_ellipses_and_splines_stay_splines() {
|
||||
let major = &c["major_at"];
|
||||
assert!(((major[0].as_f64().unwrap().powi(2) + major[1].as_f64().unwrap().powi(2)).sqrt() - 5.0).abs() < 1e-6, "{c}");
|
||||
}
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
// A spline of a parallel sketch projects as the same spline.
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": 30}));
|
||||
let sp = run(&mut s, "DrawSpline", json!({"points": [[0, 0], [10, 5], [20, 0]]}))["curves"][0].clone();
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": 30}));
|
||||
let sp = run(&mut s, "sketch.spline.fit_point", json!({"points": [[0, 0], [10, 5], [20, 0]]}))["curves"][0].clone();
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let sk1 = s.doc.features.last().unwrap().id;
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "ProjectNewCmd", json!({"refs": [{"sketch": sk1, "curve": sp}]}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "sketch.project", json!({"refs": [{"sketch": sk1, "curve": sp}]}));
|
||||
let si = inspect(&mut s);
|
||||
let c = si["curves"].as_array().unwrap().iter().find(|c| c["id"] == r["links"][0]["curves"][0]).unwrap().clone();
|
||||
assert_eq!(c["type"], "spline", "{c}");
|
||||
@@ -355,13 +355,13 @@ fn tilted_circles_project_to_exact_ellipses_and_splines_stay_splines() {
|
||||
fn sweeps_and_pipes_follow_3d_sketch_curves() {
|
||||
// A line projected onto a sphere: a 3D arc on its top.
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveSphere", json!({"center": [0, 0, 0], "radius": 20}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY", "offset": 50}));
|
||||
let l = ids(&run(&mut s, "DrawPolyline", json!({"points": [[-12, 0], [12, 0]]}))["curves"])[0].clone();
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "solid.sphere", json!({"center": [0, 0, 0], "radius": 20}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": 50}));
|
||||
let l = ids(&run(&mut s, "sketch.line", json!({"points": [[-12, 0], [12, 0]]}))["curves"])[0].clone();
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let src = s.doc.features.last().unwrap().id;
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "ProjectToSurface", json!({"curves": [{"sketch": src, "curve": l}], "face": [0, 0, 20]}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY"}));
|
||||
let r = run(&mut s, "sketch.project_to_surface", json!({"curves": [{"sketch": src, "curve": l}], "face": [0, 0, 20]}));
|
||||
let wid = r["links"][0]["wires"][0].as_str().unwrap().to_string();
|
||||
let path_sketch = s.active_sketch.unwrap();
|
||||
let pts = {
|
||||
@@ -369,11 +369,11 @@ fn sweeps_and_pipes_follow_3d_sketch_curves() {
|
||||
let sk = &st.sketch(path_sketch).unwrap().sketch;
|
||||
sk.wires[sk.wire_index(&wid).unwrap()].pts.clone()
|
||||
};
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
let len: f64 = pts.windows(2).map(|w| w[0].dist(w[1])).sum();
|
||||
// A pipe along it: volume ≈ π r² × length.
|
||||
let before = s.model.state().bodies.len();
|
||||
run(&mut s, "PrimitivePipe", json!({"path_sketch": path_sketch, "path": [wid.clone()], "diameter": "2 mm", "operation": "new"}));
|
||||
run(&mut s, "solid.pipe", json!({"path_sketch": path_sketch, "path": [wid.clone()], "diameter": "2 mm", "operation": "new"}));
|
||||
let st = s.model.state();
|
||||
assert_eq!(st.bodies.len(), before + 1);
|
||||
let v = st.bodies.last().unwrap().mesh().measure().volume;
|
||||
@@ -385,11 +385,11 @@ fn sweeps_and_pipes_follow_3d_sketch_curves() {
|
||||
let t = (b - a).normalized().unwrap();
|
||||
let x = t.cross(solvecraft_geom::Vec3::Z).normalized().unwrap();
|
||||
let y = t.cross(x);
|
||||
run(&mut s, "SketchCreate", json!({"plane": {"origin": [a.x, a.y, a.z], "x_dir": [x.x, x.y, x.z], "y_dir": [y.x, y.y, y.z]}}));
|
||||
run(&mut s, "ShapeRectangleTwoPoint", json!({"p0": [-1, -1], "p1": [1, 1]}));
|
||||
run(&mut s, "sketch.create", json!({"plane": {"origin": [a.x, a.y, a.z], "x_dir": [x.x, x.y, x.z], "y_dir": [y.x, y.y, y.z]}}));
|
||||
run(&mut s, "sketch.rectangle.two_point", json!({"p0": [-1, -1], "p1": [1, 1]}));
|
||||
let prof = s.active_sketch.unwrap();
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "Sweep", json!({"sketch": prof, "path_sketch": path_sketch, "path": [wid], "operation": "new"}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.sweep", json!({"sketch": prof, "path_sketch": path_sketch, "path": [wid], "operation": "new"}));
|
||||
let st = s.model.state();
|
||||
assert_eq!(st.bodies.len(), before + 2);
|
||||
let v = st.bodies.last().unwrap().mesh().measure().volume;
|
||||
|
||||
Reference in new issue
Block a user