symbolOf function
Opening o's symbol (spec 08 D10, D11), computed in its host's local
space on the host's frame f and taken to the opening's own local space
by toOwn, which is toWorld(self)⁻¹ · toWorld(host): host-local →
world → own local. Every child is ByLayer, Generated's default.
cut is the opening's cut (D8); the symbol is drawn over [x₁, x₂],
the cut's interval. Null means no-fit (D11): the symbol is drawn over
the stored interval [c − w/2, c + w/2], never over the band.
- door (a LINE, then an ARC): the hinge
His the jamb corner on the swing-side face atx₁(hingestart) orx₂(hingeend); the leaf runs fromHperpendicular to the wall, away from the band,wlong; the swing is the quarter arc aboutHof radiuswbetween the leaf's tip and the shut jamb (the other jamb on the same face), a sweep of +π/2, starting at whichever of the two makes it anticlockwise. A no-fit door is drawn the same way: its symbol lies outside the band already; - window (three LINEs, in order): the left face, the midline
(lOff + rOff)/2and the right face, fromx₁tox₂. No-fit, each is translated by the thicknesstalong the left normal: offsetslOff + t,lOff + t/2andlOff; - gap (one LINE): the threshold line on the centreline (offset 0)
from
x₁ + mtox₂ − m,m = min(t/4, w/4). No-fit, at offsetlOff + t/2.
o must not be degenerate (D6): it generates nothing.
Implementation
List<Generated> symbolOf(
HostFrame f, OpeningParams o, Cut? cut, Transform2 toOwn) {
final w = o.width;
final fits = cut != null;
final x1 = fits ? cut.a : o.position - w / 2;
final x2 = fits ? cut.b : o.position + w / 2;
final t = f.lOff - f.rOff;
Vector2 own(double u, double off) => toOwn.transformPoint(f.at(u, off));
Generated line(double u1, double u2, double off) =>
Generated(EntityKind.line, linePayload(own(u1, off), own(u2, off)));
switch (o.kind) {
case OpeningKind.door:
final (uh, us) = o.hinge == HingeEnd.start ? (x1, x2) : (x2, x1);
final (face, out) =
o.swing == SwingSide.left ? (f.lOff, w) : (f.rOff, -w);
final hinge = own(uh, face);
final tip = own(uh, face + out);
final shut = own(us, face);
final toTip = tip - hinge, toShut = shut - hinge;
final ccw = toTip.x * toShut.y - toTip.y * toShut.x > 0;
final from = ccw ? toTip : toShut;
return [
Generated(EntityKind.line, linePayload(hinge, tip)),
Generated(
EntityKind.arc,
arcPayload(
hinge, toTip.length, math.atan2(from.y, from.x), math.pi / 2)),
];
case OpeningKind.window:
final offsets = fits
? [f.lOff, (f.lOff + f.rOff) / 2, f.rOff]
: [f.lOff + t, f.lOff + t / 2, f.lOff];
return [for (final off in offsets) line(x1, x2, off)];
case OpeningKind.gap:
final m = math.min(t / 4, w / 4);
return [line(x1 + m, x2 - m, fits ? 0 : f.lOff + t / 2)];
}
}