{"version":3,"file":"floorPlan.path.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.path.ts"],"sourcesContent":["/**\n * Turns walls into SVG path data for the two-pass thick-wall rendering.\n *\n * The trick: both passes stroke the SAME path data, the outline pass at `thickness` and\n * the fill pass at `thickness - 2 * outlineWidth`. The visible outline is not drawn at\n * all, it is what is left of the outline pass after the fill pass covers its middle.\n * That is why the two must never diverge, and why every outline path has to be drawn\n * before every fill path (one `<g>` each, never interleaved pairs).\n *\n * Three things do not fall out of that trick and are handled explicitly:\n *\n * 1. Nothing is ever drawn across a butt end, because there both passes terminate at\n *    the same coordinate. Openings and free ends therefore need explicit cap lines.\n * 2. Two butt-capped walls meeting at an angle leave an uncovered notch at the outer\n *    corner. Walls are emitted as CHAINS through degree-2 nodes so `stroke-linejoin`\n *    miters the corner, and where a chain has to stop, `reflexCornerStubs` mitres the\n *    one corner a junction cannot close by itself.\n * 3. Where two walls of different thickness meet end to end, the drawing steps from\n *    thick fill straight to background with no edge, so that joint needs a cap too.\n */\n\nimport { nodeDegrees } from './floorPlan.faces';\nimport { dist } from './floorPlan.geometry';\nimport type { PlanFloor, PlanOpening, PlanPoint, PlanWall } from './floorPlan.types';\n\nexport interface WallPathGroup {\n  /** Millimetres. The stroke width for the outline pass. */\n  thickness: number;\n  /**\n   * Path data, to be handed VERBATIM to both passes. The outline pass strokes it at\n   * `thickness`, the fill pass at `thickness - 2 * outlineWidth`.\n   */\n  d: string;\n}\n\nexport type WallCapReason = 'jamb' | 'freeEnd' | 'thicknessStep';\n\nexport interface WallCapLine {\n  a: PlanPoint;\n  b: PlanPoint;\n  reason: WallCapReason;\n  wallId: string;\n}\n\nexport interface WallPathResult {\n  /** Render every group's outline first, then every group's fill. */\n  groups: WallPathGroup[];\n  /** Drawn last, in the outline colour, at the outline width. */\n  caps: WallCapLine[];\n}\n\nexport interface BuildWallPathsOptions {\n  /**\n   * Build paths for only these walls, as if the rest were not drawn.\n   *\n   * Node degrees still come from the WHOLE floor, so chains break and corners are filled\n   * exactly where they are for the real walls. That is what lets a subset be painted over\n   * the top of the full drawing and land on it precisely: a highlight of a room's\n   * boundary is the same geometry as the walls themselves, openings and all.\n   */\n  wallIds?: ReadonlySet<string>;\n  /** Cap the free end of a wall that stops in mid-air. Default true. */\n  capFreeEnds?: boolean;\n  /** Cap the joint where two walls of different thickness meet. Default true. */\n  capThicknessSteps?: boolean;\n}\n\nconst EPS = 1e-6;\n\nfunction lerpPoint(a: PlanPoint, b: PlanPoint, t: number): PlanPoint {\n  return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };\n}\n\nfunction fmt(n: number): string {\n  return Number.isInteger(n) ? String(n) : n.toFixed(3).replace(/\\.?0+$/, '');\n}\n\nfunction samePoint(a: PlanPoint, b: PlanPoint): boolean {\n  return Math.abs(a.x - b.x) < 0.001 && Math.abs(a.y - b.y) < 0.001;\n}\n\n/**\n * The parts of a wall's centreline that are actually wall, as `[start, end]` offsets in\n * millimetres from node `a`.\n *\n * Overlapping openings merge into one gap; an opening reaching an end removes that span\n * entirely. An empty result means the opening spans the whole wall.\n */\nexport function wallCentrelineSpans(floor: PlanFloor, wall: PlanWall): Array<[number, number]> {\n  const a = floor.nodes[wall.a];\n  const b = floor.nodes[wall.b];\n  if (!a || !b) return [];\n  const len = dist(a, b);\n  if (len < EPS) return [];\n\n  const gaps: Array<[number, number]> = [];\n  for (const opening of Object.values(floor.openings)) {\n    if (opening.wallId !== wall.id) continue;\n    const half = opening.width / 2;\n    const start = Math.max(0, opening.offset - half);\n    const end = Math.min(len, opening.offset + half);\n    if (end > start) gaps.push([start, end]);\n  }\n  if (gaps.length === 0) return [[0, len]];\n\n  gaps.sort((x, y) => x[0] - y[0]);\n  const merged: Array<[number, number]> = [gaps[0]];\n  for (let i = 1; i < gaps.length; i++) {\n    const last = merged[merged.length - 1];\n    if (gaps[i][0] <= last[1]) last[1] = Math.max(last[1], gaps[i][1]);\n    else merged.push(gaps[i]);\n  }\n\n  const spans: Array<[number, number]> = [];\n  let cursor = 0;\n  for (const [start, end] of merged) {\n    if (start - cursor > EPS) spans.push([cursor, start]);\n    cursor = end;\n  }\n  if (len - cursor > EPS) spans.push([cursor, len]);\n  return spans;\n}\n\n/** Everything a renderer needs to draw a door leaf, swing arc or window symbol. */\nexport function openingGeometry(\n  floor: PlanFloor,\n  opening: PlanOpening,\n): { centre: PlanPoint; dir: PlanPoint; normal: PlanPoint; p1: PlanPoint; p2: PlanPoint } | null {\n  const wall = floor.walls[opening.wallId];\n  if (!wall) return null;\n  const a = floor.nodes[wall.a];\n  const b = floor.nodes[wall.b];\n  if (!a || !b) return null;\n  const len = dist(a, b);\n  if (len < EPS) return null;\n\n  const dir = { x: (b.x - a.x) / len, y: (b.y - a.y) / len };\n  const normal = { x: -dir.y, y: dir.x };\n  const half = Math.min(opening.width / 2, len / 2);\n  const offset = Math.min(Math.max(opening.offset, half), len - half);\n  const centre = { x: a.x + dir.x * offset, y: a.y + dir.y * offset };\n\n  return {\n    centre,\n    dir,\n    normal,\n    p1: { x: centre.x - dir.x * half, y: centre.y - dir.y * half },\n    p2: { x: centre.x + dir.x * half, y: centre.y + dir.y * half },\n  };\n}\n\n/** One directed step along a chain. */\ninterface Step {\n  wall: PlanWall;\n  from: string;\n  to: string;\n}\n\n/**\n * Maximal runs of same-thickness walls joined through degree-2 nodes.\n *\n * A chain may only continue through a node whose TOTAL degree is 2 and whose two walls\n * share a thickness: a different stroke width means a different path, and a degree-3+\n * node is a junction rather than a corner.\n */\nfunction buildChains(floor: PlanFloor, walls: PlanWall[], degrees: Map<string, number>): Step[][] {\n  const byId = new Map(walls.map((w) => [w.id, w]));\n  const atNode = new Map<string, PlanWall[]>();\n  for (const wall of walls) {\n    for (const nodeId of [wall.a, wall.b]) {\n      const list = atNode.get(nodeId);\n      if (list) list.push(wall);\n      else atNode.set(nodeId, [wall]);\n    }\n  }\n\n  const continuesThrough = (nodeId: string): PlanWall[] | null => {\n    if ((degrees.get(nodeId) ?? 0) !== 2) return null;\n    const here = atNode.get(nodeId);\n    // Both walls must be in this thickness group, or the chain has to break here.\n    if (!here || here.length !== 2) return null;\n    return here;\n  };\n\n  const used = new Set<string>();\n  const chains: Step[][] = [];\n\n  const other = (wall: PlanWall, nodeId: string): string => (wall.a === nodeId ? wall.b : wall.a);\n\n  for (const wall of walls) {\n    if (used.has(wall.id)) continue;\n\n    // Walk backwards to the start of the run, unless it closes on itself.\n    let startWall = wall;\n    let startNode = wall.a;\n    const seenBack = new Set<string>([wall.id]);\n    for (;;) {\n      const pair = continuesThrough(startNode);\n      if (!pair) break;\n      const prev = pair[0].id === startWall.id ? pair[1] : pair[0];\n      if (seenBack.has(prev.id)) break; // closed loop\n      seenBack.add(prev.id);\n      startWall = prev;\n      startNode = other(prev, startNode);\n    }\n\n    // Walk forwards, collecting directed steps.\n    const steps: Step[] = [];\n    let current = startWall;\n    let from = startNode;\n    for (;;) {\n      if (used.has(current.id)) break;\n      used.add(current.id);\n      const to = other(current, from);\n      steps.push({ wall: current, from, to });\n      const pair = continuesThrough(to);\n      if (!pair) break;\n      const next = pair[0].id === current.id ? pair[1] : pair[0];\n      if (used.has(next.id)) break;\n      current = next;\n      from = to;\n      if (!byId.has(current.id)) break;\n    }\n\n    if (steps.length > 0) chains.push(steps);\n  }\n\n  return chains;\n}\n\n/**\n * The outer corner of the one REFLEX gap at a node, as a two-legged stub.\n *\n * A chain's `stroke-linejoin` mitres the corner wherever a wall bends, but a chain has\n * to stop at a junction, and at a thickness change, so something else has to close the\n * corner there. Most junction corners need nothing: where the angular gap between two\n * neighbouring walls is at most 180 degrees, the two bands reach across it and already\n * meet at the mitre point, because both start AT the node rather than short of it.\n *\n * A gap WIDER than 180 degrees is the exception, and it is the only one. There the two\n * faces bounding the gap diverge instead of crossing, so nothing spans the gap and what\n * is left between the two butt ends is an open wedge biting into the node. It shows up\n * whenever every wall at a node points into the same half-plane: a wall running east, a\n * wall running north, and a third splitting the two leaves a quarter-circle bitten out\n * of the south-west side. Because the gaps around a node sum to 360 degrees, at most\n * one can be reflex, so a node never needs more than one of these.\n *\n * The stub is two legs laid back along the two walls bounding that gap. Stroked at the\n * wall thickness it stays within their own bands, adding nothing anywhere else, and its\n * mitre join fills the wedge and bevels under the same `stroke-miterlimit` as every\n * other corner. Filling every gap this way instead of only the reflex one is what used\n * to fire spikes out of narrow junctions: those gaps had nothing to fill, so the join\n * ran outside the walls, the further the tighter the angle.\n */\nfunction reflexCornerStubs(\n  floor: PlanFloor,\n  walls: PlanWall[],\n  degrees: Map<string, number>,\n): Array<{ thickness: number; d: string }> {\n  interface Arm {\n    wall: PlanWall;\n    dir: PlanPoint;\n    angle: number;\n    /** Millimetres of wall between the node and the first opening, if any. */\n    reach: number;\n  }\n\n  const armsAt = new Map<string, Arm[]>();\n  const addArm = (nodeId: string, arm: Arm) => {\n    const list = armsAt.get(nodeId);\n    if (list) list.push(arm);\n    else armsAt.set(nodeId, [arm]);\n  };\n\n  for (const wall of walls) {\n    const a = floor.nodes[wall.a];\n    const b = floor.nodes[wall.b];\n    const len = dist(a, b);\n    if (len < EPS) continue;\n    const spans = wallCentrelineSpans(floor, wall);\n    if (spans.length === 0) continue;\n\n    const dir = { x: (b.x - a.x) / len, y: (b.y - a.y) / len };\n    const first = spans[0];\n    const last = spans[spans.length - 1];\n    addArm(wall.a, {\n      wall,\n      dir,\n      angle: Math.atan2(dir.y, dir.x),\n      reach: first[0] < EPS ? first[1] : 0,\n    });\n    addArm(wall.b, {\n      wall,\n      dir: { x: -dir.x, y: -dir.y },\n      angle: Math.atan2(-dir.y, -dir.x),\n      reach: last[1] > len - EPS ? len - last[0] : 0,\n    });\n  }\n\n  const stubs: Array<{ thickness: number; d: string }> = [];\n  const TAU = Math.PI * 2;\n\n  for (const [nodeId, arms] of armsAt) {\n    if (arms.length < 2) continue;\n    /*\n     * A chain runs straight through a plain corner, and its own join closes it. The test\n     * has to be the one `buildChains` uses, which reads the degree of the node in the\n     * WHOLE floor: drawing a subset of the walls, two arms at a T junction look like a\n     * corner but the chain still breaks there, and skipping the fill left a notch bitten\n     * out of the join.\n     */\n    const chainRunsThrough =\n      (degrees.get(nodeId) ?? 0) === 2 && arms.length === 2 && arms[0].wall.thickness === arms[1].wall.thickness;\n    if (chainRunsThrough) continue;\n\n    arms.sort((p, q) => p.angle - q.angle);\n\n    let widest = 0;\n    let widestGap = -1;\n    for (let i = 0; i < arms.length; i++) {\n      const next = arms[(i + 1) % arms.length];\n      const gap = i === arms.length - 1 ? next.angle + TAU - arms[i].angle : next.angle - arms[i].angle;\n      if (gap > widestGap) {\n        widestGap = gap;\n        widest = i;\n      }\n    }\n    if (widestGap <= Math.PI + EPS) continue;\n\n    const from = arms[widest];\n    const to = arms[(widest + 1) % arms.length];\n    // The thinner of the two, so the stub can never bulge out past the thinner wall.\n    const thickness = Math.min(from.wall.thickness, to.wall.thickness);\n    // Half a thickness of leg is enough to carry the join, and an opening close to the\n    // node shortens it so the stub cannot paint across the jamb.\n    const legFrom = Math.min(thickness / 2, from.reach);\n    const legTo = Math.min(thickness / 2, to.reach);\n    if (legFrom < EPS || legTo < EPS) continue;\n\n    const node = floor.nodes[nodeId];\n    stubs.push({\n      thickness,\n      d:\n        `M ${fmt(node.x + from.dir.x * legFrom)},${fmt(node.y + from.dir.y * legFrom)}` +\n        ` L ${fmt(node.x)},${fmt(node.y)}` +\n        ` L ${fmt(node.x + to.dir.x * legTo)},${fmt(node.y + to.dir.y * legTo)}`,\n    });\n  }\n\n  return stubs;\n}\n\n/**\n * Builds the stroke path data for every wall, grouped by thickness, plus the cap lines\n * the two-pass trick cannot produce on its own.\n */\nexport function buildWallPaths(floor: PlanFloor, options: BuildWallPathsOptions = {}): WallPathResult {\n  const { wallIds, capFreeEnds = true, capThicknessSteps = true } = options;\n\n  const walls = Object.values(floor.walls).filter((w) => {\n    if (wallIds && !wallIds.has(w.id)) return false;\n    const a = floor.nodes[w.a];\n    const b = floor.nodes[w.b];\n    return a && b && dist(a, b) > EPS && w.a !== w.b;\n  });\n  if (walls.length === 0) return { groups: [], caps: [] };\n\n  const degrees = nodeDegrees(floor);\n  const caps: WallCapLine[] = [];\n\n  // ── Group by thickness: one stroke width per path. ────────────────────────────\n  const byThickness = new Map<number, PlanWall[]>();\n  for (const wall of walls) {\n    const list = byThickness.get(wall.thickness);\n    if (list) list.push(wall);\n    else byThickness.set(wall.thickness, [wall]);\n  }\n\n  const subpathsByThickness = new Map<number, string[]>();\n  const pushSubpath = (thickness: number, d: string) => {\n    const list = subpathsByThickness.get(thickness);\n    if (list) list.push(d);\n    else subpathsByThickness.set(thickness, [d]);\n  };\n\n  for (const [thickness, groupWalls] of byThickness) {\n    for (const chain of buildChains(floor, groupWalls, degrees)) {\n      let current: PlanPoint[] = [];\n      const flush = () => {\n        if (current.length >= 2) {\n          pushSubpath(thickness, current.map((p, i) => `${i === 0 ? 'M' : 'L'} ${fmt(p.x)},${fmt(p.y)}`).join(' '));\n        }\n        current = [];\n      };\n\n      for (const step of chain) {\n        const a = floor.nodes[step.from];\n        const b = floor.nodes[step.to];\n        const len = dist(a, b);\n        if (len < EPS) continue;\n\n        // Spans come back in the wall's own a->b direction; flip them when the chain\n        // traverses the wall the other way.\n        let spans = wallCentrelineSpans(floor, step.wall);\n        if (step.from !== step.wall.a) {\n          spans = spans.map(([s, e]) => [len - e, len - s] as [number, number]).reverse();\n        }\n\n        for (const [s, e] of spans) {\n          const p1 = lerpPoint(a, b, s / len);\n          const p2 = lerpPoint(a, b, e / len);\n          if (current.length > 0 && samePoint(current[current.length - 1], p1)) {\n            current.push(p2);\n          } else {\n            flush();\n            current = [p1, p2];\n          }\n        }\n        // An opening reaching the far end leaves nothing to continue from.\n        if (spans.length === 0 || spans[spans.length - 1][1] < len - EPS) flush();\n      }\n\n      // A chain that returns to where it started closes properly, so the final corner\n      // gets a miter join like every other corner rather than two butt caps.\n      const first = chain[0];\n      const last = chain[chain.length - 1];\n      const closed = first.from === last.to;\n      if (closed && current.length >= 3 && samePoint(current[0], current[current.length - 1])) {\n        const ring = current.slice(0, -1);\n        pushSubpath(thickness, `${ring.map((p, i) => `${i === 0 ? 'M' : 'L'} ${fmt(p.x)},${fmt(p.y)}`).join(' ')} Z`);\n        current = [];\n      } else {\n        flush();\n      }\n    }\n  }\n\n  for (const stub of reflexCornerStubs(floor, walls, degrees)) pushSubpath(stub.thickness, stub.d);\n\n  // ── Caps. ─────────────────────────────────────────────────────────────────────\n  const capAt = (wall: PlanWall, offset: number, reason: WallCapReason) => {\n    const a = floor.nodes[wall.a];\n    const b = floor.nodes[wall.b];\n    const len = dist(a, b);\n    if (len < EPS) return;\n    const dir = { x: (b.x - a.x) / len, y: (b.y - a.y) / len };\n    const normal = { x: -dir.y, y: dir.x };\n    const centre = { x: a.x + dir.x * offset, y: a.y + dir.y * offset };\n    const half = wall.thickness / 2;\n    caps.push({\n      a: { x: centre.x - normal.x * half, y: centre.y - normal.y * half },\n      b: { x: centre.x + normal.x * half, y: centre.y + normal.y * half },\n      reason,\n      wallId: wall.id,\n    });\n  };\n\n  for (const wall of walls) {\n    const a = floor.nodes[wall.a];\n    const b = floor.nodes[wall.b];\n    const len = dist(a, b);\n    for (const [s, e] of wallCentrelineSpans(floor, wall)) {\n      if (s > EPS) capAt(wall, s, 'jamb');\n      else if (capFreeEnds && (degrees.get(wall.a) ?? 0) === 1) capAt(wall, 0, 'freeEnd');\n\n      if (e < len - EPS) capAt(wall, e, 'jamb');\n      else if (capFreeEnds && (degrees.get(wall.b) ?? 0) === 1) capAt(wall, len, 'freeEnd');\n    }\n  }\n\n  if (capThicknessSteps) {\n    const atNode = new Map<string, PlanWall[]>();\n    for (const wall of walls) {\n      for (const nodeId of [wall.a, wall.b]) {\n        const list = atNode.get(nodeId);\n        if (list) list.push(wall);\n        else atNode.set(nodeId, [wall]);\n      }\n    }\n    for (const [nodeId, incident] of atNode) {\n      if (incident.length !== 2) continue;\n      const [w1, w2] = incident;\n      if (w1.thickness === w2.thickness) continue;\n      // Draw the thicker wall's full cross-section. It overdraws a line across the\n      // thinner wall's interior, which is the usual CAD convention for a joint between\n      // two wall constructions, and far better than leaving no edge at all.\n      const thicker = w1.thickness >= w2.thickness ? w1 : w2;\n      const offset = thicker.a === nodeId ? 0 : dist(floor.nodes[thicker.a], floor.nodes[thicker.b]);\n      capAt(thicker, offset, 'thicknessStep');\n    }\n  }\n\n  const groups: WallPathGroup[] = [...subpathsByThickness.entries()]\n    .sort((x, y) => x[0] - y[0])\n    .map(([thickness, subpaths]) => ({ thickness, d: subpaths.join(' ') }));\n\n  return { groups, caps };\n}\n"],"mappings":"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"}