import type { PierInput } from './types'; import type { PierModel } from './geometry'; /** * 교량받침 reference tables from the P1 상세도 (도면값, 읽기 전용, 2026-10-23). They are not used in the model: * the model keeps the imported values (Q16). EL.X is the drawing's bearing level; E = h1 + h2 + h3 + h4. */ export interface BearingRefRow { no: number; row: '전열' | '후열'; /** EL.X (m). */ elx: number; /** 블럭 높이 h1 (mm, 도면). */ h1: number; /** 모르타르 h2 (mm). */ h2: number; /** 받침 h3 (mm). */ h3: number; /** 솔플레이트 h4 (mm). */ h4: number; /** E (mm, 도면). */ E: number; A: number; B: number; C1: number; C2: number | null; C3: number | null; C4: number | null; C5: number | null; C6: number | null; S1: number; } export interface SolplateRefRow { no: number; /** 기울기 S (%), negative as drawn. */ s: number; L: number; W: number; /** 중심 두께 T (mm). The solplate tapers along the bridge axis. */ T: number; /** 두께 at the 교각축 직각 (−) side (mm). */ T1: number; /** 두께 at the 교각축 직각 (+) side (mm). */ T2: number; } const FRONT = { h1: 164, h2: 50, h3: 181, h4: 30, E: 425 }; const BACK = { h1: 139, h2: 50, h3: 181, h4: 30, E: 400 }; export const BEARING_ELEVATION_REF: BearingRefRow[] = [ { no: 1, row: '전열', elx: 43.625, ...FRONT, A: 700, B: 640, C1: 600, C2: 1298, C3: 2500, C4: 600, C5: 600, C6: 1200, S1: 852 }, { no: 2, row: '전열', elx: 43.697, ...FRONT, A: 700, B: 640, C1: 600, C2: 1298, C3: 2500, C4: 600, C5: 600, C6: 1200, S1: 852 }, { no: 3, row: '전열', elx: 43.768, ...FRONT, A: 700, B: 790, C1: 600, C2: 1298, C3: 2500, C4: 600, C5: 600, C6: 1200, S1: 852 }, { no: 4, row: '전열', elx: 43.840, ...FRONT, A: 700, B: 640, C1: 600, C2: 1298, C3: 2500, C4: 600, C5: 600, C6: 1200, S1: 852 }, { no: 5, row: '전열', elx: 43.912, ...FRONT, A: 700, B: 640, C1: 600, C2: 1298, C3: 2500, C4: 600, C5: 600, C6: 1200, S1: 852 }, { no: 6, row: '후열', elx: 43.600, ...BACK, A: 700, B: 540, C1: 602, C2: null, C3: null, C4: null, C5: null, C6: null, S1: 950 }, { no: 7, row: '후열', elx: 43.672, ...BACK, A: 700, B: 540, C1: 602, C2: null, C3: null, C4: null, C5: null, C6: null, S1: 950 }, { no: 8, row: '후열', elx: 43.744, ...BACK, A: 700, B: 650, C1: 602, C2: null, C3: null, C4: null, C5: null, C6: null, S1: 950 }, { no: 9, row: '후열', elx: 43.816, ...BACK, A: 700, B: 540, C1: 602, C2: null, C3: null, C4: null, C5: null, C6: null, S1: 950 }, { no: 10, row: '후열', elx: 43.887, ...BACK, A: 700, B: 540, C1: 602, C2: null, C3: null, C4: null, C5: null, C6: null, S1: 950 }, ]; export const SOLPLATE_REF: SolplateRefRow[] = [ { no: 1, s: -1.910, L: 800, W: 740, T: 30, T1: 38, T2: 22 }, { no: 2, s: -1.907, L: 800, W: 740, T: 30, T1: 38, T2: 22 }, { no: 3, s: -1.905, L: 800, W: 890, T: 30, T1: 38, T2: 22 }, { no: 4, s: -1.903, L: 800, W: 740, T: 30, T1: 38, T2: 22 }, { no: 5, s: -1.901, L: 800, W: 740, T: 30, T1: 38, T2: 22 }, { no: 6, s: -1.910, L: 800, W: 640, T: 30, T1: 38, T2: 22 }, { no: 7, s: -1.907, L: 800, W: 640, T: 30, T1: 38, T2: 22 }, { no: 8, s: -1.905, L: 800, W: 750, T: 30, T1: 38, T2: 22 }, { no: 9, s: -1.903, L: 800, W: 640, T: 30, T1: 38, T2: 22 }, { no: 10, s: -1.901, L: 800, W: 640, T: 30, T1: 38, T2: 22 }, ]; /** 중심 두께 T of the 공통 규칙 (30 mm). T1 = T + L·|S|/2 (−측), T2 = T − L·|S|/2 (+측), so T1 + T2 = 2T. */ export const SOLPLATE_T_RULE = 30; /** T1 / T2 by the drawing's rule: T ± L·|S|/2, rounded to mm (S in %). */ export function solplateTs(T: number, L: number, s: number): { T1: number; T2: number } { const half = (L * Math.abs(s)) / 200; return { T1: Math.round(T + half), T2: Math.round(T - half) }; } /** 공통 규칙 (2단계, 승인 2026-10-23): inputs that drive E, L, W, T1, T2. Defaults are the drawing's values. */ export interface BearingRules { /** 모르타르 h2 (mm). */ h2: number; /** 받침 높이 h3 (mm). */ h3: number; /** 솔플레이트 중심 두께 T (mm). */ T: number; /** 솔플 여유 (mm): L = A + margin, W = B + margin. */ margin: number; } export const BEARING_RULES_DEFAULT: BearingRules = { h2: 50, h3: 181, T: SOLPLATE_T_RULE, margin: 100 }; /** Values of one bearing with the 공통 규칙 applied: E = h1 + h2 + h3 + h4, L = A + margin, W = B + margin, T1/T2 from T. */ export function applyBearingRules(row: BearingRefRow, rules: BearingRules): { E: number; L: number; W: number; T1: number; T2: number } { const sp = SOLPLATE_REF[row.no - 1]; const L = row.A + rules.margin; const { T1, T2 } = solplateTs(rules.T, L, sp.s); return { E: row.h1 + rules.h2 + rules.h3 + row.h4, L, W: row.B + rules.margin, T1, T2 }; } /** 받침 기준 (Q16, 승인 2026-10-23): 'excel' = 엑셀 z (기본), 'drawing' = 도면 EL.X. Project-wide. */ export type BearingBasis = 'excel' | 'drawing'; /** One bearing's drawing values entered on ② (mm for h1, h2; m for EL.X). */ export interface DrawingBearing { no: number; elx: number; h1: number; h2: number; } /** Tolerance for the coping top check against the drawing (승인 2026-10-23: 5 mm). */ export const DRAWING_TOL_MM = 5; /** The input with each bearing's z replaced by the drawing EL.X, for bearings that have a drawing value. */ export function withDrawingBasis(input: PierInput, drawing: DrawingBearing[]): PierInput { const byNo = new Map(drawing.map((d) => [d.no, d])); return { ...input, bearings: input.bearings.map((b) => { const d = byNo.get(b.no); return d ? { ...b, z: d.elx } : b; }), }; } /** Coping top implied by each drawing row (EL.X − h1 − h2) against the model's coping top; differences in mm. */ export function drawingCopingCheck(model: PierModel, drawing: DrawingBearing[]): { no: number; diffMm: number; ok: boolean }[] { const front = model.blocks.filter((b) => b.row === '전열'); const back = model.blocks.filter((b) => b.row === '후열'); return drawing.map((d) => { const implied = d.elx - (d.h1 + d.h2) / 1000; const modelTop = d.no <= 5 ? model.segments[d.no - 1]?.top : back[d.no - 6]?.bottom; const diffMm = modelTop === undefined ? NaN : Math.round((modelTop - implied) * 1000 * 10) / 10; return { no: d.no, diffMm, ok: Number.isFinite(diffMm) && Math.abs(diffMm) <= DRAWING_TOL_MM }; }); }