Draft of walls between caps on non-convex bodies: planes tilt about their neutral-plane line, cylinders become cones (47: drafted round-ended pocket)

Oracle: 56/76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-08 03:35:18 +00:00
1 parent 94a0cdef77
commit 7e373ff1f7
4 files changed
+252 -3

No files matched your search

+29 -1
View File
@@ -161,7 +161,10 @@ pub fn draft(b: &Body, faces: &[Vec3], neutral: &Plane, pull: Vec3, angle: f64)
return Err(KernelError::Invalid("draft angle must be between −90° and 90°".into()));
}
let pull = pull.normalized().ok_or_else(|| KernelError::Invalid("pull direction".into()))?;
let hs = planar_convex(b)?;
let hs = match planar_convex(b) {
Ok(h) => h,
Err(_) => return draft_walls(b, faces, neutral, pull, angle),
};
let size = b.size();
let mut out = Vec::new();
let mut moved = 0;
@@ -187,6 +190,31 @@ pub fn draft(b: &Body, faces: &[Vec3], neutral: &Plane, pull: Vec3, angle: f64)
convex_polyhedron(&out)
}
/// Draft of a non-convex body: walls (planes, cylinders) next to caps square to `pull`.
fn draft_walls(b: &Body, at: &[Vec3], neutral: &Plane, pull: Vec3, angle: f64) -> Result<Body> {
let healed = Body::new(crate::heal::heal(b.deep_copy(), b.size()))?;
let size = healed.size();
let mesh = healed.tessellate((size * 1e-3).max(1e-3))?;
let mut chosen: Vec<usize> = Vec::new();
for p in at {
let near = mesh
.triangles
.iter()
.zip(&mesh.tri_face)
.filter_map(|(t, f)| mesh.tri(t).map(|[x, y, z]| (point_tri(*p, x, y, z), *f as usize)))
.min_by(|a, c| a.0.total_cmp(&c.0));
match near {
Some((d, f)) if d < size * 1e-3 + 1e-6 => {
if !chosen.contains(&f) {
chosen.push(f);
}
}
_ => return Err(KernelError::Invalid(format!("no face at {:?}", [p.x, p.y, p.z]))),
}
}
crate::offset::draft_walls(&healed, &chosen, neutral, pull, angle)
}
/// Round every edge of a convex body with planar faces by `r`: faces shrink, each edge becomes a
/// cylinder and each corner a sphere patch (the body is the inner polyhedron grown by a ball).
pub fn round_all_edges(b: &Body, r: f64) -> Result<Body> {