mesh: the one-to-one sweep names a body that ends at several levels (#444)

The crank ends at 8, 16, 20 and 22 mm, so no one-to-one sweep takes it.
The sweep met one of those caps as a linking face and reported "linking
face has no top side". A plane parallel to the source that only part of a
ring reaches is now named as what it is, with extrude pointed to. The arm's
profile alone sweeps as well as extrude does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-16 00:33:55 -04:00
1 parent 0b7dda95f7
commit 9a30c7d9ed
2 files changed
+52 -2

No files matched your search

+20 -2
View File
@@ -33,7 +33,7 @@ use super::region;
use super::{Ctx, Raw, project_to_face, project_to_faces};
use crate::quad::transfinite_grid;
use crate::size::ideal_divisions;
use crate::vec3::{P, sub};
use crate::vec3::{P, dot, sub};
use crate::{Error, Result};
/// The most source faces tried.
@@ -118,7 +118,10 @@ fn topology(brep: &Brep, s: usize) -> std::result::Result<Topology, String> {
run.push((e, fwd));
k += 1;
}
ring.push(link(brep, f, &run)?);
ring.push(link(brep, f, &run).map_err(|e| match cap(brep, s, f) {
Some(why) => why,
None => e,
})?);
}
used.extend(ring.iter().map(|l| l.face));
front = ring.iter().flat_map(|l| l.top.iter().map(move |&(e, fwd)| (e, fwd, l.face))).collect();
@@ -140,6 +143,21 @@ fn topology(brep: &Brep, s: usize) -> std::result::Result<Topology, String> {
Ok(Topology { source: s, target, rings })
}
/// Why face `f`, reached from a front swept from source `s`, cannot be a linking face when it is
/// a plane parallel to the source: a cap that only part of the ring reaches. The body then ends
/// at several levels (a step, a boss, a pocket floor), which no one-to-one sweep takes; saying so
/// names the reason where the linking-face split would only report the symptom (#444).
fn cap(brep: &Brep, s: usize, f: usize) -> Option<String> {
let (_, ns) = brep.faces.get(s)?.plane?;
let (_, nf) = brep.faces.get(f)?.plane?;
(dot(ns, nf).abs() > 1.0 - 1e-9).then(|| {
format!(
"face {} is parallel to the source and only part of the ring reaches it: the body ends at more than one level (a step, a boss or a pocket), and a one-to-one sweep has one target face; method `extrude` meshes such bodies level by level",
brep.face_tag(f)
)
})
}
/// Whether the front's edges are exactly one loop of face `t`.
fn is_loop_of(brep: &Brep, t: usize, front: &[(usize, bool, usize)]) -> bool {
let edges: BTreeSet<usize> = front.iter().map(|x| x.0).collect();