kernel: a cut's tool face blocks a planar role only where it enters the result

map_planar_sources took every plane of a cut's tool as competing with an input face on it,
facing either way, and dropped that face's exact role. A text pocketed 1 mm down from a block's
top has its tool's top on the top's plane facing up, as the top does; the top then lost its
CertifiedExtrudeCap, and the sketch on it reported "the top cap of Extrude1 no longer exists"
(a_face_sketch_saved_with_fitted_letters_reopens_and_builds_the_same). A cut's tool faces enter
the result turned round, as the walls of the hollow, so a tool face can only take the place of a
face on its plane facing against it (a pocket's floor, a face the tool sat on from outside). Only
that orientation competes now; the existing blocking cases (a tool's bottom on a pocket floor, a
tool face against a wall) are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-29 02:00:00 -04:00
committed by Irakli Kourtis
parent 5489599c0d
commit f5dfb78ee8
+6 -2
View File
@@ -225,9 +225,13 @@ impl Body {
let mapped = guard("exact planar support lineage", || {
let mut competing = Vec::new();
for plane in blocker.map(actual_planes).transpose()?.into_iter().flatten().flatten() {
// A tool face blocks a face on its plane facing either way.
// A cut's tool face enters the result turned round (the wall of the hollow it
// leaves), so it competes only with a face on its plane facing against it: a
// pocket's floor, or a target face the tool sat on from outside. A tool face that
// faces the same way as the target's face on its plane (a pocket cut down from a
// cap, its top on the cap) is the tool's own outside and leaves the cap the cap.
let opposing = Plane::new(plane.origin, plane.x, -plane.y).ok_or_else(|| KernelError::Invalid("invalid opposing plane".into()))?;
competing.extend([plane, opposing]);
competing.push(opposing);
}
competing.sort_by(|a, b| a.normal().x.total_cmp(&b.normal().x));
let mut candidates = Vec::new();