STEP and SMLib: no edge or vertex tolerance past the 1 mm SMLib takes

An edge raised to cover its pcurves' gap could get past SMLib's limit
(Congé19: 0.98 mm off, tolerance 1.47 mm) and its whole solid then failed
as "SMLib rejected the input". The tolerance an edge or vertex would get,
not only its gap, is now held to that 1 mm: farther off is refused with
how far. The record mapping refuses a tolerance past it with a message
rather than handing SMLib what it rejects.

The margin over a surface gap moves to solidcraft_geom::brep::pcurve
(SURFACE_GAP_MARGIN) for SMLib's pcurves to use too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-27 22:02:31 -04:00
committed by Irakli Kourtis
parent 0bee8c2ed2
commit 5d6810128b
4 changed files with 29 additions and 18 deletions
+4
View File
@@ -64,6 +64,10 @@ const CHECKS: usize = 16;
/// How close, against the geometry's size, a closed-form pcurve must lift onto its edge to be
/// taken as exact (rounding, well inside any tolerance).
const EXACT: f64 = 1e-9;
/// An edge's tolerance over its largest distance from a face's surface: a pcurve is accepted
/// within half its edge's tolerance ([`pcurves_within`]), as SMLib's zone tolerance is half the
/// record's, so a tolerance that covers a gap goes past twice it.
pub const SURFACE_GAP_MARGIN: f64 = 3.0;
/// For each loop of a face on `surface`, the pcurve of each of its edge uses, in order, within
/// `tolerance` mm (or the use's own edge tolerance where larger) of the edge when lifted onto
+2
View File
@@ -104,6 +104,8 @@ pub const FACE_TORUS_MAJOR_RADIUS: i32 = 162;
pub const FACE_TORUS_MINOR_RADIUS: i32 = 163;
pub const EDGE_TOLERANCE: i32 = 164;
pub const VERTEX_TOLERANCE: i32 = 165;
/// The largest EDGE_TOLERANCE or VERTEX_TOLERANCE import takes (smlib.h: "at most 1").
pub const MAX_TOLERANCE: f64 = 1.0;
/// `SMLIB_FLAT_MAX_LEN`: no array is longer.
pub const MAX_LEN: usize = 1 << 27;
pub const SURFACE_NURBS: u8 = 0;
+11 -3
View File
@@ -254,15 +254,23 @@ fn laid_out(brep: &b::Brep, trusted: bool, analytic: bool, bare: &HashSet<(u32,
}
a.i(flat::EDGE_VERTICES).extend([i64::from(e.vertices[0]), i64::from(e.vertices[1])]);
a.r(flat::EDGE_RANGE).extend(*interval);
// Each edge's own tolerance, never below the body's.
a.r(flat::EDGE_TOLERANCE).push(e.tolerance.max(brep.tolerance));
// Each edge's own tolerance, never below the body's, and never past what SMLib takes.
let tolerance = e.tolerance.max(brep.tolerance);
if !(tolerance <= flat::MAX_TOLERANCE) {
return Err(Unsupported::NotYet("an edge tolerance over 1 mm"));
}
a.r(flat::EDGE_TOLERANCE).push(tolerance);
}
let (mut lo, mut hi) = ([f64::INFINITY; 3], [f64::NEG_INFINITY; 3]);
for v in &brep.vertices {
a.i(flat::VERTEX_POINT_TYPE).push(1);
a.r3(flat::VERTEX_POSITION, v.point);
a.r(flat::VERTEX_TOLERANCE).push(v.tolerance.max(brep.tolerance));
let tolerance = v.tolerance.max(brep.tolerance);
if !(tolerance <= flat::MAX_TOLERANCE) {
return Err(Unsupported::NotYet("a vertex tolerance over 1 mm"));
}
a.r(flat::VERTEX_TOLERANCE).push(tolerance);
for k in 0..3 {
lo[k] = lo[k].min(v.point[k]);
hi[k] = hi[k].max(v.point[k]);
+12 -15
View File
@@ -77,20 +77,17 @@ const MAX_SPLINE_POINTS: usize = 4096;
const MAX_SPLINE_DEGREE: usize = 16;
/// Samples along a curve when projecting a vertex onto it.
const MAX_SAMPLES: usize = 4096;
/// How far (mm) a vertex may lie from its curve before the edge is refused.
const MAX_VERTEX_GAP: f64 = 1.0;
/// How far (mm) an edge's curve may lie from a face's surface before the face is refused.
const MAX_EDGE_GAP: f64 = 1.0;
/// The largest tolerance (mm) an edge or vertex is given: SMLib takes none larger (smlib.h's
/// EDGE_TOLERANCE and VERTEX_TOLERANCE, `solidcraft_smlib::flat::MAX_TOLERANCE`). Geometry that
/// would need more is refused, with how far off it lies.
const MAX_TOLERANCE: f64 = 1.0;
/// A vertex's tolerance over its largest gap from its curves and surfaces.
const VERTEX_GAP_MARGIN: f64 = 1.5;
/// Intervals an edge's curve is measured over against each face's surface it bounds.
const EDGE_GAP_SAMPLES: usize = 16;
/// An edge's tolerance over the largest gap measured between its pcurves and its curve, as the
/// record check measures it: with margin, as a vertex's.
const EDGE_GAP_MARGIN: f64 = 1.5;
/// An edge's tolerance over its largest distance from a face's surface, measured before its
/// pcurve is made: a closed-form pcurve is accepted within half its edge's tolerance
/// (`pcurve::pcurves_within`), so the tolerance goes past twice the distance.
const EDGE_SURFACE_MARGIN: f64 = 3.0;
/// A solid (or sheet) read from the file.
#[derive(Clone, Debug)]
pub struct Solid {
@@ -441,11 +438,11 @@ impl<'b, 'a> Builder<'b, 'a> {
/// A vertex `gap` mm from where its edge's curve puts it: refused if far off, else its
/// tolerance covers the gap.
fn raise_vertex(&mut self, v: u32, gap: f64, edge: u64) -> R<()> {
if !(gap <= MAX_VERTEX_GAP) {
if !(VERTEX_GAP_MARGIN * gap <= MAX_TOLERANCE) {
return Err(format!("edge #{edge}: a vertex lies {gap} mm off its curve"));
}
if let Some(x) = self.vertices.get_mut(v as usize) {
x.tolerance = x.tolerance.max(1.5 * gap);
x.tolerance = x.tolerance.max(VERTEX_GAP_MARGIN * gap);
}
Ok(())
}
@@ -492,7 +489,7 @@ impl<'b, 'a> Builder<'b, 'a> {
let Some(s) = on.project_with(&starts, p, None, f64::INFINITY).and_then(|q| on.point(q)) else { continue };
gap = gap.max(s.dist(p));
}
self.cover_edge(e, gap, EDGE_SURFACE_MARGIN)?;
self.cover_edge(e, gap, pcurve::SURFACE_GAP_MARGIN)?;
}
}
Ok(())
@@ -504,7 +501,7 @@ impl<'b, 'a> Builder<'b, 'a> {
if margin * gap <= x.tolerance {
return Ok(());
}
if !(gap <= MAX_EDGE_GAP) {
if !(margin * gap <= MAX_TOLERANCE) {
return Err(format!("an edge lies {gap} mm off the face's surface"));
}
x.tolerance = margin * gap;
@@ -1002,10 +999,10 @@ impl<'b, 'a> Builder<'b, 'a> {
{
let p = v3(x.point);
let gap = surface.project(p, None, f64::INFINITY).and_then(|q| surface.point(q)).map_or(f64::INFINITY, |s| s.dist(p));
if !(gap <= MAX_VERTEX_GAP) {
if !(VERTEX_GAP_MARGIN * gap <= MAX_TOLERANCE) {
return Err(format!("face #{}: a vertex loop's vertex lies {gap} mm off its surface", face.step));
}
x.tolerance = x.tolerance.max(1.5 * gap);
x.tolerance = x.tolerance.max(VERTEX_GAP_MARGIN * gap);
}
}
}