74 lines
2.1 KiB
TypeScript
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 }
|
|
}
|