pub struct SweepPath {
pub curves: Vec<NurbsCurve>,
pub names: Vec<String>,
pub closed: bool,
pub planar: Option<Vec3>,
pub joints: Vec<PathJoint>,
pub straight: bool,
pub screw_axes: Vec<Option<Vec3>>,
}Expand description
A resolved sweep path AND its classification: the ordered, head-to-tail curves, the name of each, whether the run is CLOSED, the PLANE it lies in if it lies in one, and the continuity of every joint — the closing one included.
This is the sweep’s path type, and the classification is computed ONCE, here,
where the path is resolved. Before it, three refusals each derived their own
answer to the same question from the same curves: the builder’s corner gate
measured a tangent break while sampling, the sampler decided a path was
closed by comparing its first and last station, and SW’s translate mode
inferred closure from the fact that a closed path’s advances through the
profile must sum to zero. They agreed, but nothing made them agree, and none
of the three could SAY what it had found — a closed path was only ever
reported as the consequence the refusing rule happened to notice.
ORDER AND ORIENTATION are the caller’s: this classifies the chain it is given, segment order and each segment’s direction untouched, so the first segment still decides which way the sweep runs.
Fields§
§curves: Vec<NurbsCurve>The ordered, head-to-tail world curves.
names: Vec<String>Each curve’s source name, parallel to curves. A short or empty slice is
legal — SweepPath::name degrades to <unnamed> — because a caller
that builds a chain itself (the tube’s bend runs, the wire harness’
spline spans) has no per-segment user-facing name to give.
closed: boolThe last segment’s end returns to the first segment’s start.
planar: Option<Vec3>The UNIT NORMAL of the plane the whole path lies in, when it lies in one
to within [MAX_PLANARITY_DEVIATION] of its own extent.
None for a spatial path, and also for one whose sampled polygon
encloses no signed area to derive a normal from — a straight run, or a
figure-of-eight whose lobes cancel. Only the CLOSED lane reads this, and
a straight run is never closed.
joints: Vec<PathJoint>Every joint, in order: the interior ones (0,1), (1,2), …, then the
CLOSING one (n-1, 0) when the path is closed.
straight: boolEvery segment is a STRAIGHT LINE — a degree-1 curve with two control
points, which is the test SW’s translate mode applies to a segment
before it reduces it to a chord.
Read with Self::corner by the MITRE lane: a cornered run of straight
segments is a polyline, and a polyline corner is the one corner a sweep
can join exactly (see Self::cornered_polyline). A corner at a CURVED
segment is not — there is no single bisector plane a curve’s section can
be trimmed to — so the straightness of the segments, not the size of the
break, is what separates the two.
screw_axes: Vec<Option<Vec3>>Each segment’s SCREW AXIS direction, parallel to curves: Some for a
segment its builder KNOWS is a helix about that axis, None for every
other curve. Unit length; its sign is irrelevant.
Not measured here, and deliberately so: a helix’s published curve is a
cubic FIT, and a fit is not a helix to any bar a classification could
hold it to without a tolerance keyed to the fit density — and a TAPERED
helix is not a constant-slope curve at all. The feature that wound the
helix hands its axis over instead (Self::with_screw_axes).
Read only by the Rigid placement (SW pathAlign): on a helix the path’s
own motion is the SCREW about this axis, and the rotation-minimizing frame
every other curve is carried by rolls away from that screw by the helix’s
integrated torsion — 169.75° over three turns of a radius-5, pitch-5 coil.
Implementations§
Source§impl SweepPath
impl SweepPath
Sourcepub fn new(
curves: Vec<NurbsCurve>,
names: Vec<String>,
) -> Result<Self, KernelRefusal>
pub fn new( curves: Vec<NurbsCurve>, names: Vec<String>, ) -> Result<Self, KernelRefusal>
Classify curves (ordered head-to-tail) into a path. names may be
shorter than curves, or empty.
Sourcepub fn with_screw_axes(
self,
axes: Vec<Option<Vec3>>,
) -> Result<Self, KernelRefusal>
pub fn with_screw_axes( self, axes: Vec<Option<Vec3>>, ) -> Result<Self, KernelRefusal>
Attach each segment’s SCREW AXIS (Self::screw_axes), parallel to the
curves. A zero axis is refused rather than silently read as “no axis”.
Sourcepub fn from_curves(
curves: &[NurbsCurve],
names: &[String],
) -> Result<Self, KernelRefusal>
pub fn from_curves( curves: &[NurbsCurve], names: &[String], ) -> Result<Self, KernelRefusal>
Classify a borrowed chain — the entry a caller assembling curves for one
build uses (Self::new takes them by value for a caller that owns them).
Sourcepub fn name(&self, index: usize) -> &str
pub fn name(&self, index: usize) -> &str
Segment index’s name, degrading to <unnamed> for a caller that named
none.
Sourcepub fn corner(&self) -> Option<&PathJoint>
pub fn corner(&self) -> Option<&PathJoint>
The first CORNER (a G0 joint), if the path has one — what a builder that
skins between stations refuses on.
Sourcepub fn cornered_polyline(&self) -> bool
pub fn cornered_polyline(&self) -> bool
This path is a CORNERED POLYLINE: every segment straight, with at least
one G0 joint. The MITRE lane’s selector, and the one predicate both the
builder and the two features read — the builder to pick the lane, the
features to know how many faces to name (one wall per segment × section
edge, rather than one per section edge).
Each clause is a separate geometric reason:
- STRAIGHT, because a mitre trims both sides to ONE plane, and only a straight segment has a single direction for that plane to bisect;
- a CORNER, because a tangent-continuous polyline (collinear segments) is already carried by the skinning lane, which must keep it.
CLOSED IS NOT A CLAUSE, and that is this predicate’s whole content: a
closed cornered polyline — a picture FRAME — is mitred at every joint
INCLUDING the closing one, and comes out as one wall per (segment ×
section curve) with no caps at all. On a PLANAR loop the joint rotations
are all about the path plane’s normal and sum to the loop’s total turning,
±2π, so the section carried once round comes back as itself and the
closing mitre is built exactly like the others (sweep_topology/miter.rs
derives it, and measures the residual it predicts to be zero). A SPATIAL
loop’s section returns rolled by the path’s own holonomy, and the lane
closes it with a counter-twist shared over the sides — the same closure
policy the smooth ring lane applies (crate::SweepClosure).
So this answers “is this the MITRE lane”, and Self::closed answers
“does the result have caps”. Both features read both.