fix: cuts no longer split walls they don't touch (#670)
A cut built slab by slab (the exact prism boolean) sewed the result from horizontal slabs and only joins merged the coplanar pieces back. So a floor vent cut through the Raspberry Pi case split the long wall into strips at the ports' tops and bottoms (87 faces instead of 79 at 32 mm), and at 24 mm the end opening split the end wall. - Prism booleans merge coplanar neighbours for every operation (faces only: edges, curves and surfaces stay exact), keeping each face's construction source where all its pieces share it, Split Face lines and regularization protection. Painted or protected operands keep their authored pieces as before. - The prism history now tells apart a wall's several edges with its caps (a wall with openings meets each opening's floor), so cuts beside existing openings keep exact history and faces keep their names. - Tests: the Pi case's faces pinned after every feature at 24, at 24 changed to 32, and built at 32 (each outer side one face); random openings and bosses on a shelled case never split another side; every corpus design rebuilds a parameter edit like a fresh build and reverts exactly. - Action matrix baseline: demo/pi-case re-blessed (fewer, merged faces; no regressions), demo/pi-case-0.8 recorded, and 88 new passes on regressions/lid_ribs_flush_with_window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9ba72e118b
commit
1e4387f3ea
8 files changed
+1277
-376
No files matched your search
@@ -476,7 +476,7 @@ fn planar_surfaces(shell: &mt::Shell, tol: f64) -> Option<mt::Shell> {
|
||||
/// Heal a solid; returns the input unchanged when nothing applies or healing fails.
|
||||
#[cfg(test)]
|
||||
pub fn heal(solid: Solid, size: f64) -> Solid {
|
||||
healed(solid, size, &[], false).0
|
||||
healed(solid, size, &[], false, false).0
|
||||
}
|
||||
|
||||
/// What healing made each face and edge of its result from.
|
||||
@@ -535,14 +535,21 @@ impl HealMap {
|
||||
/// along lines they were split along on purpose (`keep`), with what each face and edge of the
|
||||
/// result was made from (`None` when that could not be followed).
|
||||
pub(crate) fn heal_traced(solid: Solid, size: f64, keep: &[Vec<Vec3>]) -> (Solid, Option<HealMap>) {
|
||||
healed(solid, size, keep, true)
|
||||
healed(solid, size, keep, true, false)
|
||||
}
|
||||
|
||||
/// [`heal_traced`] that only merges coplanar neighbouring faces, leaving every edge, curve and
|
||||
/// surface as it is: for results whose geometry is already exact (a prism boolean's), where
|
||||
/// joining edges would change more than the faces split in pieces.
|
||||
pub(crate) fn merge_faces_traced(solid: Solid, size: f64, keep: &[Vec<Vec3>]) -> (Solid, Option<HealMap>) {
|
||||
healed(solid, size, keep, true, true)
|
||||
}
|
||||
|
||||
/// The healed solid, and what it was made from when `traced`.
|
||||
fn healed(solid: Solid, size: f64, keep: &[Vec<Vec3>], traced: bool) -> (Solid, Option<HealMap>) {
|
||||
fn healed(solid: Solid, size: f64, keep: &[Vec<Vec3>], traced: bool, faces_only: bool) -> (Solid, Option<HealMap>) {
|
||||
// Edges a boolean made are intersection curves, which panic where they no longer
|
||||
// evaluate; the solid then stays as it is.
|
||||
match crate::guard("heal", || Ok(heal_shells(&solid, size, keep, traced))) {
|
||||
match crate::guard("heal", || Ok(heal_shells(&solid, size, keep, traced, faces_only))) {
|
||||
Ok(Some((healed, map))) => (healed, map),
|
||||
_ => {
|
||||
let map = if traced { crate::guard("heal map", || Ok(HealMap::identity(&solid))).ok() } else { None };
|
||||
@@ -588,7 +595,7 @@ impl Trace {
|
||||
}
|
||||
}
|
||||
|
||||
fn heal_shells(solid: &Solid, size: f64, keep: &[Vec<Vec3>], traced: bool) -> Option<(Solid, Option<HealMap>)> {
|
||||
fn heal_shells(solid: &Solid, size: f64, keep: &[Vec<Vec3>], traced: bool, faces_only: bool) -> Option<(Solid, Option<HealMap>)> {
|
||||
let tol = (size * 1e-7).max(1e-9);
|
||||
let mut shells = Vec::new();
|
||||
let mut changed = false;
|
||||
@@ -603,11 +610,11 @@ fn heal_shells(solid: &Solid, size: f64, keep: &[Vec<Vec3>], traced: bool) -> Op
|
||||
let mut from: Vec<Vec<usize>> = (first..first + count).map(|i| vec![i]).collect();
|
||||
first += count;
|
||||
// Faces come out in place, one for one, except where coplanar ones merge.
|
||||
if let Some(m) = planar_surfaces(&cur, (size * 1e-7).max(1e-9)) {
|
||||
if !faces_only && let Some(m) = planar_surfaces(&cur, (size * 1e-7).max(1e-9)) {
|
||||
cur = m;
|
||||
changed = true;
|
||||
}
|
||||
if let Some(m) = exact_edges(&cur, (size * 1e-5).max(1e-7), &mut trace) {
|
||||
if !faces_only && let Some(m) = exact_edges(&cur, (size * 1e-5).max(1e-7), &mut trace) {
|
||||
cur = m;
|
||||
changed = true;
|
||||
}
|
||||
@@ -616,7 +623,7 @@ fn heal_shells(solid: &Solid, size: f64, keep: &[Vec<Vec3>], traced: bool) -> Op
|
||||
from = groups.iter().map(|g| g.iter().filter_map(|i| from.get(*i)).flatten().copied().collect()).collect();
|
||||
changed = true;
|
||||
}
|
||||
if let Some(m) = merge_collinear(&cur, &mut trace) {
|
||||
if !faces_only && let Some(m) = merge_collinear(&cur, &mut trace) {
|
||||
cur = m;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user