mesh::csg::mesh_csg splits each operand's triangles by the carrier planes of the other's triangles (AABB-localised) and never merges anything back. When operands share large coplanar faces — every prismatic part: all stator operands span z 11.1..17.1 — each boolean in a chain re-splits the accumulated cap triangles again.
Measured on the rana-60 stator: the authored 50-step union fold through the mesh path had not finished after 9 minutes (RSS 1.5 GB and climbing; 16 GB before propagate_boolean was fixed in #890). Even with only one mesh union followed by 8 mesh differences, the part is ~103k triangles where the analytic equivalent is ~14.7k. Related: #879, #822.
Proposal: a pass at the end of mesh_csg that groups kept fragments by carrier plane + connectivity, merges each connected coplanar region into its boundary loops (holes allowed), drops collinear boundary vertices not used by any other-plane triangle (or t-junctions open), and re-triangulates. Must preserve volume, watertightness (keep a region's original triangles if it fails to triangulate cleanly), orientation and determinism. Trap: mesh_fallback runs QuadricCtx::project_mesh, which reads per-vertex constraints off incident triangle normals — restrict the merge to exactly planar regions that are not quadric-projected.
Done when: a 12-step chain (ring, then 12 posts unioned one at a time through mesh_csg) ends within 3× the triangle count of the single-shot union, at the closed-form volume.
Found while getting the rana-60-cnc stator to solve (#890). Helpers ring(), post(), fillet_block(side) live in crates/vcad-kernel-booleans/tests/coplanar_cap_union.rs; assert volume against a closed form in any new test — every failure in this family was a plausible mesh of the wrong solid.
🤖 Filed by Claude Code
mesh::csg::mesh_csgsplits each operand's triangles by the carrier planes of the other's triangles (AABB-localised) and never merges anything back. When operands share large coplanar faces — every prismatic part: all stator operands span z 11.1..17.1 — each boolean in a chain re-splits the accumulated cap triangles again.Measured on the rana-60 stator: the authored 50-step union fold through the mesh path had not finished after 9 minutes (RSS 1.5 GB and climbing; 16 GB before
propagate_booleanwas fixed in #890). Even with only one mesh union followed by 8 mesh differences, the part is ~103k triangles where the analytic equivalent is ~14.7k. Related: #879, #822.Proposal: a pass at the end of
mesh_csgthat groups kept fragments by carrier plane + connectivity, merges each connected coplanar region into its boundary loops (holes allowed), drops collinear boundary vertices not used by any other-plane triangle (or t-junctions open), and re-triangulates. Must preserve volume, watertightness (keep a region's original triangles if it fails to triangulate cleanly), orientation and determinism. Trap:mesh_fallbackrunsQuadricCtx::project_mesh, which reads per-vertex constraints off incident triangle normals — restrict the merge to exactly planar regions that are not quadric-projected.Done when: a 12-step chain (ring, then 12 posts unioned one at a time through
mesh_csg) ends within 3× the triangle count of the single-shot union, at the closed-form volume.Found while getting the rana-60-cnc stator to solve (#890). Helpers
ring(),post(),fillet_block(side)live incrates/vcad-kernel-booleans/tests/coplanar_cap_union.rs; assert volume against a closed form in any new test — every failure in this family was a plausible mesh of the wrong solid.🤖 Filed by Claude Code