mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 18:45:55 +00:00
Sheet face names: a triangle takes a flat face's name only where that face faces its way
A face's sheet name is the name 80% of its mesh triangles' centres agree on. SMLib's mesher fans a 1 mm rim (30 mm tall) into four triangles about its middle; two of their centres lie 1/6 mm from the panel's top or bottom face, inside the 0.2·t tolerance, and took that face's name, so the rim got no name (rim.side0/side1/ext0/ext1 of the tray's flanges: 6 faces unnamed). A flat face's name now needs its plane to face along the triangle's normal (within 1e-3); otherwise the point is a rim's, a bend's or an ext rim's. No face changes name: these faces had none. sheet::face_names_tests::a_trays_faces_have_readable_sheet_names_that_follow_its_size now passes its naming checks and fails later, on the point named_face_point gives for a rim (the roomiest triangle's incentre, 0.497 mm from the rim's edge, not 0.5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
//! neighbouring flange), the rim along the bend there, `<flange>:rim.ext0` and `rim.ext1`. A panel is `base` or a flange's tag (`F<feature>.<k>`), so the names
|
||||
//! say what each face is and stay with it when sizes change or other flanges come and go.
|
||||
|
||||
use solidcraft_geom::{Vec2, Vec3};
|
||||
use solidcraft_geom::{Plane, Vec2, Vec3};
|
||||
|
||||
use super::SheetBody;
|
||||
use crate::{ModelBody, ModelState, apply_point, mat_inverse};
|
||||
@@ -13,6 +13,9 @@ use crate::{ModelBody, ModelState, apply_point, mat_inverse};
|
||||
/// The share of a face's sample points that must agree on a name for the face to take it.
|
||||
const AGREE: f64 = 0.8;
|
||||
|
||||
/// The sine of the angle within which a flat face's plane faces along a triangle's normal.
|
||||
const FACING: f64 = 1e-3;
|
||||
|
||||
impl SheetBody {
|
||||
/// The readable name of the face of this sheet a point lies on (sheet coordinates, within
|
||||
/// `tol`, kept below a quarter of the thickness): a flat face's (see
|
||||
@@ -21,6 +24,24 @@ impl SheetBody {
|
||||
self.panel_face_at(p, tol).map(|(name, _)| name).or_else(|| self.bend_face_at(p, tol)).or_else(|| self.ext_rim_at(p, tol))
|
||||
}
|
||||
|
||||
/// [`face_name_at`](Self::face_name_at) for a point on a face whose normal is `normal` (a
|
||||
/// mesh triangle's, either way round): a flat face's name is taken only where its plane faces
|
||||
/// along `normal`. A rim is as narrow as the sheet is thick, so the centres of its triangles
|
||||
/// can lie within `tol` of the panel's top or bottom face beside it.
|
||||
fn face_name_facing(&self, p: Vec3, normal: Vec3, tol: f64) -> Option<String> {
|
||||
let facing = |plane: &Plane| plane.normal().cross(normal).len() < FACING;
|
||||
match self.panel_face_at(p, tol) {
|
||||
Some((name, plane)) if facing(&plane) => Some(name),
|
||||
Some(_) => self
|
||||
.rim_face_at(p, tol)
|
||||
.filter(|(_, plane)| facing(plane))
|
||||
.map(|(name, _)| name)
|
||||
.or_else(|| self.bend_face_at(p, tol))
|
||||
.or_else(|| self.ext_rim_at(p, tol)),
|
||||
None => self.bend_face_at(p, tol).or_else(|| self.ext_rim_at(p, tol)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The rim of a flange's panel along its bend line, where the panel runs on past the
|
||||
/// bend's start (`<flange>:rim.ext0`) or end (`rim.ext1`).
|
||||
fn ext_rim_at(&self, p: Vec3, tol: f64) -> Option<String> {
|
||||
@@ -106,12 +127,13 @@ pub fn body_sheet_face_names(st: &ModelState, b: &ModelBody) -> Vec<Option<Strin
|
||||
let mut total = vec![0usize; nf];
|
||||
for (t, f) in m.triangles.iter().zip(&m.tri_face) {
|
||||
let (Some(v), Some(n), Some([a, b2, c])) = (votes.get_mut(*f as usize), total.get_mut(*f as usize), m.tri(t)) else { continue };
|
||||
let Some(normal) = (b2 - a).cross(c - a).normalized() else { continue };
|
||||
// At most a few dozen points a face: enough to tell its name, cheap on a fine mesh.
|
||||
if *n >= 48 {
|
||||
continue;
|
||||
}
|
||||
*n += 1;
|
||||
if let Some(name) = sheet.face_name_at((a + b2 + c) * (1.0 / 3.0), tol) {
|
||||
if let Some(name) = sheet.face_name_facing((a + b2 + c) * (1.0 / 3.0), normal, tol) {
|
||||
match v.iter_mut().find(|(x, _)| *x == name) {
|
||||
Some(x) => x.1 += 1,
|
||||
None => v.push((name, 1)),
|
||||
|
||||
Reference in New Issue
Block a user