51 lines
2.9 KiB
Rust
51 lines
2.9 KiB
Rust
use crate::{Document, ModelBody, ModelState};
|
|
use solvecraft_geom::{Plane, Vec3};
|
|
use solvecraft_sketch::{LinkKind, LinkSource, Sketch};
|
|
use std::collections::BTreeMap;
|
|
use std::sync::Arc;
|
|
|
|
fn named_box(name: &str, width: f64, height: f64) -> ModelBody {
|
|
let body = solvecraft_kernel::box_solid(Vec3::ZERO, Vec3::new(width, width, height)).unwrap();
|
|
let mut names = vec!["unrelated".to_string(); body.faces(0.01).unwrap().len()];
|
|
let top = body.faces(0.01).unwrap().into_iter().find(|face| face.plane_normal.is_some_and(|normal| normal.z > 0.99)).unwrap().index;
|
|
names[top] = "shared:top".into();
|
|
let mut result = ModelBody::new(name.into(), body, 1);
|
|
result.names = crate::naming::NameCell::known(Arc::new(names));
|
|
result
|
|
}
|
|
|
|
#[test]
|
|
fn named_manual_projection_keeps_its_body_and_face_at_shared_boundaries() {
|
|
let doc = Document::default();
|
|
let mut initial = ModelState::default();
|
|
initial.bodies.extend([named_box("Source", 20., 10.), named_box("Control", 5., 10.)]);
|
|
let plane = Plane::XY.offset(20.);
|
|
let source = LinkSource::Face { body: "Source".into(), at: Vec3::new(1., 1., 10.) };
|
|
let resolved = crate::project::resolve(&doc, &BTreeMap::new(), &initial, &plane, LinkKind::Project, &source).unwrap();
|
|
let mut sketch = Sketch::default();
|
|
let link = sketch.add_link(LinkKind::Project, source, &resolved.geom).unwrap();
|
|
sketch.links[0].face_name = Some("shared:top".into());
|
|
sketch.links[0].source = LinkSource::Face { body: "Source".into(), at: Vec3::new(0., 0., 10.) };
|
|
let mut current = ModelState::default();
|
|
current.bodies.extend([named_box("Source", 20., 20.), named_box("Control", 5., 10.)]);
|
|
assert!(crate::project::refresh_links(&doc, &BTreeMap::new(), ¤t, &plane, &mut sketch).is_empty());
|
|
assert!(!sketch.links[0].lost);
|
|
assert!(sketch.points.iter().any(|point| point.pos.x > 19.));
|
|
assert!(sketch.points.iter().any(|point| point.pos.y > 19.));
|
|
assert!(matches!(&sketch.links[0].source,LinkSource::Face{body,at} if body=="Source" && (at.z-20.).abs()<1e-6));
|
|
// The closest named point can sit on the wall/top seam: retain its actual
|
|
// face index rather than re-picking the adjacent vertical wall.
|
|
let index = crate::naming::face_on_body(current.body("Source").unwrap(), "shared:top", Vec3::new(0., 0., 10.)).unwrap().0;
|
|
assert!(current.body("Source").unwrap().body.faces(0.01).unwrap()[index].plane_normal.unwrap().z > 0.99);
|
|
let saved = sketch.clone();
|
|
let mut missing = ModelState::default();
|
|
missing.bodies.push(named_box("Control", 5., 10.));
|
|
let warnings = crate::project::refresh_links(&doc, &BTreeMap::new(), &missing, &plane, &mut sketch);
|
|
assert!(sketch.links[0].lost);
|
|
assert!(!warnings.is_empty());
|
|
assert_eq!(sketch.curves, saved.curves);
|
|
assert_eq!(sketch.points, saved.points);
|
|
assert_eq!(sketch.links[0].id, link);
|
|
assert!(matches!(&sketch.links[0].source,LinkSource::Face{body,..} if body=="Source"));
|
|
}
|