74 lines
2.1 KiB
TypeScript

import type { FloorplanGeometry, FloorplanPoint, GeometryContext } from '@pascal-app/core'
import { terminalSystem } from './ports'
import type { DuctTerminalNode } from './schema'
const SUPPLY_COLOR = '#d4825a'
const RETURN_COLOR = '#5a8ad4'
const FRAME_STROKE = '#6b7280'
const FACE_FILL = '#e5e7eb'
/**
* Floor-plan symbol for a duct terminal: the face rectangle (rotated by
* yaw) with the conventional register cross-slats hinted as a single
* mid-line, tinted by system. Wall mounts render the same footprint —
* the face projects to a thin strip, which is close enough for plan
* reading at this stage.
*/
export function buildDuctTerminalFloorplan(
node: DuctTerminalNode,
ctx: GeometryContext,
): FloorplanGeometry | null {
const [cx, , cz] = node.position
const cos = Math.cos(node.rotation)
const sin = Math.sin(node.rotation)
const hw = node.width / 2
const hd = (node.mount === 'wall' ? 0.06 : node.depth) / 2
const corner = (lx: number, lz: number): FloorplanPoint => [
cx + lx * cos + lz * sin,
cz - lx * sin + lz * cos,
]
const points: FloorplanPoint[] = [
corner(-hw, -hd),
corner(hw, -hd),
corner(hw, hd),
corner(-hw, hd),
]
const view = ctx.viewState
const palette = view?.palette
const showSelectedChrome = (view?.selected || view?.highlighted) ?? false
const accent = terminalSystem(node) === 'supply' ? SUPPLY_COLOR : RETURN_COLOR
const stroke = showSelectedChrome && palette ? palette.selectedStroke : FRAME_STROKE
const mid1 = corner(-hw * 0.8, 0)
const mid2 = corner(hw * 0.8, 0)
const children: FloorplanGeometry[] = [
{
kind: 'polygon',
points,
fill: FACE_FILL,
stroke,
strokeWidth: showSelectedChrome ? 0.025 : 0.015,
opacity: 0.92,
},
{
kind: 'line',
x1: mid1[0],
y1: mid1[1],
x2: mid2[0],
y2: mid2[1],
stroke: accent,
strokeWidth: 1.5,
vectorEffect: 'non-scaling-stroke',
opacity: 0.9,
},
]
if (showSelectedChrome) {
children.push({ kind: 'move-handle', point: [cx, cz] })
}
return { kind: 'group', children }
}