Expand description
Lower an EdgeFeatureData into pure-CSG masks against its child.
Chamfers and fillets are not primitives anywhere in the pipeline — an
EdgeFeature node lowers to booleans over ordinary
Cube/Cylinder/Cone/Revolve solids, so every backend (Manifold,
BSP, SDF ray-march, projection) renders them through variants it already
supports. Subtractive masks cut as Difference(child, Union(sub));
additive masks (concave ring fillets) union on top of that.
Edges are re-resolved against the current child on every lowering
(resolve_edge), so features follow parameter edits; selections that no
longer resolve are skipped (callers surface the count from
LowerReport). Masks are built in the child’s local frame — callers
apply outer transforms above the feature node as usual.
§Chamfer masks
- Straight convex edge: the cut plane passes through the two setback
lines
P_F = edge + s·d̂_F; the mask is an oriented box with one face on that plane, deep enough to swallow the edge, emitted asTranslate ∘ Rotate ∘ Cube. Extending past the setback lines is safe — beyond them the box sits on the air side of both faces (convexity) — and the tiny ε overhang along the edge keeps corners watertight (adjacent chamfers stay un-mitered in v1). - Circular convex rim: the meridian setback points revolve into a cut
cone (a cylinder when the setbacks share a radius). The mask is
Difference(slab, cone)when the rim’s material lies radially inside (outer rims) orIntersection(slab, cone)when it lies outside (hole-rim countersinks). The slab is clamped axially to the setback band, so blind holes are never deepened and walls below the chamfer are untouched; radial/axial ε only ever extends into air.
§Fillet masks
For faces meeting at interior angle γ (cos γ = d̂_A·d̂_B), a radius-r
arc tangent to both faces has its center a distance h = r/sin(γ/2) down
the bisector and touches each face at setback s_T = r/tan(γ/2) from the
edge. The clamp below applies to s_T (that is what must fit on the
faces), and r rescales with it.
- Straight convex edge: the chamfer box through the
s_Tsetbacks, minus the tangent cylinder along the edge — the cylinder wall becomes the fillet surface. Fully SDF-visible. - Circular rim (convex or concave): the meridian wedge between the
setbacks minus the tangent circle, sampled into a polygon
(
data.segmentsarc chords) and revolved around the rim axis. Convex rims subtract the ring; concave rims (boss-base junctions) add the corner-fill ring.Revolvemasks are invisible in the SDF preview (existing sentinel) and ignored by the analytic picking walk — mesh backends render them exactly.
Feature size is clamped per edge to 0.45 × the smaller adjacent face
extent, so a slider can’t push a mask through the far side of a face.
Rim masks tessellate at the curved leaf’s own segment count and
angular phase ([rim_segments]/[place_on_rim]): where a mask surface
runs along the leaf’s wall (countersink tangency, fillet tangent bands),
coincident chords make the boolean junction a clean polygon ring instead
of an interleaved sliver band (wobbly seams, streaky shading).
§Frame-mapped (elliptical) rims
Rims of anisotropically scaled leaves resolve as circles in the leaf’s
own frame (CircularEdge::frame).
Their masks are built in that frame by the same meridian constructions
and wrapped with the frame transform (Translate∘Rotate∘Scale∘Rotate
from an SVD split), so the cut is the exact affine image of the circular
one: the feature stretches with the shape, and size/extents are
frame-local for those edges. A constant-width cut along an ellipse is
not expressible with the primitive vocabulary (its offset curves are
not conics), so stretching is the exact-CSG semantic choice.
Structs§
- Lower
Report - What a lowering pass did — callers log/report the skip count.
- Lowered
Masks - Masks for one lowering pass, in the child’s frame:
subcuts material (chamfers, convex fillets),addfills it in (concave ring fillets).
Functions§
- lower
- Lower
dataagainstchild: subtract the cut masks, union the fill masks, or pass the child through unchanged when nothing resolves. - lower_
masks - The masks for
dataagainstchild, in the child’s frame. Unresolvable/unsupported edges are skipped and counted.