Files
Pier_v1/src/view/cast-rebar-svg.ts
T
ypshimandClaude Haiku 5.5 2e0bfb6fc8 feat(rebar): 현장타설 말뚝 · 다주형 코핑 형상과 철근 계산
- 현장타설 기둥·말뚝 형상(cast-in-place-shape)과 주철근·횡철근·커플러 계산(rebar/cast-in-place, cast-layout)
- 다주형 코핑 철근(multicol-coping), 기둥 높이 · 양단부 연장
- 철근표 요약 · 재료 수량 · 3D 뷰 연결과 삽도(cast-rebar-svg)
- 검사 기준 갱신과 회귀 테스트, 검증 스크립트 보관

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-06 13:15:01 +09:00

31 lines
2.6 KiB
TypeScript

import type { PierModel } from '../core/geometry';
import type { CastLayout } from '../core/rebar/cast-layout';
/** Front and section projections of the same centre lines used in the 3D scene. */
export function castRebarSvg(model: PierModel, layout: CastLayout): string {
const bars = layout.bars.filter(b => b.columnIndex === 0);
if (!bars.length) return '<p>입력 오류를 확인하세요. 생성된 기둥·말뚝 철근이 없습니다.</p>';
const pts = bars.flatMap(b => b.pts);
const bottom = pts.reduce((a, p) => Math.min(a, p[1]), Infinity);
const top = pts.reduce((a, p) => Math.max(a, p[1]), -Infinity);
const diameter = model.columnDiameterMm / 1000;
const scale = Math.min(180 / diameter, 480 / (top - bottom));
const x = (v: number) => 130 + (v - model.columns[0].s) * scale;
const y = (v: number) => 35 + (top - v) * scale;
const colour = (kind: string) => kind === 'main' ? '#0f5c66' : kind === 'coupler' ? '#0b3f46' : '#6b3fa0';
const front = bars.map(b => `<polyline points="${b.pts.map(p => `${x(p[0]).toFixed(2)},${y(p[1]).toFixed(2)}`).join(' ')}" fill="none" stroke="${colour(b.kind)}" stroke-width="${b.kind === 'coupler' ? 2 : 0.7}"/>`).join('');
const sectionHeight = model.groundEl + Math.min(1, (model.columns[0].top - model.groundEl) / 2);
const sectionScale = 140 / diameter;
const section = bars.filter(b => b.kind === 'main' && b.pts[0][1] <= sectionHeight && b.pts.at(-1)![1] >= sectionHeight).map(b => {
const p = b.pts[0];
return `<circle cx="${365 + (p[0] - model.columns[0].s) * sectionScale}" cy="${160 + p[2] * sectionScale}" r="${Math.max(1, b.diameterMm / 2000 * sectionScale)}" fill="#0f5c66"/>`;
}).join('');
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 470 560" role="img" aria-label="첫 기둥 및 현장타설말뚝 배근 정면·기둥 단면" style="width:100%;max-width:560px">
<text x="20" y="20" font-size="12">정면 · 실제 생성 경로</text>
<rect x="${x(model.columns[0].s - diameter / 2)}" y="${y(top)}" width="${diameter * scale}" height="${(top - bottom) * scale}" fill="none" stroke="#d9d6cc"/>
${front}<line x1="20" x2="245" y1="${y(model.groundEl)}" y2="${y(model.groundEl)}" stroke="#5b6878" stroke-dasharray="4 3"/>
<text x="20" y="${y(model.groundEl) - 5}" font-size="11">지반고 EL ${model.groundEl.toFixed(3)}</text>
<text x="285" y="40" font-size="12">기둥 주철근 단면</text><circle cx="365" cy="160" r="70" fill="none" stroke="#d9d6cc"/>${section}
<text x="20" y="548" font-size="11">단부·저부 P6 미확정 사항은 알림 참조 · 길이 단위 mm</text></svg>`;
}