Files
Pier_v1/src/view/abut-footing-svg.ts
T
ypshimandClaude Opus 5.5 372d759eb7 feat(abut): ② 확대기초 · 말뚝 카드를 시안대로 작성 (평면 삽도, 버림, 열별 본수)
- 선택: 평면 skew 평행사변형(기본) / 직사각(비활성, 다음 단계), 말뚝 원기둥 D600 / 강관 · PHC(비활성, 규칙 미정)
- 평면 삽도 (src/view/abut-footing-svg.ts): 저판, 벽체 윤곽, 교대축, 말뚝 3열(skew만큼 밀림), 열 위치 · 본수, 폭 치수
- 입력: 폭 4600, 두께 1100, 앞굽 1200 (뒷굽 자동 1000), 버림 여유 · 두께 100 / 100, 말뚝 지름 600 (QA-5), 연단 650, 본수 규칙 간격 2000
- 열 위치 "650 · 2000 · 1300 · 650" 입력 (전면 연단 자동, 합 = 폭 검사), 열별 말뚝 본수 표 − / + (0 = 본수 규칙)
- 자동 값: 뒷굽, 길이(교좌면 길이), 말뚝 길이(①에서 수정), 선단 EL, 본수 규칙 문구. 시안 메모
- 3D: 교대 버림을 저판 아래에 그림 (부재 표시 "버림" 토글 적용), 말뚝 지름 입력 반영, 말뚝 열을 skew만큼 s 방향으로 밀어 배치
- 예전 저장 파일의 앞굽 끝 · 뒷굽 끝은 폭 · 앞굽으로 바꿔 읽음
- 테스트 추가 · 갱신. 전체 661건 통과, 타입 검사 · 빌드 통과. 브라우저 시각 확인은 미실시

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 08:46:58 +09:00

60 lines
3.4 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.
/**
* 교대 확대기초 · 말뚝 평면 삽도 (2026-11-04, 시안 ② 확대기초·말뚝 카드). 순수 문자열 함수.
* 생성본 값으로 그린다: 저판(skew 평행사변형, 굵은 선), 벽체 윤곽(실선), 교대축(점선), 말뚝 3열(원), 열 위치, 폭 치수.
* 가로(s)와 세로(t) 축척이 같다. 위가 전면, 아래가 배면이다.
*/
export interface AbutFootingDrawing {
/** 교대축 길이 L (m). */
lengthM: number;
/** s per m of t along the wing (skew): s = s_axis + k·t. */
skewK: number;
/** t (m): 저판 앞굽 끝, 뒷굽 끝, 벽체 전면, 벽체 배면. */
footingFrontM: number;
footingBackM: number;
wallFrontM: number;
wallBackM: number;
/** 말뚝 열: t (m), s (m, 교대축 기준, skew 전), 열 이름 (1열 · 전면 …). */
rows: { t: number; s: number[]; name: string }[];
pileDiameterM: number;
/** 열 위치 치수 (mm, 배면부터): 배면 연단, 간격, 간격, 전면 연단. */
rowDimsMm: [number, number, number, number];
footingWidthMm: number;
}
const INK = '#18212b';
const MUTED = '#55606e';
const label = (x: number, y: number, s: string, anchor = 'start', fill = INK) =>
`<text x="${x.toFixed(1)}" y="${y.toFixed(1)}" text-anchor="${anchor}" font-size="11" fill="${fill}" font-family="JetBrains Mono, monospace">${s}</text>`;
export function abutFootingPlanSvg(d: AbutFootingDrawing): string {
const k = 36; // px per m, both directions
const sMin = Math.min(d.skewK * d.footingFrontM, d.skewK * d.footingBackM) - 0.4;
const sMax = d.lengthM + Math.max(d.skewK * d.footingFrontM, d.skewK * d.footingBackM) + 0.4;
const tTop = d.footingFrontM + 0.4;
const X = (s: number, t: number) => 20 + (s + d.skewK * t - sMin) * k;
const Y = (t: number) => 14 + (tTop - t) * k;
const W = 20 + (sMax - sMin) * k + 170;
const H = Y(d.footingBackM - 0.4) + 34;
const quad = (t0: number, t1: number, style: string) =>
`<polygon points="${[[0, t0], [d.lengthM, t0], [d.lengthM, t1], [0, t1]].map(([s, t]) => `${X(s, t).toFixed(1)},${Y(t).toFixed(1)}`).join(' ')}" ${style}/>`;
const parts: string[] = [];
parts.push(quad(d.footingBackM, d.footingFrontM, `fill="#e6ebf0" stroke="${INK}" stroke-width="2"`));
parts.push(quad(d.wallBackM, d.wallFrontM, `fill="none" stroke="${MUTED}"`));
parts.push(`<line x1="${X(0, 0).toFixed(1)}" y1="${Y(0).toFixed(1)}" x2="${X(d.lengthM, 0).toFixed(1)}" y2="${Y(0).toFixed(1)}" stroke="#c0392b" stroke-dasharray="6 3"/>`);
parts.push(label(X(d.lengthM, 0) + 6, Y(0) + 4, '교대축', 'start', '#c0392b'));
const r = Math.max(2, (d.pileDiameterM / 2) * k);
for (const row of d.rows) {
for (const s of row.s) parts.push(`<circle cx="${X(s, row.t).toFixed(1)}" cy="${Y(row.t).toFixed(1)}" r="${r.toFixed(1)}" fill="#ffffff" stroke="${INK}"/>`);
const tLabel = `${row.t >= 0 ? '+' : '−'}${Math.round(Math.abs(row.t) * 1000)}`;
parts.push(label(X(d.lengthM, row.t) + r + 8, Y(row.t) + 4, `${row.name} · t ${tLabel} · ${row.s.length}본`));
}
const [e1, g1, g2, e2] = d.rowDimsMm;
parts.push(label(20, H - 10, `${d.footingWidthMm} = 뒷굽쪽 ${e1} · ${g1} · ${g2} · ${e2} 전면 · 위 = 전면`, 'start', MUTED));
return [
`<svg viewBox="0 0 ${W.toFixed(0)} ${H.toFixed(0)}" width="100%" role="img" aria-label="확대기초 평면: skew 평행사변형, 폭 ${d.footingWidthMm}, 말뚝 ${d.rows.map((r2) => r2.s.length).join(' + ')}본">`,
...parts,
'</svg>',
].join('');
}