Expand description
Exact validation of profiles on the contour the exact path builds (#352).
ExactProfileValidator implements ValidateProfile for
ContourProfile and Profile. It decides closure, self-contact and
hole nesting, and refuses with a typed ProfileFinding instead of
guessing.
§Why the lowered ring, not the authored curves
A ProfileSegment stores a Circle2 (an f64 frame and radius) and an
f64 angle domain, so an arc end is centre + r (cos t, sin t). By the
Lindemann-Weierstrass theorem cos t and sin t are transcendental for
every nonzero dyadic t: an arc-to-arc joint almost never closes exactly,
and an arc end almost never lies exactly on a line. An exact predicate on
the literal data would answer “open contour” and “off the axis”, both
correctly and both uselessly. Intent can only be recovered through a
declared interpretation, and the exact path already has one:
contour_to_arc_ring.
- A joint is ONE
f64point, the start of the segment leaving it. - A joint closes when the entering end lies within
max(tolerance.linear(), 8 eps * operand magnitudes)of it. - Each arc becomes a bulge, split into equal sub-arcs of less than half a turn.
The extruder, the revolver and the half-space path build from that ring. So the validator judges the lowered ring and “valid” means valid as the exact path will build it. Each ring edge maps back to the segment it came from, and findings name segments, not ring edges.
§Exact, then tolerance-free
Self-contact, shared boundary and hole nesting are decided on the lowered
ring by axiolid_overlay::check_arc_polygon: exact signs over the ring’s
f64 data, no tolerance in any contact or nesting decision (ADR 0070).
The tolerance enters only where it does in the exact path: joint closure,
and the per-ring degeneracies of validate_arc_ring (repeated vertex,
zero-radius arc, zero area).
What the lowering moves is reported, not hidden:
ProfileReport::max_joint_gap is the largest joint gap it closed. The
lowered boundary lies within 2 * max_joint_gap plus rounding of the
authored one:
- Each lowered arc is a similarity image of the authored arc, its two ends moved by at most the gap at their joints.
- For a sub-arc of less than half a turn, a point of the image moves by
at most
|d0| + |d1 - d0|, whered0andd1are the movements of its ends; both are at most the gap, which gives the bound.
Two parts of the authored boundary that come closer than that, without touching, are decided for the lowered ring.
§Near-contacts (opt-in, #388)
Parts that miss each other by less than a distance are valid exactly.
A consumer that treats them as touching asks
ExactProfileValidator::validate_with for a clearance (usually
tolerance.linear()) and gets a ProfileFinding::Clearance naming the
two segments, with a certified lower bound on their distance. A pair is
reported when its distance has a local minimum below the clearance away
from where they meet, or when it forms an exact cusp (they meet and leave
in the same direction); the neighbourhood of a meeting point at a nonzero
angle, a narrow wedge, is not. The check is
axiolid_overlay::check_arc_polygon_with’s: exact, and a pair it cannot
decide is reported with undecided set, never cleared. It is off in
ValidateProfile::validate, so the extruder and every existing caller
see the same report as before. The lowered ring is judged, as everywhere
here: the authored parts may be 2 * max_joint_gap closer or farther.
§Refused and reported
Refused with a finding, checking nothing more of that contour: too few ring vertices (a polyline segment lowers exactly, to one vertex per polyline vertex it passes), a segment family the lowering refuses (ellipse, B-spline, chains, …), a degenerate frame, an empty parameter range, a polyline domain outside its points, fewer than two finite polyline points, more than a whole turn, and an open joint. A contour that does not lower makes the profile report only those findings, because nesting against a missing ring would be a wrong answer.
Reported, with the segments involved: a self-contact (crossing, pinch,
tangency or fold-back), a shared stretch of boundary between contours, a
hole outside the outer contour, and holes whose interiors meet. An
isolated point where two contours meet is a ProfileContact, not a
finding: ProfileReport::is_valid accepts it and
ProfileReport::is_strict refuses it. Contacts that together cut the
interior apart (a hole touching the outer contour at several points, a
closed chain of holes) are a DisconnectedInterior finding.
Structs§
- Exact
Profile Validator - Validates a profile on the arc ring the exact path lowers it to.
- Profile
Contact - A point where two different contours meet.
- Profile
Report - The result of
ExactProfileValidator.
Enums§
- Contour
Ref - Which contour of a
ContourProfile. - Profile
Finding - Why a profile is not valid as the exact path would build it.