Files
OneCAD/crates/engine/src/tests/xz_plane.rs
T
bherbruckandClaude Opus 5.5 296683229d Rename SolveCraft to SolidCraft everywhere, with compatibility shims (#389)
* WIP deep rename (not for push)

* WIP2

* WIP3

* WIP4 wxs fix

* rustfmt

* Rename the remaining identifiers in merged crash-report code

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-12 17:17:01 -04:00

98 lines
4.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! The XZ origin plane (#78): sketch x = +X, y = −Z, normal +Y, so a positive extrude from XZ
//! (or from a plane offset from it) goes +Y. Designs saved before format 6 used y = +Z and
//! normal −Y; opening one keeps its geometry exactly where it was saved.
use serde_json::{Value, json};
use super::run;
use crate::*;
/// A 10 × 5 rectangle on XZ extruded 3, and a 4 × 4 square on a plane offset 7 from XZ
/// extruded 2.
fn build(s: &mut Session) {
run(s, "sketch.create", json!({"plane": "XZ", "name": "Base"}));
run(s, "sketch.line", json!({"points": [[0, 0], [10, 0], [10, 5], [0, 5]], "closed": true}));
run(s, "sketch.finish", json!({}));
run(s, "solid.extrude", json!({"sketch": "Base", "distance": 3, "body_name": "Slab"}));
run(s, "construct.plane.offset", json!({"base": "XZ", "offset": "7 mm", "name": "Shelf"}));
run(s, "sketch.create", json!({"plane": "Shelf", "name": "Top"}));
run(s, "sketch.line", json!({"points": [[20, 1], [24, 1], [24, 5], [20, 5]], "closed": true}));
run(s, "sketch.finish", json!({}));
run(s, "solid.extrude", json!({"sketch": "Top", "distance": 2, "body_name": "Post", "operation": "new"}));
}
/// Volume and world bounding box (min, max) of each body.
fn bodies(s: &mut Session) -> Vec<(String, f64, [f64; 3], [f64; 3])> {
let m = run(s, "inspect.measure", json!({}));
let v3 = |v: &Value| -> [f64; 3] { [0, 1, 2].map(|i| v[i].as_f64().unwrap()) };
m["bodies"]
.as_array()
.unwrap()
.iter()
.map(|b| (b["name"].as_str().unwrap().to_string(), b["volume_mm3"].as_f64().unwrap(), v3(&b["bbox"]["min"]), v3(&b["bbox"]["max"])))
.collect()
}
fn close(a: [f64; 3], b: [f64; 3]) -> bool {
a.iter().zip(b).all(|(x, y)| (x - y).abs() < 1e-6)
}
fn expect(got: &[(String, f64, [f64; 3], [f64; 3])], want: &[(&str, f64, [f64; 3], [f64; 3])]) {
assert_eq!(got.len(), want.len(), "{got:?}");
for ((name, vol, min, max), (wname, wvol, wmin, wmax)) in got.iter().zip(want) {
assert_eq!(name, wname);
assert!((vol - wvol).abs() < 1e-6 * wvol, "{name}: volume {vol} vs {wvol}");
assert!(close(*min, *wmin) && close(*max, *wmax), "{name}: bbox {min:?}..{max:?}, expected {wmin:?}..{wmax:?}");
}
}
#[test]
fn positive_extrude_from_xz_goes_plus_y() {
let mut s = Session::default();
build(&mut s);
expect(
&bodies(&mut s),
&[
// Sketch y = −Z; extrude along +Y.
("Slab", 150.0, [0.0, 0.0, -5.0], [10.0, 3.0, 0.0]),
// The offset plane sits at Y = +7 and its extrude continues to +Y.
("Post", 32.0, [20.0, 7.0, -5.0], [24.0, 9.0, -1.0]),
],
);
}
#[test]
fn format_5_xz_design_opens_where_it_was_saved() {
let dir = std::env::temp_dir().join(format!("solidcraft-xz78-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("old-xz.solidcraft");
let mut s = Session::default();
build(&mut s);
run(&mut s, "file.save_as", json!({"path": path.to_string_lossy()}));
// Stamp the file as format 5: its XZ references then mean the old frame (sketch y = +Z,
// normal −Y), which is what a build before format 6 wrote and evaluated.
let mut v: Value = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert!(v.to_string().contains("\"XZ\""), "the saved design names the XZ plane");
v["format"] = Value::from("solidcraft/5");
std::fs::write(&path, v.to_string()).unwrap();
let mut old = Session::default();
run(&mut old, "doc.open", json!({"path": path.to_string_lossy()}));
let want = [
// The old frame: the same sketch coordinates land at +Z and the extrude goes −Y.
("Slab", 150.0, [0.0, -3.0, 0.0], [10.0, 0.0, 5.0]),
("Post", 32.0, [20.0, -9.0, 1.0], [24.0, -7.0, 5.0]),
];
expect(&bodies(&mut old), &want);
// Saving the migrated design writes the current format and keeps the geometry.
let resaved = dir.join("resaved.solidcraft");
run(&mut old, "file.save_as", json!({"path": resaved.to_string_lossy()}));
let text = std::fs::read_to_string(&resaved).unwrap();
assert!(text.contains(&format!("\"solidcraft/{}\"", solidcraft_doc::format::FORMAT)), "resaved at the current format");
let mut again = Session::default();
run(&mut again, "doc.open", json!({"path": resaved.to_string_lossy()}));
expect(&bodies(&mut again), &want);
let _ = std::fs::remove_dir_all(&dir);
}