Skip to main content

Module profile_validate

Module profile_validate 

Source
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 f64 point, 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|, where d0 and d1 are 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§

ExactProfileValidator
Validates a profile on the arc ring the exact path lowers it to.
ProfileContact
A point where two different contours meet.
ProfileReport
The result of ExactProfileValidator.

Enums§

ContourRef
Which contour of a ContourProfile.
ProfileFinding
Why a profile is not valid as the exact path would build it.