- logic 새 파일 다섯 — Cross_Wall_Geom(벽 1매) · Cross_Wall_Hatch_Geom(무늬 띠 · 물빼기 · 도수로 띠 · 원지반선) · Cross_Excavation_Geom(벽 터파기) · Cross_Design_Surface_Geom(암선 · 포장층) · Cross_Revetment_Geom(독립 기슭막이 배치) - logic 으로 옮김 — Body_Guard → Cross_Body_Guard · Structure_Layouts · Route_Carry_Patch(내용 그대로 · import 경로만) - inferStationInterval → common_util_station(글자표 없는 자리 · common_util_svg 는 다시 내보냄) — Node 묶음 ui_template_locale 끌림 끊음 - 부르는 쪽 import 줄 · 등록부 ts 경로 · 시험 · 도우미 경로 - test_472_3 GEOMETRY_PULLS 다섯 줄 걷음 · Wall_Hatch · Excavation · Design_Surface 세 줄은 Culvert · Box · Ford 그림 파일(518-2)이 그리기 함수로 부르는 동안 남김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
4.2 KiB
TypeScript
88 lines
4.2 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_UI_Cross_Revetment.ts
|
|
* 독립 기슭막이 **그리기** — 자리 · 단 · 트림(기하)은 `logic/B06_Section_Cross_Revetment_Geom`(472-3).
|
|
* 그리기(폴리곤·이음선·돌·성토부선)는 배관과 같은 공용 `_Cross_Wall`.
|
|
* ========================================================================== */
|
|
|
|
import { tagShape } from "../common_util/common_util_pick_tag";
|
|
import {
|
|
FILL_SLOPE_RATIO_MIN,
|
|
REVET_EMBED_DEPTH_M,
|
|
} from "./logic/B06_Section_UI_Cross_Culvert_Const";
|
|
import type { RevetmentLayout } from "./logic/B06_Section_Cross_Revetment_Geom";
|
|
import { foundationChoice } from "./logic/B06_Section_Cross_Excavation_Geom";
|
|
import { appendWallTrench } from "./B06_Section_UI_Cross_Excavation";
|
|
import { appendPlanLine, drawRevetWall } from "./B06_Section_UI_Cross_Wall";
|
|
|
|
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
|
/** 횡단 카드에 독립 기슭막이(1단+다단)를 그린다 — 배관 벽과 같은 도형. 그렸으면 setter. */
|
|
export function appendRevetmentOverlay(
|
|
svg: SVGElement,
|
|
layout: RevetmentLayout | null,
|
|
x: (offset: number) => number,
|
|
y: (elevation: number) => number,
|
|
onSelect?: () => void,
|
|
): ((active: boolean) => void) | null {
|
|
if (!layout || !layout.walls.length) return null;
|
|
// 성토부선(벽 사이·벽 아래) 먼저 — 벽 밑에 깔린다.
|
|
for (const segment of layout.fillSegments) {
|
|
if (segment.kind === "cut") continue;
|
|
appendPlanLine(
|
|
svg,
|
|
segment.points,
|
|
x,
|
|
y,
|
|
`${layout.name} 성토부선 — 사면길이 ${segment.lengthM.toFixed(2)}m` +
|
|
(segment.overLimit ? " (법정 5m 이상 — 단 추가 검토)" : " (법정 5m 이내)") +
|
|
` · 성토 물매 1:${(segment.ratio ?? 1.2).toFixed(2)}`,
|
|
);
|
|
}
|
|
// 터파기는 벽보다 **먼저** — 파선이 벽 밑에 깔린다. 기초 축이 비어 있으면 안 그린다.
|
|
const trenchFoundation = foundationChoice(layout.foundation);
|
|
for (const wall of layout.walls) {
|
|
appendWallTrench(svg, wall, trenchFoundation, x, y);
|
|
}
|
|
const drawn: SVGPolygonElement[] = [];
|
|
layout.walls.forEach((wall, index) => {
|
|
const keyId = index === 0 ? "own" : `own-extra${index - 1}`;
|
|
const tooltip =
|
|
`${layout.name} ${wall.form ?? ""} H=${(wall.height + REVET_EMBED_DEPTH_M).toFixed(1)}m` +
|
|
`(상단 = 성토선 접점, 전면 1:${wall.lean}(품셈 13-4-4 [주]⑪ 표준경사))` +
|
|
(wall.floatGapM > 0.01
|
|
? ` · ⚠ 바닥 원지반 이격 ${wall.floatGapM.toFixed(2)}m — 하부 지지 별도`
|
|
: ` · 근입 ${REVET_EMBED_DEPTH_M.toFixed(2)}m`) +
|
|
(wall.lengthM ? ` · 연장 ${wall.lengthM.toFixed(1)}m` : "") +
|
|
// 「좌우로 옮겨도 안 움직인다」의 까닭 — 배관 벽 툴팁과 같은 문구(2026-09-07).
|
|
(wall.shiftFloorM
|
|
? ` · ⚠ 좌우 이동 하한 ${wall.shiftFloorM.toFixed(2)}m — 성토선 각도(1:${FILL_SLOPE_RATIO_MIN})를` +
|
|
` 지키려면 그만큼은 나가 있어야 함. 그 아래 값을 넣으면 벽이 안 움직임`
|
|
: "");
|
|
const shape = drawRevetWall(svg, wall, x, y, "b06-chart__culvert-revet", tooltip, keyId);
|
|
if (onSelect) shape.classList.add("is-selectable");
|
|
if (layout.linked) shape.classList.add("is-linked");
|
|
tagShape(shape, layout.structureId, keyId); // 신원표(323-5)
|
|
drawn.push(shape);
|
|
});
|
|
// 클릭 판정용 투명 겹면 — **맨 위**에 얹는다. 돌 해칭이 벽 폴리곤을 덮어 직접 핸들러를
|
|
// 달면 가운데 클릭이 돌에 먹힌다(배관 벽과 같은 규칙 — 판정면만 위로).
|
|
if (onSelect) {
|
|
for (const wall of layout.walls) {
|
|
const hit = document.createElementNS(SVG_NS, "polygon");
|
|
hit.setAttribute(
|
|
"points",
|
|
wall.points.map((p) => `${x(p.offset)},${y(p.elevation)}`).join(" "),
|
|
);
|
|
hit.setAttribute("class", "b06-chart__culvert-revet-hit");
|
|
hit.addEventListener("click", (event) => {
|
|
event.stopPropagation();
|
|
onSelect();
|
|
});
|
|
svg.append(hit);
|
|
}
|
|
}
|
|
return (active: boolean): void => {
|
|
for (const polygon of drawn) polygon.classList.toggle("is-active", active);
|
|
};
|
|
}
|