diff --git a/src/main.ts b/src/main.ts
index 07e835c..175d1f7 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -730,12 +730,12 @@ function renderFootingDrawings(box: HTMLDivElement, pier: Pier): void {
const plan = el('figure', undefined, 'footing-fig');
plan.innerHTML = footingPlanSvg(pier.model);
plan.appendChild(el('figcaption', '평면 · 1열이 아래, 열은 교축과 직각 방향 줄', 'muted small'));
- grid.append(cardCol, plan);
- box.appendChild(grid);
+ // The side view (정면) sits to the right of the plan, on the same scale (승인 2026-10-23).
const side = el('figure', undefined, 'footing-fig');
side.innerHTML = footingSideSvg(pier.model);
- side.appendChild(el('figcaption', '정면 · 점선 = 경사 선택 시 상면 (L2, h2)', 'muted small'));
- box.appendChild(side);
+ side.appendChild(el('figcaption', '정면 · 끊음 표시: 기둥과 말뚝 일부 생략 · 점선 = 경사 선택 시 상면 (L2, h2)', 'muted small'));
+ grid.append(cardCol, plan, side);
+ box.appendChild(grid);
box.appendChild(el('p', '기초 회전각 θ는 교각축 대비 회전으로, 생성 규칙은 spec에 추가 후 적용합니다 (지금은 0°).', 'muted small'));
}
diff --git a/src/style.css b/src/style.css
index d385ae8..aa56b18 100644
--- a/src/style.css
+++ b/src/style.css
@@ -800,8 +800,13 @@ body { background: #eef1f4; font-family: 'Noto Sans KR', system-ui, sans-serif;
.footing-fig { margin: 0; }
.footing-fig svg { width: 100%; height: auto; max-height: 260px; background: #ffffff; border: 1px solid #d5dde6; border-radius: 6px; }
-/* ② 말뚝 배치: 열별 본수 카드 (왼쪽) · 평면도 (오른쪽), 측면도는 아래 */
-.footing-grid { display: grid; grid-template-columns: minmax(230px, 320px) minmax(0, 1fr); gap: 12px; align-items: start; margin-top: 12px; }
+/* ② 말뚝 배치: 열별 본수 카드 · 평면도 · 정면을 한 줄에 (같은 축척). 1100px 이하는 정면을 아래 줄로, 800px 이하는 한 열로. */
+.footing-grid { display: grid; grid-template-columns: minmax(220px, 280px) auto auto; gap: 12px; align-items: start; margin-top: 12px; }
+.footing-grid .footing-fig svg { display: block; max-width: none; }
+@media (max-width: 1100px) {
+ .footing-grid { grid-template-columns: minmax(220px, 280px) auto; }
+ .footing-grid .footing-fig:last-of-type { grid-column: 1 / -1; }
+}
@media (max-width: 800px) {
.footing-grid { grid-template-columns: 1fr; }
}
diff --git a/src/view/footing-svg.ts b/src/view/footing-svg.ts
index b6ec64a..580e4cd 100644
--- a/src/view/footing-svg.ts
+++ b/src/view/footing-svg.ts
@@ -1,20 +1,33 @@
/**
* 확대기초·말뚝 그림 (2단계, 승인 2026-10-23): plan and side views as SVG strings, drawn from the model (footings, piles,
* columns) and the input values. Pure: no DOM, so that it can be tested. Units: m in the model; the labels show mm.
+ * Both views use one scale (FOOTING_PX_PER_M), so they can sit side by side. The side view breaks the column and the piles
+ * (끊음 표시) so that its height stays near the plan's.
*/
import type { PierModel } from '../core/geometry';
+export const FOOTING_PX_PER_M = 22;
+/** Side view: the column is shown this far above the footing top, the piles this far below the footing bottom (m). */
+const COLUMN_STUB = 3;
+const PILE_STUB = 4;
+
const mm = (v: number) => Math.round(v * 1000);
+function svgOf(x0: number, y0: number, w: number, h: number, label: string, body: string): string {
+ const pw = Math.round(w * FOOTING_PX_PER_M);
+ const ph = Math.round(h * FOOTING_PX_PER_M);
+ return ``;
+}
+
/** Plan view: the footing rectangle (length along the 교축, width across), the pile circles, the column circle, the axis. */
export function footingPlanSvg(model: PierModel): string {
const f = model.footings[0];
if (!f) return '';
const pad = 0.8;
const x0 = f.s - f.length / 2 - pad;
- const x1 = f.s + f.length / 2 + pad;
const y0 = -f.width / 2 - pad;
- const y1 = f.width / 2 + pad;
+ const w = f.length + 2 * pad;
+ const h = f.width + 2 * pad;
const piles = model.piles.filter((p) => Math.abs(p.s - f.s) <= f.length / 2 + 1e-6);
const parts: string[] = [];
parts.push(``);
@@ -24,42 +37,47 @@ export function footingPlanSvg(model: PierModel): string {
for (const c of model.columns) {
parts.push(``);
}
- // Pier axis (dash-dot) through the footing centre.
- parts.push(``);
- // Dimension labels: length and width, in mm.
+ parts.push(``);
parts.push(`${mm(f.length)}`);
parts.push(`${mm(f.width)}`);
- return ``;
+ return svgOf(x0, y0, w, h, '확대기초·말뚝 평면', parts.join(''));
}
-/** Side view (elevation): the footing, the piles down to their tips, and the column above the footing (EL up). */
+/** Side view (elevation, EL up): the footing, the piles, and the column stub above the footing, both broken (끊음). */
export function footingSideSvg(model: PierModel): string {
const f = model.footings[0];
if (!f) return '';
const piles = model.piles.filter((p) => Math.abs(p.s - f.s) <= f.length / 2 + 1e-6);
- const tipEl = piles.length ? Math.min(...piles.map((p) => p.bottom)) : f.bottom;
- const topEl = model.levelBottom;
+ const pileTop = piles.length ? Math.max(...piles.map((p) => p.top)) : f.bottom;
+ const pileLen = piles.length ? piles[0].top - piles[0].bottom : 0;
const pad = 0.8;
const x0 = f.s - f.length / 2 - pad;
- const x1 = f.s + f.length / 2 + pad;
- const y0 = -(topEl + pad);
- const y1 = -(tipEl - pad);
+ const w = f.length + 2 * pad;
+ // Visible band in EL: from the column stub above the footing top, down to the pile stub below the footing bottom.
+ const topEl = f.top + COLUMN_STUB;
+ const botEl = f.bottom - PILE_STUB;
+ const y0 = -topEl;
+ const h = topEl - botEl;
const parts: string[] = [];
- // Elevation: y = −EL so that the level grows upward on the screen.
parts.push(``);
for (const p of piles) {
- parts.push(``);
+ const from = Math.max(p.bottom, botEl);
+ const to = Math.min(p.top, f.bottom);
+ if (to > from) parts.push(``);
}
- // Column: from the footing top up to the Level underside.
const col = model.columns[0];
if (col) {
- parts.push(``);
+ parts.push(``);
+ // Break marks on the column stub and at the pile bottom.
+ parts.push(``);
+ }
+ if (piles.length) {
+ parts.push(``);
}
- // Labels: the footing height and the pile length, in mm.
parts.push(`h1 ${mm(f.top - f.bottom)}`);
if (piles.length) {
- const pileLen = piles[0].top - piles[0].bottom;
- parts.push(`말뚝 ${mm(pileLen)}`);
+ parts.push(`말뚝 ${mm(pileLen)} (끊음)`);
}
- return ``;
+ void pileTop;
+ return svgOf(x0, y0, w, h, '확대기초·말뚝 측면', parts.join(''));
}