Files
Pier_v1/src/view/abut-bearing-svg.ts
T

106 lines
5.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-03, 시안 ② 교량받침 카드): 평면, 교축 방향 단면, 솔플레이트 상세. 순수 문자열 함수.
* 입력은 받침 표에서 이미 계산한 값뿐이다(교대 모델을 다시 읽지 않는다). 치수는 mm, EL은 m.
*/
export interface AbutBearingDetail {
no: number;
/** 블럭 평면 (정사각), 몰탈패드 평면 (정사각), mm. */
blockMm: number;
padMm: number;
/** 솔플레이트 교직 L × 교축 W (mm). 받침 본체 평면은 입력이 없어 그리지 않는다. */
L: number;
W: number;
/** 높이 (mm): 블럭 콘크리트 h1, 패드 h2, 받침 h3, 솔플레이트 h4 = T. */
h1: number;
h2: number;
h3: number;
h4: number;
T1: number;
T2: number;
/** 블럭 평면 회전 (deg), 교대축 직각 기준. */
rotDeg: number;
/** 솔플레이트 경사 (%). */
S: number;
seatEl: number;
z: number;
}
const INK = '#18212b';
const MUTED = '#55606e';
const ORANGE = '#c46a1a';
const text = (x: number, y: number, s: string, anchor = 'middle', 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>`;
const square = (cx: number, cy: number, w: number, h: number, style: string) =>
`<rect x="${(cx - w / 2).toFixed(1)}" y="${(cy - h / 2).toFixed(1)}" width="${w.toFixed(1)}" height="${h.toFixed(1)}" ${style}/>`;
/** 평면: 블럭 1200, 몰탈패드 1000 (점선), 솔플레이트 L × W (주황). 블럭은 받침 방위각만큼 돈다. */
export function abutBearingPlanSvg(d: AbutBearingDetail): string {
const k = 0.17; // px per mm
const cx = 150;
const cy = 130;
const turn = `transform="rotate(${(-d.rotDeg).toFixed(3)} ${cx} ${cy})"`;
return [
`<svg viewBox="0 0 300 270" width="100%" role="img" aria-label="받침 ${d.no} 평면: 블럭 ${d.blockMm}, 몰탈패드 ${d.padMm}, 솔플레이트 ${d.L} × ${d.W}, 회전 ${d.rotDeg.toFixed(2)}°">`,
`<g ${turn}>`,
square(cx, cy, d.blockMm * k, d.blockMm * k, `fill="#dfe5ec" stroke="${MUTED}"`),
square(cx, cy, d.padMm * k, d.padMm * k, `fill="none" stroke="${MUTED}" stroke-dasharray="4 3"`),
square(cx, cy, d.L * k, d.W * k, `fill="#f0c9a0" fill-opacity="0.6" stroke="${ORANGE}"`),
`</g>`,
text(cx, cy - (d.blockMm * k) / 2 - 8, `${d.blockMm}`),
text(cx, cy + 4, `솔플 ${d.L} × ${d.W}`),
text(cx, cy + (d.blockMm * k) / 2 + 16, `패드 ${d.padMm} (점선)`, 'middle', MUTED),
text(cx, 262, `받침 ${d.no} · 회전 ${d.rotDeg.toFixed(2)}° (방위각)`, 'middle', MUTED),
'</svg>',
].join('');
}
/** 교축 방향 단면 (높이 2배 과장): 블럭 h1, 패드 h2, 받침 h3, 솔플레이트 h4. E = h1 + h2 + h3 + h4. */
export function abutBearingSectionSvg(d: AbutBearingDetail): string {
const kx = 0.17;
const ky = 0.34; // 2× exaggerated heights
const cx = 150;
const base = 215;
const E = d.h1 + d.h2 + d.h3 + d.h4;
const layer = (bottom: number, h: number, w: number, style: string) =>
`<rect x="${(cx - (w * kx) / 2).toFixed(1)}" y="${(base - (bottom + h) * ky).toFixed(1)}" width="${(w * kx).toFixed(1)}" height="${(h * ky).toFixed(1)}" ${style}/>`;
const at = (mm: number) => base - mm * ky;
const right = cx + (d.blockMm * kx) / 2 + 6;
return [
`<svg viewBox="0 0 330 250" width="100%" role="img" aria-label="받침 ${d.no} 단면: h1 ${d.h1}, h2 ${d.h2}, h3 ${d.h3}, h4 ${d.h4}, E ${E}">`,
`<line x1="20" y1="${base}" x2="300" y2="${base}" stroke="${MUTED}"/>`,
layer(0, d.h1, d.blockMm, `fill="#dfe5ec" stroke="${MUTED}"`),
layer(d.h1, d.h2, d.padMm, `fill="#c9d1da" stroke="${MUTED}"`),
layer(d.h1 + d.h2, d.h3, d.L - 100, `fill="#b9c3ce" stroke="${INK}"`),
layer(d.h1 + d.h2 + d.h3, d.h4, d.L, `fill="#f0c9a0" stroke="${ORANGE}"`),
text(right, at(d.h1 / 2) + 4, `h1 ${d.h1}`, 'start'),
text(right, at(d.h1 + d.h2 / 2) + 4, `h2 ${d.h2}`, 'start'),
text(right, at(d.h1 + d.h2 + d.h3 / 2) + 4, `h3 ${d.h3}`, 'start'),
text(right, at(E - d.h4 / 2) + 4, `h4 ${d.h4}`, 'start'),
text(cx, at(E) - 10, `E = ${E}`),
text(24, base + 16, `교좌면 EL.${d.seatEl.toFixed(3)}`, 'start', MUTED),
text(24, at(d.h1 + d.h2) - 4, `z EL.${d.z.toFixed(3)}`, 'start', MUTED),
text(cx, 244, '교축 방향 · 높이 2배 과장', 'middle', MUTED),
'</svg>',
].join('');
}
/** 솔플레이트 상세: 길이 L, 두께 T1 → T2 (경사 S). 두께는 과장해서 그린다. */
export function abutSolplateSvg(d: AbutBearingDetail): string {
const kx = 0.3;
const ky = 2.2; // thickness exaggerated
const x0 = 45;
const x1 = x0 + d.L * kx;
const base = 120;
return [
`<svg viewBox="0 0 330 190" width="100%" role="img" aria-label="받침 ${d.no} 솔플레이트: L ${d.L}, T1 ${d.T1}, T2 ${d.T2}, S ${d.S.toFixed(3)} %">`,
`<polygon points="${x0},${base} ${x1.toFixed(1)},${base} ${x1.toFixed(1)},${(base - d.T2 * ky).toFixed(1)} ${x0},${(base - d.T1 * ky).toFixed(1)}" fill="#f0c9a0" stroke="${ORANGE}"/>`,
text(x0 - 4, base - (d.T1 * ky) / 2 + 4, `T1 ${d.T1}`, 'end'),
text(x1 + 4, base - (d.T2 * ky) / 2 + 4, `T2 ${d.T2}`, 'start'),
text((x0 + x1) / 2, base + 18, `L ${d.L} · W ${d.W}`),
text((x0 + x1) / 2, base - Math.max(d.T1, d.T2) * ky - 10, `S ${d.S.toFixed(3)} % · T ${d.h4}`),
text(165, 180, '솔플레이트 상세 · 두께 과장 · 가정 (QA-15)', 'middle', MUTED),
'</svg>',
].join('');
}