classify function
The joint at self's end k among others, in this order (spec 07 D4):
- T — the end lies within
wallJoin.linearof another centreline, strictly inside it (more thanwallJoin.linearfrom both of its ends). Several: the lowest handle. - Node (Ruling 07-3) — the candidates are this end and every other
wall's end within
wallJoin.linearof it; the anchor is the lowest(handle, end index)among them; the members are every end, this wall's included, withinwallJoin.linearof the anchor's endpoint. Every member computes the same set whenever the lowest end is withinwallJoin.linearof all the others; a wider cluster, which snapping never produces, can compute differing sets (ends at 0, 0.9 and 1.8 ×wallJoin.linearin handle order: the first two see two members, the third sees three). Ends sharing a direction with another member keep free caps and the node is built from the rest (Ruling 07-4); fewer than two left is no node. - Free otherwise.
self must not be degenerate. Degenerate walls in others, and self
itself if listed, are ignored.
Implementation
Joint classify(WorldWall self, int k, List<WorldWall> others) {
final p = self.endpoint(k);
final walls = [
for (final o in others)
if (o.handle != self.handle && !o.degenerate) o,
];
WorldWall? through;
for (final o in walls) {
if (!strictlyInside(p, o)) continue;
if (through == null || o.handle.value < through.handle.value) through = o;
}
if (through != null) return Tee(through);
var anchor = self;
var anchorK = k;
for (final o in walls) {
for (final m in const [0, 1]) {
if (_joined(o.endpoint(m), p) && _lower(o, m, anchor, anchorK)) {
anchor = o;
anchorK = m;
}
}
}
final at = anchor.endpoint(anchorK);
final members = <End>[
for (final w in [self, ...walls])
for (final m in const [0, 1])
if (_joined(w.endpoint(m), at)) End(w, m),
];
final ends = [
for (final x in members)
if (!members.any((y) => !identical(x, y) && _sameDirection(x, y))) x,
];
if (ends.length < 2 ||
!ends.any((x) => x.wall.handle == self.handle && x.k == k)) {
return const Free();
}
ends.sort((x, y) {
final c = x.angle.compareTo(y.angle);
return c != 0 ? c : _byHandleThenEnd(x, y);
});
final handles = {for (final x in members) x.wall.handle.value}.toList()
..sort();
return NodeJoint(ends, [for (final h in handles) Handle(h)]);
}