feat(abut): 교대 형상·입력 패널과 교각 받침·솔플레이트 개편

- 교대 형상(src/core/abut, 3D 장면, 목록·카메라·맞춤)과 교대 입력 패널 추가
- 교각 받침 기준 카드 제거, 솔플레이트 규칙을 교각별 입력으로 변경
- 받침 ELEVATION·솔플레이트 TABLE을 모델값으로 연결
- 교대 입력값 카드: 형식 행에 시점·종점 표시, 제목을 "A1 입력값 [입력]"으로 변경
- 테스트 614건 통과, 타입 검사 통과

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-11-03 14:51:34 +09:00
1 parent b1b2ad1ddb
commit 1d31d2f3a9
44 files changed
+2571 -120

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
/**
* 교대 상세 (2026-11-03, 교각 상세와 같은 개념): the values the 삽도 shows, computed from the model. Read only.
* Each row is [label, value]. Lengths in mm, levels in m, as in the 삽도.
*/
import type { AbutRecord } from './parse';
import { buildAbut, type AbutModel } from './geometry';
import { toAbutInput } from './parse';
import { buildMembers } from './members';
import { buildWings } from './wings';
const m3 = (v: number) => `${v.toFixed(3)} m`;
const mm = (v: number) => `${Math.round(v)} mm`;
export function abutSummaryRows(rec: AbutRecord): [string, string][] {
const model: AbutModel = buildAbut(toAbutInput(rec));
const members = buildMembers(model, { bottomEl: rec.foundationBottomEl, pileLengthMm: rec.pileLengthMm }, rec.shape);
const wings = buildWings(model, members, rec.wings);
const shape = members.shape;
const first = model.bearings[0];
const L = model.length;
const rows: [string, string][] = [
['형식 / 기초 형식', `${rec.type} · ${rec.foundation}`],
['교좌면 EL (구간 ①)', m3(rec.seatEl)],
['기초 하단 EL', m3(rec.foundationBottomEl)],
['지반고 EL', m3(rec.groundEl)],
['저판 상면 EL', m3(members.footingTopEl)],
['교대축 길이 (IP1 → IP3)', m3(L)],
['skew', `${rec.skewDeg.toFixed(2)}°`],
['종단경사 i', `${(rec.slopeI * 100).toFixed(2)} %`],
['받침블럭 높이 (패드 포함)', mm(first.blockHeightMm)],
['벽체 높이 (구간 ①)', m3(members.wallSegments.find((w) => Math.abs(w.seatEl - first.seatEl) < 1e-9)?.heightM ?? NaN)],
['벽체 두께 · 전면', `${Math.round(shape.wallFrontM * 1000 - shape.wallBackM * 1000)} mm · ${Math.round(shape.wallFrontM * 1000)} mm`],
['흉벽 높이 · 두께', `${Math.round(shape.parapetHeightM * 1000)} mm · ${Math.round(-shape.parapetBackM * 1000)} mm`],
['흉벽 상단 EL (IP1 끝 / IP3 끝)', `${members.parapetTopStartEl.toFixed(3)} / ${members.parapetTopEndEl.toFixed(3)} m`],
['브라켓 상면 EL (구간 ①)', m3(first.seatEl + shape.parapetHeightM - shape.bracketHeightM)],
['흉벽 경사', `${(members.parapetSlope * 100).toFixed(3)} %`],
['계단 경계 (IP3 쪽에서)', model.stepBounds.map((s) => (L - s).toFixed(3)).reverse().join(' / ') + ' m'],
['저판 폭 (앞굽 끝 / 뒷굽 끝)', `${Math.round(shape.footingFrontM * 1000)} / ${Math.round(shape.footingBackM * 1000)} mm`],
['말뚝 (열 × 본수)', `${members.piles.length} × ${members.piles[0]?.s.length ?? 0} = ${members.piles.length * (members.piles[0]?.s.length ?? 0)} 본`],
['말뚝 선단 EL', members.pileBottomEl === undefined ? '—' : m3(members.pileBottomEl)],
['수축줄눈 (ceil(L/10) − 1)', `${Math.max(0, Math.ceil(L / 10) - 1)} 개`],
];
if (wings.length > 0) {
const w = wings[0];
rows.push(['날개벽 경사', `${model.wing ? (model.wing.slopePct).toFixed(2) : '—'} %`]);
rows.push(['날개벽 뒷굽 거리 (교대축 기준)', mm(w.heelDistanceM * 1000)]);
}
if (model.wing) rows.push(['접속슬래브 폭', mm(model.wing.slabWidthMm)]);
return rows;
}
/** 입력값 rows of the 교대 panel (시안 "A1 입력값" card): what the user typed, read only. */
export function abutInputRows(rec: AbutRecord): [string, string][] {
const rows: [string, string][] = [
['형식 / 기초 형식', `${rec.type} (${rec.type === 'A1' ? '시점' : '종점'}) · ${rec.foundation}`],
['교좌면 EL (구간 ①)', `${rec.seatEl.toFixed(3)} m`],
['기초 하단 EL', `${rec.foundationBottomEl.toFixed(3)} m`],
['지반고 EL', `${rec.groundEl.toFixed(3)} m`],
['skew', `${rec.skewDeg.toFixed(2)}°`],
['종단경사 i', `${(rec.slopeI * 100).toFixed(2)} %`],
['말뚝 길이', `${Math.round(rec.pileLengthMm)} mm`],
['IP', 'IP1 → IP3 직선'],
['받침', `${rec.bearings.length}개 · z = 패드 상면`],
];
return rows;
}
/** The 8 detail rows shown in the collapsed 상세 (the rest stay in the 삽도 view). */
export const ABUT_DETAIL_LABELS = [
'벽체 높이 (구간 ①)',
'흉벽 상단 EL (IP1 끝 / IP3 끝)',
'브라켓 상면 EL (구간 ①)',
'저판 상면 EL',
'계단 경계 (IP3 쪽에서)',
'말뚝 (열 × 본수)',
'말뚝 선단 EL',
'접속슬래브 폭',
];