outline function
A wall's world outline: an anticlockwise ring, end cap then start cap (spec 07 D5, D6).
ringis empty for a degenerate wall (D2).fellBackis true when the joined ring was not simple and anticlockwise, so this wall alone squared both ends at its own endpoints (D6's short wall). Its neighbours are unaffected: squaring them too would make them depend on each other through this wall, a two-hop dependency 06's closure does not regenerate.holelists the node's member walls (Ruling 07-3), ascending, when a crossing lobe of positive area was dropped at one of this wall's ends and this wall owns that lobe (D5.6, D12: reported once, by the owner). If both ends own one, it lists both nodes' members, ascending, once each.
The ring is simplified (D6): exact consecutive duplicates and zero-width spikes, which do occur (a closing duplicate at some right-angle Ls of round sizes), are removed. No measured triangulation outcome has depended on it, since lobes split at exactly repeated vertices and the triangulator tolerates consecutive duplicates; it stays as D6's guard.
fallback false returns the joined ring even when it is not simple — a
measurement hook, never used to store an outline.
Implementation
({List<Vector2> ring, bool fellBack, List<Handle>? hole}) outline(
WorldWall w, List<WorldWall> others,
{bool fallback = true}) {
if (w.degenerate) {
return (ring: const <Vector2>[], fellBack: false, hole: null);
}
final je = classify(w, 1, others), js = classify(w, 0, others);
final ce = cap(End(w, 1), je), cs = cap(End(w, 0), js);
final owned = <int>{
if (ce.ownsHole)
for (final h in (je as NodeJoint).members) h.value,
if (cs.ownsHole)
for (final h in (js as NodeJoint).members) h.value,
}.toList()
..sort();
final hole = owned.isEmpty ? null : [for (final h in owned) Handle(h)];
final ring = simplifyRing([...ce.points, ...cs.points]);
if (fallback && !isSimpleCcw(ring)) {
return (
ring: [
...cap(End(w, 1), const Free()).points,
...cap(End(w, 0), const Free()).points,
],
fellBack: true,
hole: hole,
);
}
return (ring: ring, fellBack: false, hole: hole);
}