Files
OneCAD/crates/ui-egui/src/sketch_side_ui_tests.rs
T

88 lines
4.3 KiB
Rust

//! Sketch on an origin plane from either side: the new sketch faces the viewer and the view
//! turns to it from where it was, never round to the far side (#1586).
use crate::scenario::Harness;
use serde_json::json;
use solidcraft_engine::doc::{FeatureKind, PlaneRef};
use solidcraft_engine::geom::{Plane, Vec3};
fn sketch_from(yaw: f64, pitch: f64, name: &str) -> (Harness, Vec3, Plane) {
let mut h = Harness::new();
h.app.preferences.look_at_anim = false;
h.app.cam.yaw = yaw;
h.app.cam.pitch = pitch;
let eye = h.app.cam.eye();
h.step(&json!({"start":"sketch.create"})).unwrap();
h.step(&json!({"click":{"plane":name}})).unwrap();
h.settle();
let plane = h.app.session.world_state().sketches.first().map(|s| s.plane).expect("a sketch on the plane");
(h, eye, plane)
}
#[test]
fn a_new_sketch_on_an_origin_plane_faces_the_side_it_was_started_from() {
// (yaw, pitch, plane, the plane's own normal); each plane from both of its sides.
let cases = [
(0.4, 0.4, "XZ", Vec3::Y),
(std::f64::consts::PI - 0.4, 0.4, "XZ", Vec3::Y),
(-1.2, 0.4, "YZ", Vec3::X),
(1.2, 0.4, "YZ", Vec3::X),
(-0.6, 0.5, "XY", Vec3::Z),
(-0.6, -0.5, "XY", Vec3::Z),
];
for (yaw, pitch, name, own) in cases {
let (h, eye, plane) = sketch_from(yaw, pitch, name);
let n = plane.normal();
let what = format!("{name} from yaw {yaw} pitch {pitch}");
assert!(n.dot(own).abs() > 0.999, "{what}: sketched on {n:?}");
assert!(eye.dot(n) > 0.0, "{what}: the sketch normal {n:?} points away from the eye {eye:?}");
// The view looks straight at the sketch from the side it was looking from.
let after = h.app.cam.eye();
assert!(after.dot(own * eye.dot(own).signum()) > 0.0, "{what}: the view turned to the far side {after:?}");
let (right, up, back) = h.app.cam.basis();
assert!(back.dot(n) > 0.999, "{what}: not looking straight at the sketch ({back:?})");
// Only a sketch from behind the plane saves the flip, turned so its x runs right and
// its y up on screen (a plane's own side keeps its own axes, as before).
let sketch = h.app.session.active_sketch.unwrap();
let FeatureKind::Sketch { plane: saved, .. } = &h.app.session.doc.feature(sketch).unwrap().kind else { panic!() };
let behind = eye.dot(own) < 0.0;
if behind {
assert!(right.dot(plane.x) > 0.999 && up.dot(plane.y) > 0.999, "{what}: sketch axes {:?} {:?} on screen", plane.x, plane.y);
}
assert_eq!(matches!(saved, PlaneRef::Flipped { .. }), behind, "{what}: saved {saved:?}");
}
}
#[test]
fn a_flipped_sketch_extrudes_toward_the_viewer_and_reopens_the_same() {
let (mut h, _, plane) = sketch_from(0.4, 0.4, "XZ");
assert!(plane.normal().dot(Vec3::Y) < -0.999);
h.app.run("sketch.rectangle.two_point", json!({"p0":[0,0],"p1":[10,5]})).unwrap();
let sketch = h.app.session.active_sketch.unwrap();
h.app.finish_sketch();
h.app.run("solid.extrude", json!({"sketch":sketch,"distance":4,"operation":"new_body","body_name":"Block"})).unwrap();
let bounds = |h: &Harness| h.app.session.world_state().body("Block").map(|b| b.mesh().bounds()).expect("an extruded body");
let before = bounds(&h);
assert!(before.min.y < -3.9 && before.max.y < 1e-6, "extruded away from the viewer: {before:?}");
let path = h.dir.join("flipped-sketch.solidcraft");
h.app.run("file.save", json!({"path":path})).unwrap();
h.app.run("doc.open", json!({"path":path})).unwrap();
assert_eq!(bounds(&h), before);
}
#[test]
fn a_construction_plane_seen_from_below_gets_a_sketch_facing_down() {
let mut h = Harness::new();
h.app.preferences.look_at_anim = false;
h.app.run("construct.plane.offset", json!({"base":"XY","offset":"5 mm","name":"P"})).unwrap();
h.app.cam.yaw = -0.6;
h.app.cam.pitch = -0.5;
h.app.session.selection = vec![solidcraft_engine::Sel::Plane { name: "P".into() }];
h.step(&json!({"key":"L"})).unwrap();
h.settle();
let sketch = h.app.session.active_sketch.expect("a sketch on P");
let plane = h.app.session.world_state().sketch(sketch).map(|s| s.plane).unwrap();
assert!(plane.normal().z < -0.999 && (plane.origin.z - 5.0).abs() < 1e-9, "{plane:?}");
assert!(h.app.cam.eye().z < 5.0, "the view stays below the plane");
}