pub fn resolve_face_crossing(
solid: &BrepSolid,
) -> Result<BrepSolid, KernelRefusal>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.rsowns 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.