/* ============================================================================= * B06_Section_UI_Cross_Wall.ts * 기슭막이 벽 **그리기**(기하 = `logic/B06_Section_Cross_Wall_Geom` · 472-3) — 배관 세트 벽 * (`_Cross_Culvert_Geom`/`_Culvert`)과 독립 기슭막이(`_Cross_Revetment`)가 같은 산식·같은 도형을 쓰도록 뽑아낸 층이다 * (2026-08-28 사용자: "배관용에서 배관만 빼면 대부분 동일해야"). 벽 1매의 합성 단면 * (하부 사다리꼴 + 상부 평행사변형, 배면 수직·전면 1:0.3)과 그 돌쌓기 표현은 여기 하나뿐. * * 관 유입·유출 흙막이 · 추가 흙막이 · 사면안정 흙막이 · 옹벽이 모두 이 함수 하나로 선다. * 형태가 바꾸는 것은 안 무늬(`_Cross_Wall_Hatch`)뿐 — 외곽은 높이·자리·기울기로만 정함. * ========================================================================== */ import type { OffsetPoint, WallLayout } from "./logic/B06_Section_Cross_Culvert_Types"; import { appendWallHatch } from "./B06_Section_UI_Cross_Wall_Hatch"; const SVG_NS = "http://www.w3.org/2000/svg"; function polygon( points: Array<[number, number]>, className: string, tooltip: string, ): SVGPolygonElement { const shape = document.createElementNS(SVG_NS, "polygon"); shape.setAttribute("points", points.map(([px, py]) => `${px},${py}`).join(" ")); shape.setAttribute("class", className); if (tooltip) { const title = document.createElementNS(SVG_NS, "title"); title.textContent = tooltip; shape.append(title); } return shape; } /** * 벽 1매를 SVG로 그린다 — 폴리곤 + 대각 이음선 + 계류측 기운 띠의 돌쌓기 해칭. * 배관 오버레이(`_Cross_Culvert` 161~246행)와 **같은 그리기**. 선택·강조 배선은 호출자 * 몫이라 여기서는 본체 폴리곤만 돌려준다. `keyId`는 clipPath id 중복 방지용. */ export function drawRevetWall( layer: SVGElement, wall: WallLayout, x: (offset: number) => number, toDisplayY: (elevation: number) => number, className: string, tooltip: string, keyId: string, ): SVGPolygonElement { const revetShape = polygon( wall.points.map((p) => [x(p.offset), toDisplayY(p.elevation)] as [number, number]), className, tooltip, ); layer.append(revetShape); // 이음선 + **형태별 표현**(돌/콘크리트/돌망태/통나무/바자)은 공용 해칭이 맡는다 // (2026-08-30 사용자 지시 3) — 배관 오버레이와 같은 함수를 쓴다. appendWallHatch(layer, wall, x, toDisplayY, keyId); return revetShape; } /** 성토·절토 접속선(공사 계획선) 폴리라인 — 설계선과 같은 보라 실선. */ export function appendPlanLine( layer: SVGElement, points: OffsetPoint[], x: (offset: number) => number, toDisplayY: (elevation: number) => number, tooltip: string, className = "b06-chart__design-cross", ): void { if (points.length < 2) return; const line = document.createElementNS(SVG_NS, "polyline"); line.setAttribute( "points", points.map((p) => `${x(p.offset)},${toDisplayY(p.elevation)}`).join(" "), ); line.setAttribute("class", className); if (tooltip) { const title = document.createElementNS(SVG_NS, "title"); title.textContent = tooltip; line.append(title); } layer.append(line); } /** * 벽 안으로 지나가는 다른 선(원지반 · 설계선 · 비탈 · 다른 외곽)을 가린다(66-5) — 흙막이 · 옹벽을 * 바탕색 덮개와 함께 맨 위로 올림. 벽 자기 외곽 · 무늬는 그대로. 관 · 클릭 판정면 · 글은 그 위로 * 다시 올려 지금 차례(관이 벽을 지나감 · 판정면 맨 위)를 지킨다. */ export function raiseWalls(layer: SVGElement): void { const kids = [...layer.children]; const groups = kids .filter((el) => el.classList.contains("b06-chart__culvert-revet")) .map((wall) => { // 무늬 = 벽 바로 뒤의 clipPath + 잘린 묶음(`appendWallHatch`) const hatch: Element[] = []; let next = wall.nextElementSibling; while ( next && (next.tagName === "clipPath" || next.getAttribute("clip-path")?.startsWith("url(#b06-revet-clip-")) ) { hatch.push(next); next = next.nextElementSibling; } const cover = document.createElementNS(SVG_NS, "polygon"); cover.setAttribute("points", wall.getAttribute("points") ?? ""); cover.setAttribute("class", "b06-chart__wall-cover"); return [cover, wall, ...hatch]; }); if (!groups.length) return; for (const group of groups) layer.append(...group); layer.append( ...kids.filter((el) => el.matches(".b06-chart__culvert-pipe, .b06-chart__culvert-revet-hit, text"), ), ); }