hostFrameOf function
host's frame (spec 08 D7), among walls (any walls; classify skips
host itself, degenerate walls and walls that do not join it). Null
for a degenerate host (07 D2).
The caps are computed in world, as 07's outline is, then taken to the
host's group-local space through host.toWorld.invert() and judged
again there (07's final review I1): a local ring that is not simple and
anticlockwise is replaced by the free caps computed in local space, the
wall at the identity with no neighbours, and the frame falls back.
Implementation
HostFrame? hostFrameOf(WorldWall host, List<WorldWall> walls) {
final caps = capsOf(host, walls);
if (caps == null) return null;
final p = host.params;
final toLocal = host.toWorld.invert();
var ce = [for (final q in caps.endCap) toLocal.transformPoint(q)];
var cs = [for (final q in caps.startCap) toLocal.transformPoint(q)];
var fellBack = caps.fellBack;
if (!isSimpleCcw(simplifyRing([...ce, ...cs]))) {
final free = WorldWall(host.handle, p, Transform2.identity());
ce = cap(End(free, 1), const Free()).points;
cs = cap(End(free, 0), const Free()).points;
fellBack = true;
}
final dv = p.end - p.start;
final (l, r) = host.offsets;
return HostFrame._(
p.start, p.end, dv.normalized(), dv.length, l, r, ce, cs, fellBack);
}