Files
Pier_v1/src/core/validate.ts
T
ypshimandClaude Haiku 5.5 d963d8ed3c feat(core): parse P1 workbook and build T-type pier shape
- parse Excel input by header strings (pier, IP, bearing tables)
- DMS azimuth parser (E03), input validation (E01, E02)
- pure geometry: axis, bearings, stepped coping, column, footing, piles, blinding
- warnings W01, W02, W05, W07, I01
- regression tests against spec.md section 12 (P1)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-21 17:26:16 +09:00

70 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { DIM, type PierModel } from './geometry';
import type { Issue, PierInput, PierType } from './types';
const EXPECTED_COLUMNS: Record<PierType, number> = { 'T형': 1, '2주형': 2, '3주형': 3 };
/** Rules from spec §10 that are not implemented in this stage. Shown to the user, never silently skipped. */
export const NOT_IMPLEMENTED_RULES = [
'E04 fck 미입력 (배근 단계, 3단계)',
'W03 받침 중심 ~ 계단 경계 < 블럭 폭/2',
'W04 블럭이 코핑 평면 밖',
'W06 속성 복사 건너뜀 (2단계)',
'W08 솔플레이트 T1−T2 검사 (2단계)',
'다주형 코핑 헌치·Level−300 (Q3), 일체기초 판정 (2·3주형)',
] as const;
/** Input-level checks (spec §10 E01, E02). Returns false when the pier must not be built. */
export function validateInput(input: PierInput, issues: Issue[]): boolean {
let ok = true;
if (input.columnCount !== EXPECTED_COLUMNS[input.type]) {
issues.push({
code: 'E01',
level: 'E',
pier: input.name,
message: `교각형식 ${input.type}과 기둥갯수 ${input.columnCount}개가 맞지 않습니다. 기둥 ${EXPECTED_COLUMNS[input.type]}개로 맞추세요.`,
});
ok = false;
}
const front = input.bearings.filter((b) => b.row === '전열').length;
const back = input.bearings.filter((b) => b.row === '후열').length;
if (front !== back) {
issues.push({ code: 'E02', level: 'E', pier: input.name, message: `전열 받침 ${front}개, 후열 받침 ${back}개로 수가 다릅니다.` });
ok = false;
}
return ok;
}
/** Geometry-level checks (spec §10 W01, W02, W05, W07, I01) on a built model. */
export function validatePier(input: PierInput, model: PierModel, issues: Issue[]): void {
const ip2Gap = Math.hypot(model.ip2Input.e - model.ip2Calc.e, model.ip2Input.n - model.ip2Calc.n);
if (ip2Gap > 0.001) {
issues.push({
code: 'W01',
level: 'W',
pier: input.name,
message: `IP2 입력과 재계산값이 ${(ip2Gap * 1000).toFixed(1)} mm 다릅니다. 재계산값을 사용합니다.`,
});
}
const minBlock = Math.min(model.derived.blockHeightFront, model.derived.blockHeightBack);
if (minBlock <= 0) {
issues.push({ code: 'W02', level: 'W', pier: input.name, message: '받침블럭 콘크리트 높이가 0 이하입니다. 블럭을 생략합니다.' });
}
if (input.foundationType !== '현장타설말뚝' && model.footings.some((f) => f.top > input.groundEl)) {
issues.push({ code: 'W05', level: 'W', pier: input.name, message: '확대기초 상면이 지반고보다 높습니다.' });
}
if (model.derived.frontBackDiffSpread > DIM.lateralTolerance) {
issues.push({ code: 'W07', level: 'I', pier: input.name, message: '전열·후열 EL 차이가 받침마다 다릅니다 (정보).' });
}
// I01: block concrete below cover + bar diameter (cover 100 mm, S1·S2 H19 from spec §6.3).
const cover = 0.1;
const barDia = 0.019;
if (minBlock < cover + barDia) {
issues.push({
code: 'I01',
level: 'I',
pier: input.name,
message: `받침블럭 높이 ${(minBlock * 1000).toFixed(0)} mm가 피복 + 철근 지름(${((cover + barDia) * 1000).toFixed(0)} mm)보다 작습니다. 블럭 철근은 코핑 안에 묻힙니다.`,
});
}
}