diff --git a/crates/geom/src/brep.rs b/crates/geom/src/brep.rs index b5f59d2ccb..d81dd31ea2 100644 --- a/crates/geom/src/brep.rs +++ b/crates/geom/src/brep.rs @@ -85,9 +85,11 @@ pub struct Face { /// The modelled rectangle in surface parameters, `[[u0, u1], [v0, v1]]`, inside the /// surface's natural domain and around every loop. pub domain: [[f64; 2]; 2], - /// `loops[0]` is the outer loop, the rest inner. Loops are stored relative to the surface's - /// natural normal, whatever side a shell uses: seen from that normal, the outer loop runs - /// counter-clockwise and inner loops clockwise. + /// One outer loop and any inner ones, in the producer's order (truck lists some holes + /// first; SMLib's import puts the outer loop first, as SMLib requires). Loops are stored + /// relative to the surface's natural normal, whatever side a shell uses: seen from that + /// normal, the outer loop runs counter-clockwise and inner loops clockwise, which is what + /// tells them apart. The first loop is an edge loop. pub loops: Vec, } diff --git a/crates/geom/src/brep/geometry.rs b/crates/geom/src/brep/geometry.rs index a69dcb01da..247099ea29 100644 --- a/crates/geom/src/brep/geometry.rs +++ b/crates/geom/src/brep/geometry.rs @@ -172,7 +172,7 @@ impl Brep { } } } - // The area the loop encloses, its sign by its place (outer first). Where + // The signed area the loop encloses (positive for the outer loop). Where // uses meet at a pole the ring runs straight along the pole's line. let at = Record::Loop { face, r#loop }; let mut ring: Vec<[f64; 2]> = Vec::with_capacity(edges.len().saturating_mul(AREA_SAMPLES)); diff --git a/docs/native-brep.md b/docs/native-brep.md index edeea5e8ad..911e8130d7 100644 --- a/docs/native-brep.md +++ b/docs/native-brep.md @@ -52,8 +52,11 @@ shells with opposite `forward`. `forward` means the face's normal in that shell its surface's natural normal, ∂S/∂u × ∂S/∂v. In a closed shell, normals point out of the material. -**Loops.** A face's first loop is its outer loop and is an edge loop. A vertex -loop (a pole, a collapsed boundary) is only ever an inner loop. Loops are stored +**Loops.** A face has one outer loop and any number of inner ones, in the +producer's order: truck lists some holes before the outer loop, and an SMLib +import puts the outer loop first, as SMLib requires. The first loop is an edge +loop. A vertex loop (a pole, a collapsed boundary) is only ever an inner loop. +Orientation tells outer from inner. Loops are stored relative to the surface's natural normal, whichever side a shell uses: seen from that normal, the outer loop runs counter-clockwise and inner loops clockwise. This lets one face sit in two shells without contradicting itself. An edge loop @@ -82,7 +85,7 @@ paint and persistent names. The same holds for edges and vertices. 1. Regions: the infinite region, then bounded regions in the producer's order. 2. Shells and faces in order of first appearance, walking regions → shells → oriented faces. -3. Edges in order of first appearance, walking faces → loops (outer first) → +3. Edges in order of first appearance, walking faces → loops (in stored order) → oriented edges, then wire edges walking shells. A face whose first oriented face is reversed is walked backwards: each of its loops from its last oriented edge to its first. That is how a reversed face is traversed.