import type { MovementDetailKind } from '../data/movement-interior-styles'; /** * Even bay centres along the depth axis — same formula as historic `useBayZ`. * Pure (no React) so hang layout can reserve the same Z as period columns. */ export function bayPositions(depth: number, halfD: number, spacing = 4.2, max = 9): number[] { const count = Math.max(2, Math.min(max, Math.floor(depth / spacing))); const step = depth / (count + 1); return Array.from({ length: count }, (_, i) => -halfD + step * (i + 1)); } export type SideColumnRhythm = { /** Bay spacing passed to bayPositions (matches the period module). */ spacing: number; max: number; /** * Half-width along the wall (Z) of the keep-out around each bay centre. * Covers shaft/base/capital plus a small gap so frames do not kiss the column. */ halfClear: number; }; /** * Mid-wall vertical members that share the hang line on left/right walls. * Corner-only orders are omitted — WALL_PADDING already clears the pockets. */ export const SIDE_WALL_COLUMN_RHYTHMS = { gothic: { spacing: 4.2, max: 9, halfClear: 0.42 }, roman: { spacing: 4.0, max: 9, halfClear: 0.3 }, quattrocento: { spacing: 3.8, max: 9, halfClear: 0.34 }, // Paired pilasters sit at bay±0.19 with r≈0.11 cinquecento: { spacing: 5.2, max: 6, halfClear: 0.44 }, mannerist: { spacing: 4.8, max: 6, halfClear: 0.36 }, neoclassical: { spacing: 4.8, max: 6, halfClear: 0.3 }, 'gothic-revival': { spacing: 3.8, max: 8, halfClear: 0.24 }, 'art-nouveau': { spacing: 3.0, max: 10, halfClear: 0.22 }, } as const satisfies Partial>; export type SideColumnDetailKind = keyof typeof SIDE_WALL_COLUMN_RHYTHMS; export function sideColumnRhythm(details: MovementDetailKind | undefined): SideColumnRhythm | null { if (!details) return null; return (SIDE_WALL_COLUMN_RHYTHMS as Partial>)[details] ?? null; } /** Merged [z0, z1] intervals that side-wall paintings (and windows) must avoid. */ export function sideColumnKeepOutIntervals( details: MovementDetailKind | undefined, depth: number, halfD: number ): [number, number][] { const rhythm = sideColumnRhythm(details); if (!rhythm) return []; return bayPositions(depth, halfD, rhythm.spacing, rhythm.max).map( (z) => [z - rhythm.halfClear, z + rhythm.halfClear] as [number, number] ); }