A filleted solid arrived on the plate as a broken model: the slicer reported
"8 non-manifold edges" on an 80x50x12 box with r=3 on all edges, and advised
repairing it in another CAD application -- the exact round trip the Design tab
exists to remove. The same box without the fillet committed cleanly.
Measured rather than guessed. Each of the 8 bad edges is degenerate, both
endpoints the same vertex:
open tri=145 edge=1 face=5 v59(3.000000 3.000000 0.000000) v59(3.000000 3.000000 0.000000)
open tri=538 edge=1 face=6 v87(3.000000 3.000000 12.000000) v87(...)
... one per corner, 8 corners
OCCT triangulates a degenerate surface parameterization with a triangle at the
pole; a corner sphere patch has exactly one. Its two pole nodes are distinct in
the per-face triangulation and collapse to a single vertex when the faces are
welded, leaving a zero-area triangle whose v->v edge can never pair with a
neighbour. its_face_neighbors counts it as open, and the field the object panel
prints as "non-manifold edges" is in fact stats.open_edges.
So the geometry was never wrong -- the B-rep volume matches the Steiner formula
for a box dilated by a ball to 0.016%. Only the bookkeeping was.
Dropping those triangles after the weld removes 8 of 3492 and takes open_edges
to 0. Zero area, so nothing about the shape changes. tri_face is compacted in
the same pass, since it must stay index-aligned with the triangle list that the
face picking and per-body colouring both index into.
Guarded by a new [CadDocument] case that asserts open_edges == 0, no degenerate
triangle survives, and both per-triangle maps still match the triangle count.
The existing suite only ever checked B-rep volumes and areas, which is why a
mesh defect this visible went unnoticed: 150 cases / 2049 assertions green on
both forks.
snaporca-agw
The two remaining ways to create a sheet body. SurfaceLoft skins 2+ profile
sketches without end caps via a new SketchEngine::make_loft_surface — a
sibling of make_loft with the ThruSections solid flag false, so no existing
call site changes. SurfaceFill patches a single closed boundary wire into a
smooth face with BRepOffsetAPI_MakeFilling, adding each boundary edge as a
C0 constraint.
Purely additive: two enum values appended to CadFeatureType, reusing the
existing loft_profile_refs/loft_ruled and sketch_ref fields. No new cereal
fields, recipe stays v2, golden fixture unchanged (30773). MCP
surface_loft/surface_fill added as pure additions. Suite 107 cases / 1553
assertions green, including a test contrasting the open skin against the
solid loft of the same profiles.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
Adds SketchEngine::make_bridge (4-pole cubic Bezier, G1-tangent to Line/Arc
endpoints, straight-line fallback for other types) emitted as the existing
BSpline SketchEntity — no new geometry type, no serialized-field change, golden
recipe fixture untouched. CadDocument::add_bridge appends it (non-parametric,
index-validated, throws on bad refs). MCP `bridge` method mirrors action_project.
4 new [CadDocument][bridge] tests; full kernel suite green (76 cases, 1280 asserts).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q