import type { BlockModel } from './geometry'; import { integratedCheck, pairEccentricities } from './bearing-layout'; /** * 일체 블록 (승인 2026-10-26): one block per front–back pair, centred on the pair's midpoint. * Length 2500 across the 교축 (n) covers the pair (C1 600 + C2 1298 + C1 600), width 1200 along the 교각축 (s). * The top is stepped: the front half follows the front block top, the back half the back block top (단이 있는 블록). * Only built when every pair is within the eccentricity limit; otherwise the model keeps 분리 (see integratedCheck). */ export const INTEGRATED_BLOCK = { length: 2500, depth: 1200 } as const; export interface IntegratedBlock { frontNo: number; backNo: number; /** Centre along the coping length (s, m) — the mean of the pair. */ s: number; /** Centre across the 교축 (n, m) — the midpoint of the pair; the step line is here. */ n: number; /** Bottom EL (m): the lower of the two bottoms. */ bottom: number; /** Top EL of the front half (전열 side, m). */ topFront: number; /** Top EL of the back half (후열 side, m). */ topBack: number; /** Mean row skew (deg) of the pair. */ rowSkewDeg: number; } /** Integrated blocks of a pier: empty unless 일체 is chosen and every pair is within the limit. */ export function buildIntegratedBlocks(blocks: BlockModel[], chosen: boolean): IntegratedBlock[] { if (!chosen || !integratedCheck(blocks).allowed) return []; const pick = (no: number, row: BlockModel['row']) => blocks.find((b) => b.no === no && b.row === row)!; return pairEccentricities(blocks).map((p) => { const f = pick(p.frontNo, '전열'); const b = pick(p.backNo, '후열'); return { frontNo: p.frontNo, backNo: p.backNo, s: (f.s + b.s) / 2, n: (f.n + b.n) / 2, bottom: Math.min(f.bottom, b.bottom), topFront: f.top, topBack: b.top, rowSkewDeg: (f.rowSkewDeg + b.rowSkewDeg) / 2, }; }); }