Fillet: refuse a result with openings in its surface (#871) (#949)

* Fillet: refuse a result with openings in its surface (#871)

A fillet on #871's part (radius 1 on a window's edges and on the sides of a
block 1.26 mm away) came back closed as topology with every face meshing, but
the rounds overlapped and the end faces' boundary loops crossed, so the model
showed holes. The constant-radius fillet now checks its result before taking it:
the body's mesh, welded within a millionth of its size, must have no edge
without as many triangles running the other way along it, except for cracks
within the mesh tolerance where fitted curves meet. A result that fails is
refused, so the corner build gets its try and the radius search treats it as
too large.

Body::open_mesh_edges is the check. Kernel tests cover the #871 part (refused
at radius 1, closed with a round on every edge at 0.5), and an engine test runs
the fillet from the report and leaves the part as it was. All 96 robustness
seeds build the same with and without it.

Fixes #871

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Check fillets for crossed face boundaries, not free mesh edges

Free edges in the mesh also come from cracks where fitted curves meet (corner
patches, rounds ending on curved edges), so the mesh test refused good fillets.
The check is now on the cause of #871: a planar face whose boundary loops cross
each other or themselves has no inside. Body::crossed_face_loops samples each
planar face's loops within 1/1000 of the size and counts proper crossings
(touching within a millionth doesn't count).

The pyramid apex blend and the loft fillets build again. Ten action-matrix fillets
stay refused, recorded in the baseline: r = 3 on the 2 mm rim of oracle 09's
shelled box (the round runs past the inner wall; the result was 240 mm3 lighter
than any round can make it), and the six seam-edge fillets on oracle 60's bolt
holes, whose boundary jumps across the hole.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-14 01:36:30 -04:00
1 parent 482abb4562
commit 813bee8914
6 files changed
+202 -13

No files matched your search

+10 -10
View File
@@ -3666,20 +3666,20 @@
"Box/F2:side:l1|F2:side:l4~1": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l1|F2:side:l4~2": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l1|F2:start": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l1|F2:top": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l1|F2:top": "edge.axis edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l2": "face.angle_plane face.draft_neutral face.extrude face.hole face.midplane face.offset_plane face.press_pull face.shell face.sketch",
"Box/F2:side:l2|F2:side:l3~1": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l2|F2:side:l3~2": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l2|F2:start": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l2|F2:top": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l2|F2:top": "edge.axis edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l3": "face.angle_plane face.draft_neutral face.extrude face.hole face.midplane face.offset_plane face.press_pull face.shell face.sketch",
"Box/F2:side:l3|F2:side:l4~1": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l3|F2:side:l4~2": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l3|F2:start": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l3|F2:top": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l3|F2:top": "edge.axis edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l4": "face.angle_plane face.draft_neutral face.extrude face.hole face.midplane face.offset_plane face.press_pull face.shell face.sketch",
"Box/F2:side:l4|F2:start": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l4|F2:top": "edge.axis edge.chamfer edge.fillet edge.normal_plane edge.project",
"Box/F2:side:l4|F2:top": "edge.axis edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Box/F2:start": "face.angle_plane face.draft_neutral face.extrude face.hole face.midplane face.offset_plane face.press_pull face.shell face.sketch",
"Box/F2:top": "face.angle_plane face.draft_neutral face.extrude face.hole face.midplane face.offset_plane face.press_pull face.shell face.sketch",
"Box/F2:top|F3:inner:F2:side:l1": "edge.axis edge.chamfer !edge.fillet edge.normal_plane edge.project",
@@ -7698,9 +7698,9 @@
},
"oracle/60-pipe-flange": {
"Flange/F2:side:l1": "face.extrude face.hole face.midplane face.offset_plane face.press_pull face.shell face.sketch",
"Flange/F2:side:l1|F2:side:l2#1": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l2#2": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l2#3": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l2#1": "edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l2#2": "edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l2#3": "edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l6#1": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l6#2": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F2:side:l6#3": "edge.chamfer edge.fillet edge.normal_plane edge.project",
@@ -7721,11 +7721,11 @@
"Flange/F2:side:l1|F4:side:[email protected]#1": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l1|F4:side:[email protected]#2": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l2#1": "curved.axis curved.tangent_plane",
"Flange/F2:side:l2#1|F2:side:l3": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l2#1|F2:side:l3": "edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l2#2": "curved.axis curved.tangent_plane",
"Flange/F2:side:l2#2|F2:side:l3": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l2#2|F2:side:l3": "edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l2#3": "curved.axis curved.tangent_plane",
"Flange/F2:side:l2#3|F2:side:l3": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l2#3|F2:side:l3": "edge.chamfer !edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l3": "face.extrude face.hole face.offset_plane face.press_pull !face.shell face.sketch",
"Flange/F2:side:l3|F4:side:c1#1": "edge.chamfer edge.fillet edge.normal_plane edge.project",
"Flange/F2:side:l3|F4:side:c1#2": "edge.chamfer edge.fillet edge.normal_plane edge.project",