import type { PierInput } from './types'; /** EL in metres, lengths in mm. User image and clarifications 2026-11-05; casing default and rock socket per 현장타설말뚝철근.md (2026-11-06). */ export interface CastInPlaceShapeSettings { betaLengthMm?: number; weatheredRockEl?: number; bedrockEl?: number; casingOn?: boolean; casingTopEl?: number; casingBottomEl?: number; clayBottomEl?: number; /** 암반 근입부 지름 (mm, 희생강관 아래). Absent = D − 150 with a casing, D without (현장타설말뚝철근.md §1.1, Q-PL3). */ socketDiameterMm?: number; } /** Rock-socket diameter (mm): the input, else D − 150 when the casing is on (default on, spec §3 2026-11-06), else D. */ export function castSocketDiameterMm(input: Pick): number { const s = input.castInPlaceShape ?? {}; const d = input.columnDiameterMm ?? 2000; return s.socketDiameterMm ?? ((s.casingOn ?? true) ? d - 150 : d); } export function castShape(input: Pick) { const s = input.castInPlaceShape ?? {}; const pileBottomEl = input.groundEl - input.pileLengthMm / 1000; const bedrockEl = s.bedrockEl ?? pileBottomEl + 1; const betaLengthMm = s.betaLengthMm ?? 9000; return { pileTopEl: input.groundEl, pileBottomEl, betaLengthMm, betaEl: input.groundEl - betaLengthMm / 1000, weatheredRockEl: s.weatheredRockEl ?? pileBottomEl + 5, bedrockEl, // 희생강관: 적용, 상단 지반고 + 2500 (그림 값, 엑셀 문구 + 3000 — Q-PL4 가정), 하단 = 기반암 EL. casingOn: s.casingOn ?? true, casingTopEl: s.casingTopEl ?? input.groundEl + 2.5, casingBottomEl: s.casingBottomEl ?? bedrockEl, clayBottomEl: s.clayBottomEl, socketDiameterMm: castSocketDiameterMm(input), }; } export function castShapeIssues(value: unknown): string[] { if (value === undefined) return []; if (!value || typeof value !== 'object' || Array.isArray(value)) return ['현장타설 형상 입력 형식이 맞지 않습니다.']; const out: string[] = []; for (const [key, v] of Object.entries(value)) { if (v === undefined) continue; if (key === 'casingOn') { if (typeof v !== 'boolean') out.push('희생강관 적용 여부가 맞지 않습니다.'); } else if (!['betaLengthMm', 'weatheredRockEl', 'bedrockEl', 'casingTopEl', 'casingBottomEl', 'clayBottomEl', 'socketDiameterMm'].includes(key) || typeof v !== 'number' || !Number.isFinite(v) || (key === 'betaLengthMm' || key === 'socketDiameterMm') && v <= 0) out.push(`현장타설 형상 ${key} 값이 맞지 않습니다.`); } return out; } /** DXF note 4. Do not substitute weathered-rock EL for the independent clay-layer EL. */ export function castLowerZone(input: Pick) { const s = castShape(input); if (s.clayBottomEl === undefined) return null; const d = (input.columnDiameterMm ?? 2000) / 1000; const a = s.betaEl - 3 * d; const b = s.clayBottomEl + d; return { bottomEl: a, topEl: b, valid: a < b }; }