Faces that a sheet fold or unfold moves keep their names: points on a moved panel are taken back through the panel they lie on to where the sheet held them before the feature, and named from the faces there. Un-ignores the #535 regression test. Fixes #535. Co-authored-by: jonaswre <[email protected]>
This commit is contained in:
1 parent
abff7a49bb
commit
9e2a1eb993
5 files changed
+71
-2
No files matched your search
@@ -253,6 +253,7 @@ fn saved_former_strip_projection_reports_lost_without_expanding_healthy_material
|
||||
before,
|
||||
depth: 1,
|
||||
mats: vec![],
|
||||
sheets: vec![],
|
||||
})));
|
||||
let captured = crate::naming::face_name_at_body(&old_body, Vec3::new(20., 6., 1.)).unwrap();
|
||||
assert_eq!(crate::naming::parent_piece(&captured), Some(stem.as_str()), "actual strip capture records a piece name");
|
||||
@@ -376,6 +377,7 @@ fn saved_curved_strip_projection_is_lost_after_exact_wall_coalescence() {
|
||||
before,
|
||||
depth: 1,
|
||||
mats: vec![],
|
||||
sheets: vec![],
|
||||
})));
|
||||
let t = std::f64::consts::FRAC_1_SQRT_2;
|
||||
let at = Vec3::new(34. + 6. * t, 24. + 6. * t, 1.);
|
||||
@@ -515,6 +517,7 @@ fn saved_stepped_tab_cut_piece_projection_is_lost_without_expanding_material() {
|
||||
before,
|
||||
depth: 1,
|
||||
mats: vec![],
|
||||
sheets: vec![],
|
||||
})));
|
||||
let at = Vec3::new(0., 15., 1.);
|
||||
let former = crate::naming::face_name_at_body(&old_body, at).unwrap();
|
||||
|
||||
@@ -364,7 +364,8 @@ impl ModelState {
|
||||
fn stamp(&mut self, before: &Arc<ModelState>, f: &Feature, key: u64, mats: Vec<Mat>) {
|
||||
let feature = f.id;
|
||||
let depth = before.bodies.iter().filter_map(|b| b.names.origin.as_ref().map(|o| o.depth)).max().unwrap_or(0) + 1;
|
||||
let origin = Arc::new(crate::naming::NamingOrigin { feature: f.clone(), before: before.clone(), depth, mats });
|
||||
let sheets = if f.kind.is_sheet() { self.sheets.clone() } else { Vec::new() };
|
||||
let origin = Arc::new(crate::naming::NamingOrigin { feature: f.clone(), before: before.clone(), depth, mats, sheets });
|
||||
// Pieces a cut left are named after their faces, not the kernel's shell order (unless
|
||||
// the feature was saved when they were named in that order).
|
||||
if !f.shell_piece_order {
|
||||
|
||||
@@ -31,6 +31,8 @@ pub struct NamingOrigin {
|
||||
pub depth: usize,
|
||||
/// Instance transforms of a pattern or mirror (its copies are named after their sources).
|
||||
pub mats: Vec<crate::Mat>,
|
||||
/// The sheet metal bodies after a sheet feature (their folds place moved faces).
|
||||
pub sheets: Vec<crate::sheet::SheetBody>,
|
||||
}
|
||||
|
||||
/// The lazily computed names of a body, shared by its clones.
|
||||
@@ -334,6 +336,24 @@ fn geometric_from(b: &ModelBody, o: &NamingOrigin, nf: usize, names_of: fn(&Mode
|
||||
names = got.into_iter().map(|n| n.map(|n| format!("{n}@F{fid}.{}", k + 1))).collect();
|
||||
}
|
||||
}
|
||||
// A sheet feature that moved panels (a fold, an unfold): faces it carried along lie on the
|
||||
// faces they were, taken back through the panel they are on.
|
||||
if let (Some(after), Some(before), Some(input)) = (
|
||||
o.sheets.iter().find(|s| s.body == b.name),
|
||||
o.before.sheets.iter().find(|s| s.body == b.name),
|
||||
inputs.iter().find(|(x, _, _)| x.name == b.name),
|
||||
) {
|
||||
let input = std::slice::from_ref(input);
|
||||
for (name, ps) in names.iter_mut().zip(&pts) {
|
||||
if name.is_some() {
|
||||
continue;
|
||||
}
|
||||
let back: Option<Vec<Vec3>> = ps.iter().map(|p| after.point_before(before, *p)).collect();
|
||||
if let Some(back) = back.filter(|b| !b.is_empty()) {
|
||||
*name = vote(&back, input, tol, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
let empty = Vec::new();
|
||||
let names: Vec<String> = names
|
||||
.into_iter()
|
||||
|
||||
@@ -1327,6 +1327,39 @@ impl SheetBody {
|
||||
v
|
||||
}
|
||||
|
||||
/// Where a world point of this sheet lay in `before`, the same sheet before a feature
|
||||
/// changed its folds: the point goes back to flat coordinates through the panel it lies on
|
||||
/// and is folded again the way `before` folded that material. A panel a fold made was part of
|
||||
/// the panel it was folded out of. `None` off every panel (on a bend).
|
||||
pub(crate) fn point_before(&self, before: &SheetBody, p: Vec3) -> Option<Vec3> {
|
||||
const TOL: f64 = 1e-4;
|
||||
for (pi, r) in self.panels() {
|
||||
let Some(inv) = mat_inverse(&self.world(pi)) else { continue };
|
||||
let q = apply_point(&inv, p);
|
||||
if q.z < -TOL || q.z > self.t + TOL {
|
||||
continue;
|
||||
}
|
||||
let q2 = Vec2::new(q.x, q.y);
|
||||
let pts = dedup(&r.outer.ccw().polyline(1e-3));
|
||||
if !point_in(&pts, q2) && !near_outline(&pts, q2, TOL) {
|
||||
continue;
|
||||
}
|
||||
// Panels `before` did not have yet came out of their parent's (bounded walk).
|
||||
let mut owner = pi;
|
||||
for _ in 0..self.flanges.len() {
|
||||
match owner {
|
||||
Some(i) if i >= before.flanges.len() => owner = self.flanges.get(i).and_then(|f| f.parent),
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
if owner.is_some_and(|i| i >= before.flanges.len()) {
|
||||
return None;
|
||||
}
|
||||
return Some(apply_point(&before.world(owner), q));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// The panel edge nearest a world point: (panel, edge a, edge b in flat coordinates, on the
|
||||
/// top face?, distance).
|
||||
pub fn edge_at(&self, p: Vec3) -> Option<(Option<usize>, Vec2, Vec2, bool, f64)> {
|
||||
@@ -2409,6 +2442,19 @@ fn merge_loops(polys: &[Vec<Vec2>], work: &mut FlatWork) -> Result<Vec<Vec<Vec2>
|
||||
Ok(loops)
|
||||
}
|
||||
|
||||
/// Whether `q` lies within `tol` of the closed polygon `poly`'s outline.
|
||||
fn near_outline(poly: &[Vec2], q: Vec2, tol: f64) -> bool {
|
||||
let m = poly.len();
|
||||
(0..m).any(|i| match (poly.get(i), poly.get((i + 1) % m)) {
|
||||
(Some(&a), Some(&b)) => {
|
||||
let d = b - a;
|
||||
let t = if d.len2() > 1e-18 { ((q - a).dot(d) / d.len2()).clamp(0.0, 1.0) } else { 0.0 };
|
||||
(a + d * t).dist(q) < tol
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn signed_area(p: &[Vec2]) -> f64 {
|
||||
let m = p.len();
|
||||
(0..m).filter_map(|i| Some(p.get(i)?.cross(*p.get((i + 1) % m)?))).sum::<f64>() / 2.0
|
||||
|
||||
@@ -2478,7 +2478,6 @@ fn hole_face_names(s: &mut Session) -> Vec<String> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "fails until #535 is fixed"]
|
||||
fn a_hole_on_a_folded_panel_keeps_the_name_of_its_sketch_circle() {
|
||||
// A Ø10 hole at x = 20 on a 100 x 60 plate; the fold at x = 40 stands that (smaller) side up.
|
||||
let mut s = Session::default();
|
||||
|
||||
Reference in new issue
Block a user