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 <jonas.wrede@beyondit.gmbh>
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,
|
before,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
mats: vec![],
|
mats: vec![],
|
||||||
|
sheets: vec![],
|
||||||
})));
|
})));
|
||||||
let captured = crate::naming::face_name_at_body(&old_body, Vec3::new(20., 6., 1.)).unwrap();
|
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");
|
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,
|
before,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
mats: vec![],
|
mats: vec![],
|
||||||
|
sheets: vec![],
|
||||||
})));
|
})));
|
||||||
let t = std::f64::consts::FRAC_1_SQRT_2;
|
let t = std::f64::consts::FRAC_1_SQRT_2;
|
||||||
let at = Vec3::new(34. + 6. * t, 24. + 6. * t, 1.);
|
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,
|
before,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
mats: vec![],
|
mats: vec![],
|
||||||
|
sheets: vec![],
|
||||||
})));
|
})));
|
||||||
let at = Vec3::new(0., 15., 1.);
|
let at = Vec3::new(0., 15., 1.);
|
||||||
let former = crate::naming::face_name_at_body(&old_body, at).unwrap();
|
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>) {
|
fn stamp(&mut self, before: &Arc<ModelState>, f: &Feature, key: u64, mats: Vec<Mat>) {
|
||||||
let feature = f.id;
|
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 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
|
// 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).
|
// the feature was saved when they were named in that order).
|
||||||
if !f.shell_piece_order {
|
if !f.shell_piece_order {
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ pub struct NamingOrigin {
|
|||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
/// Instance transforms of a pattern or mirror (its copies are named after their sources).
|
/// Instance transforms of a pattern or mirror (its copies are named after their sources).
|
||||||
pub mats: Vec<crate::Mat>,
|
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.
|
/// 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();
|
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 empty = Vec::new();
|
||||||
let names: Vec<String> = names
|
let names: Vec<String> = names
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -1327,6 +1327,39 @@ impl SheetBody {
|
|||||||
v
|
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
|
/// The panel edge nearest a world point: (panel, edge a, edge b in flat coordinates, on the
|
||||||
/// top face?, distance).
|
/// top face?, distance).
|
||||||
pub fn edge_at(&self, p: Vec3) -> Option<(Option<usize>, Vec2, Vec2, bool, f64)> {
|
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)
|
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 {
|
fn signed_area(p: &[Vec2]) -> f64 {
|
||||||
let m = p.len();
|
let m = p.len();
|
||||||
(0..m).filter_map(|i| Some(p.get(i)?.cross(*p.get((i + 1) % m)?))).sum::<f64>() / 2.0
|
(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]
|
#[test]
|
||||||
#[ignore = "fails until #535 is fixed"]
|
|
||||||
fn a_hole_on_a_folded_panel_keeps_the_name_of_its_sketch_circle() {
|
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.
|
// 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();
|
let mut s = Session::default();
|
||||||
|
|||||||
Reference in new issue
Block a user