Files
Pier_v1/src/view/bearing-plan-svg.ts
T
ypshimandClaude Haiku 5.5 2f67efd449 fix(bearing): C4 and C5 are the 교각축 distances from the bearing to the block edges (승인 2026-10-26)
- bearingEdgeDistances measures along the 교각축: 분리 600 / 600; 일체 from the
  pair block centred on the mean 교각축 position (P1 outer margins 557).
- Table headings updated; C1 · C2 · C3 on the plan are measured on the 교축 from the drawn positions.

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

99 lines
6.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.
import type { PierModel } from '../core/geometry';
import { bearingEdgeDistances, pairEccentricities } from '../core/bearing-layout';
/** Drawing values (A, B of the solplate, mm) of the front and back bearings, to overlay on the model (승인 2026-10-26). */
export interface BearingPlanOverlay {
front: { A: number; B: number };
back: { A: number; B: number };
}
/** Number of pairs the 상세 보기 chips can show (①–⑩ in the mockup). */
export const PAIR_CHIP_LABELS = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'];
/**
* 교량받침 상세 · 평면 for one pair (승인 2026-10-26): the blocks and solplates are aligned in one row across the 교축
* (x = n), with the actual 교각축 offset of the bearings written as text. The model's solplates are solid, the drawing values
* dashed. 일체 draws one 2500 × 1200 outline; 분리 draws two 1200 × 1200 outlines. Dimensions: C1 (bearing to block edge),
* C2 (between the bearings), C3 (block span). C4 and C5 are the outer margins along the 교축.
*/
export function bearingPlanSvg(m: PierModel, pairIndex: number, overlay?: BearingPlanOverlay): 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 sc = (f.s + k.s) / 2;
// The pair is drawn on one line: every block, solplate and bearing sits at the pair's mean 교각축 position.
const X = (n: number) => (n - nc) * 1000;
const Y = (_s: number) => 0;
const eccentricity = Math.abs(f.s - k.s) * 1000;
const parts: string[] = [];
// Axes: 교축 (horizontal, to the right) and 교각축 방향 (vertical, downward).
parts.push(`<line x1="-1700" y1="0" x2="1650" y2="0" stroke="#B4531F" stroke-width="6" stroke-dasharray="120 60 20 60"></line>`);
parts.push(`<polygon points="1650,0 1560,-40 1560,40" fill="#B4531F"></polygon>`);
parts.push(`<text x="1640" y="-60" text-anchor="end" font-size="90" fill="#B4531F">교축</text>`);
parts.push(`<line x1="0" y1="-900" x2="0" y2="900" stroke="#B4531F" stroke-width="6" stroke-dasharray="120 60 20 60"></line>`);
parts.push(`<polygon points="0,-900 -40,-810 40,-810" fill="#B4531F"></polygon>`);
parts.push(`<text x="60" y="-860" font-size="90" fill="#B4531F">교각축 방향</text>`);
// Block outline(s): one row.
const ib = m.integratedBlocks.find((x) => x.frontNo === pair.frontNo);
if (ib) {
parts.push(`<rect x="${X(ib.n - 1.25)}" y="-600" width="2500" height="1200" fill="none" stroke="#6E8496" stroke-width="12"></rect>`);
} else {
for (const b of [f, k]) {
parts.push(`<rect x="${X(b.n) - 600}" y="-600" width="1200" height="1200" fill="none" stroke="#6E8496" stroke-width="12"></rect>`);
}
}
// Solplates: the model's plan (A across the 교축, B along the 교각축), centred on each bearing.
for (const b of [f, k]) {
if (b.plan) {
const { A, B } = b.plan;
parts.push(`<rect x="${X(b.n) - A / 2}" y="${Y(b.s) - B / 2}" width="${A}" height="${B}" fill="#EEF3F7" stroke="#2F6DB5" stroke-width="10"></rect>`);
}
}
// Drawing values overlaid (dashed) on the same bearings (#1 겹쳐 보이게).
if (overlay) {
for (const [b, v] of [[f, overlay.front], [k, overlay.back]] as const) {
parts.push(`<rect x="${X(b.n) - v.A / 2}" y="${Y(b.s) - v.B / 2}" width="${v.A}" height="${v.B}" fill="none" stroke="#B4531F" stroke-width="10" stroke-dasharray="40 25"></rect>`);
}
}
// Bearing centres and numbers.
for (const b of [f, k]) {
parts.push(`<circle cx="${X(b.n)}" cy="${Y(b.s)}" r="40" fill="#18212B"></circle>`);
parts.push(`<text x="${X(b.n) + 70}" y="${Y(b.s) - 60}" font-size="90" fill="#18212B">${b.no}</text>`);
}
if (eccentricity > 0.5) {
parts.push(`<text x="0" y="${-700}" text-anchor="middle" font-size="80" fill="#55606E">편심 ${eccentricity.toFixed(0)} mm (교각축 방향, 블록은 한 줄로 맞춤)</text>`);
}
// Dimensions along the bottom: C1 (bearing to block edge), C2 (between the bearings), C1, and C3 (block span).
const dist = bearingEdgeDistances(m);
const d = (no: number) => dist.find((x) => x.no === no)!;
const xLeft = ib ? X(ib.n - 1.25) : X(f.n) - 600;
const xRight = ib ? X(ib.n + 1.25) : X(k.n) + 600;
const dimLine = (x1: number, x2: number, y: number, label: string) =>
`<line x1="${x1}" y1="${y}" x2="${x2}" y2="${y}" stroke="#55606E" stroke-width="6"></line><line x1="${x1}" y1="${y - 50}" x2="${x1}" y2="${y + 50}" stroke="#55606E" stroke-width="6"></line><line x1="${x2}" y1="${y - 50}" x2="${x2}" y2="${y + 50}" stroke="#55606E" stroke-width="6"></line><text x="${(x1 + x2) / 2}" y="${y + 110}" text-anchor="middle" font-size="90" fill="#18212B">${label}</text>`;
const y1 = 760;
const y2 = 1000;
// C1 and C2 are along the 교축 (horizontal), measured on the drawn positions.
parts.push(dimLine(xLeft, X(f.n), y1, `C1 ${Math.round(X(f.n) - xLeft)}`));
parts.push(dimLine(X(f.n), X(k.n), y1, `C2 ${Math.round(Math.abs(k.n - f.n) * 1000)}`));
parts.push(dimLine(X(k.n), xRight, y1, `C1 ${Math.round(xRight - X(k.n))}`));
parts.push(dimLine(xLeft, xRight, y2, `C3 ${Math.round((xRight - xLeft))}`));
// C4 and C5 as in the 시안: vertical dimensions on the left of the blocks, from the top edge to the bearing row (C4) and
// from the bearing row to the bottom edge (C5). Values: the model's C4 and C5 (outer margins).
const xv = xLeft - 300;
const halfDepth = 600;
const vdim = (y1: number, y2: number, label: string) =>
`<line x1="${xv}" y1="${y1}" x2="${xv}" y2="${y2}" stroke="#55606E" stroke-width="6"></line><line x1="${xv - 50}" y1="${y1}" x2="${xv + 50}" y2="${y1}" stroke="#55606E" stroke-width="6"></line><line x1="${xv - 50}" y1="${y2}" x2="${xv + 50}" y2="${y2}" stroke="#55606E" stroke-width="6"></line><text x="${xv - 90}" y="${(y1 + y2) / 2 + 30}" text-anchor="end" font-size="90" fill="#18212B">${label}</text>`;
parts.push(vdim(-halfDepth, 0, `C4 ${Math.round(d(f.no).leftMm)}`));
parts.push(vdim(0, halfDepth, `C5 ${Math.round(d(k.no).rightMm)}`));
return `<svg viewBox="-1900 -1300 3800 2600" width="100%" style="max-width: 560px; height: auto" role="img" aria-label="교량받침 상세 평면: 쌍 ${pair.frontNo}·${pair.backNo}, 블록 한 줄, 교축·교각축 방향, C1·C2·C3, C4·C5, 도면값 겹쳐 보기">${parts.join('')}</svg>`;
}