cutsOf function
Where each of one host's openings cuts, and the host's merged cuts (spec
08 D8). openings are (centre, width) in ascending handle order;
stretches and frame are the host's.
Each opening is placed on its own (placeCut): no opening's placement
depends on another's. Then the admission (D8 as amended at
execution, revised after Task 5's review and the final review's I1):
the fitting openings are admitted in ascending handle order; each one's
cut is added to the admitted cuts and merged (mergeCuts), and this
opening is made no-fit and left out when that would leave frame
- no piece longer than
wallJoin.linear(a cut spanning the whole span, cuts covering it together, or cuts leaving only slivers): a wall keeps a piece; or - a piece that is not valid (isValidPiece: simple, anticlockwise and triangulable, the engine's own region check): an opening clamped against a slightly kinked joint can leave an end piece that is a sliver of the cap's lobe, and storing a piece the engine refuses would refuse the whole edit.
Otherwise it is kept. So a cut wall always generates a piece, every piece it generates is one the engine accepts, the outcome is deterministic, and an opening yields only when admitting it is what would empty the wall or leave it a piece it cannot store.
cuts[i] is null when opening i does not fit, from the start or by
that rule; merged is the admitted cuts merged, empty when nothing cuts
the host.
Implementation
({List<Cut?> cuts, List<(double, double)> merged}) cutsOf(HostFrame frame,
List<(double, double)> stretches, List<(double, double)> openings) {
final cuts = [for (final (c, w) in openings) placeCut(stretches, c, w)];
final admitted = <(double, double)>[];
var merged = const <(double, double)>[];
// A piece's ring is a function of its span on [frame], so a span judged
// valid once is not triangulated again by a later trial.
final valid = <(double, double)>{};
bool ok(_Piece p) {
if (valid.contains(p.span)) return true;
if (!isValidPiece(p.ring)) return false;
valid.add(p.span);
return true;
}
for (var i = 0; i < cuts.length; i++) {
final c = cuts[i];
if (c == null) continue;
final trial = mergeCuts([...admitted, (c.a, c.b)]);
final pieces = _pieces(frame, trial);
if (pieces.isEmpty || !pieces.every(ok)) {
cuts[i] = null;
} else {
admitted.add((c.a, c.b));
merged = trial;
}
}
return (cuts: cuts, merged: merged);
}