Files
Pier_v1/src/view/bearing-section-svg.ts
T
ypshimandClaude Haiku 5.5 0b847e7547 feat(bearing): section and solplate detail drawings with the drawing values overlaid (승인 2026-10-26)
- view/bearing-section-svg.ts: the pair's elevation — blocks (일체: one stepped
  outline), mortar, bearing body and solplate per bearing from the model; the
  drawing heights overlaid dashed. EL.X at the mortar top, E = h1 + h2 + h3 + h4.
- view/solplate-svg.ts: per bearing, the plan L × W and the taper T1 · T2
  (S %), with the drawing values dashed.
- ② bearing card: section figure and the two solplate figures under the plan.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-26 12:33:05 +09:00

83 lines
4.5 KiB
TypeScript

import type { PierModel } from '../core/geometry';
import { pairEccentricities } from '../core/bearing-layout';
/**
* Drawing values of one bearing (도면값), overlaid as dashed outlines (승인 2026-10-26).
* All lengths in mm; elx in m.
*/
export interface BearingDrawingRef {
elx?: number;
h1: number;
h2: number;
h3: number;
h4: number;
E: number;
A: number;
B: number;
}
/**
* 교량받침 상세 · 단면 (elevation) for one pair (승인 2026-10-26): the model's blocks, mortar, bearing body,
* and solplate per bearing, with the drawing heights overlaid as dashed outlines. x is the 교축 (n), y the EL (up).
* Labels: EL.X (mortar top), h1 (block), h2 (mortar), h3 (bearing), h4 (solplate), E = h1 + h2 + h3 + h4.
*/
export function bearingSectionSvg(m: PierModel, pairIndex: number, refs?: { front?: BearingDrawingRef; back?: BearingDrawingRef }): string {
const pair = pairEccentricities(m.blocks)[pairIndex];
if (!pair) return '';
const f = m.blocks.find((b) => b.no === pair.frontNo && b.row === '전열')!;
const k = m.blocks.find((b) => b.no === pair.backNo && b.row === '후열')!;
const nc = (f.n + k.n) / 2;
const elc = (f.bottom + k.bottom) / 2;
const X = (n: number) => (n - nc) * 1000;
const Y = (el: number) => -(el - elc) * 1000;
const parts: string[] = [];
// Blocks: one stepped outline for 일체, else one per bearing.
const ib = m.integratedBlocks.find((x) => x.frontNo === pair.frontNo);
if (ib) {
const x0 = X(ib.n - 1.25);
const x1 = X(ib.n + 1.25);
const xm = X(ib.n);
parts.push(`<polygon points="${x0},${Y(ib.bottom)} ${x1},${Y(ib.bottom)} ${x1},${Y(ib.topBack)} ${xm},${Y(ib.topBack)} ${xm},${Y(ib.topFront)} ${x0},${Y(ib.topFront)}" fill="#D6DDE5" stroke="#6E8496" stroke-width="10"></polygon>`);
} else {
for (const b of [f, k]) {
parts.push(`<rect x="${X(b.n) - 600}" y="${Y(b.top)}" width="1200" height="${(b.top - b.bottom) * 1000}" fill="#D6DDE5" stroke="#6E8496" stroke-width="10"></rect>`);
}
}
// Mortar, bearing body and solplate per bearing, from the model.
for (const [b, ref] of [[f, refs?.front], [k, refs?.back]] as const) {
const pad = 1000;
parts.push(`<rect x="${X(b.n) - pad / 2}" y="${Y(b.padTop)}" width="${pad}" height="${50}" fill="#B7C7D3" stroke="#6E8496" stroke-width="6"></rect>`);
if (b.plan) {
const { A, margin, h3, T } = b.plan;
const L = A + margin;
const bodyTop = b.padTop + h3 / 1000;
parts.push(`<rect x="${X(b.n) - (L - 200) / 2}" y="${Y(bodyTop)}" width="${L - 200}" height="${h3}" fill="#8898AA" stroke="#5B6676" stroke-width="6"></rect>`);
const drop = (L * Math.abs(b.plan.S)) / 200;
const t1 = T + drop;
const t2 = T - drop;
const x0 = X(b.n) - L / 2;
const x1 = X(b.n) + L / 2;
parts.push(`<polygon points="${x0},${Y(bodyTop)} ${x1},${Y(bodyTop)} ${x1},${Y(bodyTop + t2 / 1000)} ${x0},${Y(bodyTop + t1 / 1000)}" fill="#F3D9B8" stroke="#B4531F" stroke-width="6"></polygon>`);
}
if (ref) {
// Drawing heights from the block bottom, dashed (overlay).
const base = b.bottom;
const dBlockTop = base + (ref.h1 ?? 0) / 1000;
const dPad = dBlockTop + ref.h2 / 1000;
const dBody = dPad + ref.h3 / 1000;
const dSol = dBody + ref.h4 / 1000;
parts.push(`<rect x="${X(b.n) - 600}" y="${Y(dBlockTop)}" width="1200" height="${(dBlockTop - base) * 1000}" fill="none" stroke="#B4531F" stroke-width="8" stroke-dasharray="40 25"></rect>`);
parts.push(`<line x1="${X(b.n) - 700}" y1="${Y(dSol)}" x2="${X(b.n) + 700}" y2="${Y(dSol)}" stroke="#B4531F" stroke-width="8" stroke-dasharray="40 25"></line>`);
parts.push(`<line x1="${X(b.n) - 700}" y1="${Y(dBody)}" x2="${X(b.n) + 700}" y2="${Y(dBody)}" stroke="#B4531F" stroke-width="8" stroke-dasharray="40 25"></line>`);
}
// EL.X at the mortar top, bearing number.
parts.push(`<circle cx="${X(b.n)}" cy="${Y(b.padTop)}" r="30" fill="#18212B"></circle>`);
parts.push(`<text x="${X(b.n) + 60}" y="${Y(b.padTop) - 60}" font-size="90" fill="#18212B">${b.no} · EL.X ${b.padTop.toFixed(3)}</text>`);
parts.push(`<text x="${X(b.n)}" y="${Y(b.bottom) + 160}" text-anchor="middle" font-size="90" fill="#55606E">h1 ${Math.round((b.top - b.bottom) * 1000)}</text>`);
}
return `<svg viewBox="-2000 -1200 4000 2000" width="100%" style="max-width: 560px; height: auto" role="img" aria-label="교량받침 상세 단면: 블록, 모르타르, 받침, 솔플레이트, EL.X, 도면 높이 점선">${parts.join('')}</svg>`;
}