discontinuedPackage jet_cad_floor_plan has been discontinued and replaced by jet_cad_2d_plan.

classify function

Joint classify(
  1. WorldWall self,
  2. int k,
  3. List<WorldWall> others
)

The joint at self's end k among others, in this order (spec 07 D4):

  1. T — the end lies within wallJoin.linear of another centreline, strictly inside it (more than wallJoin.linear from both of its ends). Several: the lowest handle.
  2. Node (Ruling 07-3) — the candidates are this end and every other wall's end within wallJoin.linear of it; the anchor is the lowest (handle, end index) among them; the members are every end, this wall's included, within wallJoin.linear of the anchor's endpoint. Every member computes the same set whenever the lowest end is within wallJoin.linear of all the others; a wider cluster, which snapping never produces, can compute differing sets (ends at 0, 0.9 and 1.8 × wallJoin.linear in 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.
  3. 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)]);
}