Files
OneCAD/crates/engine/src/tests/xz_plane.rs
T
selune 006a23a767 Add design containers with deduplicated blobs and JSON compatibility (#327)
* Add fast design containers with lossless deduplicated payloads

* Keep display caching opt-in to avoid default save overhead
2026-10-12 19:15:41 -04:00

99 lines
4.5 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);
// This fixture edits the historical JSON metadata directly; request JSON explicitly.
run(&mut s, "file.save_as", json!({"path": path.to_string_lossy(), "format": "json"}));
// 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(), "format": "json"}));
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);
}