Skip to main content

resolve_face_crossing

Function resolve_face_crossing 

Source
pub fn resolve_face_crossing(solid: &BrepSolid) -> Result<BrepSolid, String>
Expand description

Split two faces of ONE body that cross each other along their carriers’ exact intersection, drop the material the crossing encloses, and re-sew.

This is the bounded half of the self-intersection answer. Where two walls of one body overshoot past each other instead of meeting at an edge, the crossing curve IS the edge they should have met at: imprinting it onto both faces cuts each into the part that belongs and the tail that overshot, and dropping both tails leaves a body sewn along that curve.

What it refuses, and why each refusal is a bound rather than a shrug:

  • A FOLD inside one face. There is no second face to imprint against, and the answer is a trim that was never constructed rather than material to drop — offset/carve.rs owns it.
  • More than one crossing pair. Each repair changes the faces the next one would be measured against, so resolving them together is a different problem from resolving one.
  • A crossing whose carriers’ intersection does not cut BOTH trims. Then the mesh crossing is not a curve the faces share and there is nothing to split along.
  • More pieces than [MAXIMUM_CROSSING_PIECES], because every candidate drop is rebuilt in full and the enumeration has to run to the end rather than be sampled.
  • Any split whose reassembly does not come back SOUND. Every way of dropping some pieces of each face — keeping at least one of each — is enumerated, closed under the re-trim, rebuilt and re-checked in full (validate() clean, connected, and scanning clean), so the piece choice is decided by the result rather than guessed from a normal. If none verifies, the solid is returned untouched and the caller refuses: a repair that cannot prove its own answer must not ship one.
  • A split that MORE THAN ONE drop resolves. Two sound answers is not an answer, and choosing between them would be the guess this repair exists not to make.

The re-trim is the other half of the split. Dropping a tail also removes that tail’s boundary uses on the NEIGHBOURING faces it bordered, and a body cannot close over an edge only one face answers for. So the drop is closed under “a face left holding an unmatched boundary goes too” — which, since the imprint already cut those neighbours where the crossing curve met their edges, drops the part of each that the crossing cut off. The closure is bounded by the faces the imprint TOUCHED: reaching any other face ends that candidate. Nothing here edits a loop by hand; every piece it chooses between came out of the imprint/fragment machinery.

And the drop RETIRES what the old configuration left. The touched bound is about material the crossing encloses, and it does not reach the third thing a moved carrier leaves on a body: a piece, or a whole loop, that the NEW configuration has no room for — a bore’s exit ring still recorded on the top face after the exit has migrated onto the side. Neither is material this drop ran past; both are held by nothing the drop keeps, and keeping either cannot close. [fragment_is_detached] retires the one the fragmenter returns as its own island and [holds_only_stale_loops] the one it returns as a hole loop that has left its face, and the ledger says a repair retired something rather than leaving it to be read off the cell counts.

A census has two directions and only one was enforced. An edge used ONCE is a face left holding an unanswered boundary, above. An edge used THREE times is three faces along one curve, which is not a body either, and the assembly does not refuse it — it puts the third face on a shell of its own and every floor in this repository then passes the result. [over_used_edge] refuses that candidate where the third use still exists, which is here. It is what stopped the turned-bore migration returning a body 23% out on area.