|
|
|
@@ -1,3 +1,4 @@
|
|
|
|
|
import type { PavementEntry } from "@util/common_util_structure_pavement";
|
|
|
|
|
import type { CrossDesign } from "./B06_Section_Api_Fetch";
|
|
|
|
|
|
|
|
|
|
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
|
@@ -29,26 +30,80 @@ export function appendRockBoundaryOverlay(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Edge = { offset_m: number; elevation_m: number };
|
|
|
|
|
|
|
|
|
|
/** 포장사양 → 무늬(88) — 콘크리트 빗금 · 아스콘 점 · 쇄석 돌. 그 밖 = 채움만. */
|
|
|
|
|
const PAVE_MARKS: Record<string, { size: number; marks: string }> = {
|
|
|
|
|
콘크리트: { size: 6, marks: '<path d="M0,6 L6,0" class="b06-chart__pave-mark"/>' },
|
|
|
|
|
아스콘: {
|
|
|
|
|
size: 5,
|
|
|
|
|
marks: '<circle cx="1.5" cy="1.5" r="0.7" class="b06-chart__pave-mark--dot"/>',
|
|
|
|
|
},
|
|
|
|
|
쇄석: {
|
|
|
|
|
size: 9,
|
|
|
|
|
marks:
|
|
|
|
|
'<circle cx="2.5" cy="2.5" r="1.6" class="b06-chart__pave-mark"/>' +
|
|
|
|
|
'<ellipse cx="6.8" cy="6.5" rx="1.8" ry="1.2" class="b06-chart__pave-mark"/>',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
/** 무늬 id 는 문서 안에서 유일 — 카드 · 다시 그리기마다 새 번호(물넘이 빗금과 같은 방식). */
|
|
|
|
|
let paveSeq = 0;
|
|
|
|
|
|
|
|
|
|
/** 확폭 끈 구간 — 규격 폭 끝(좌 = left − 확폭좌 · 우 = right + 확폭우 · 표고는 두 끝 사이 직선). */
|
|
|
|
|
function standardEdges(edges: { left: Edge; right: Edge }, design: CrossDesign) {
|
|
|
|
|
const { left, right } = edges;
|
|
|
|
|
const span = right.offset_m - left.offset_m || 1;
|
|
|
|
|
const at = (offset: number): Edge => ({
|
|
|
|
|
offset_m: offset,
|
|
|
|
|
elevation_m:
|
|
|
|
|
left.elevation_m + ((right.elevation_m - left.elevation_m) * (offset - left.offset_m)) / span,
|
|
|
|
|
});
|
|
|
|
|
return {
|
|
|
|
|
left: at(left.offset_m - (design.widening_left_m ?? 0)),
|
|
|
|
|
right: at(right.offset_m + (design.widening_right_m ?? 0)),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 포장층 — 노면선(= 포장 윗면) 아래로 두께만큼. 노면공 범위(`section.pavement`)면 그 두께 · 무늬 ·
|
|
|
|
|
* 확폭 켬/끔(여러 건은 아래로 차례로 쌓음) · 없으면 카드 포장 켬일 때 표준 두께 채움만.
|
|
|
|
|
*/
|
|
|
|
|
export function appendPavementOverlay(
|
|
|
|
|
svg: SVGElement,
|
|
|
|
|
design: CrossDesign,
|
|
|
|
|
x: (offset: number) => number,
|
|
|
|
|
y: (elevation: number) => number,
|
|
|
|
|
pavement?: readonly PavementEntry[] | null,
|
|
|
|
|
): void {
|
|
|
|
|
const edges = design.carriageway_edges ?? design.road_edges;
|
|
|
|
|
if (!design.paved || !edges) return;
|
|
|
|
|
const thickness = design.pavement_thickness_m ?? 0.2;
|
|
|
|
|
const { left, right } = edges;
|
|
|
|
|
const polygon = document.createElementNS(SVG_NS, "polygon");
|
|
|
|
|
polygon.setAttribute(
|
|
|
|
|
"points",
|
|
|
|
|
[
|
|
|
|
|
`${x(left.offset_m)},${y(left.elevation_m)}`,
|
|
|
|
|
`${x(right.offset_m)},${y(right.elevation_m)}`,
|
|
|
|
|
`${x(right.offset_m)},${y(right.elevation_m - thickness)}`,
|
|
|
|
|
`${x(left.offset_m)},${y(left.elevation_m - thickness)}`,
|
|
|
|
|
].join(" "),
|
|
|
|
|
);
|
|
|
|
|
polygon.setAttribute("class", "b06-chart__pavement");
|
|
|
|
|
svg.append(polygon);
|
|
|
|
|
if (!edges) return;
|
|
|
|
|
const layers = pavement?.length ? pavement : design.paved ? [null] : [];
|
|
|
|
|
let depth = 0;
|
|
|
|
|
for (const entry of layers) {
|
|
|
|
|
const thickness = entry?.thickness_m ?? design.pavement_thickness_m ?? 0.2;
|
|
|
|
|
const { left, right } = entry && !entry.widening_on ? standardEdges(edges, design) : edges;
|
|
|
|
|
const points = [
|
|
|
|
|
`${x(left.offset_m)},${y(left.elevation_m - depth)}`,
|
|
|
|
|
`${x(right.offset_m)},${y(right.elevation_m - depth)}`,
|
|
|
|
|
`${x(right.offset_m)},${y(right.elevation_m - depth - thickness)}`,
|
|
|
|
|
`${x(left.offset_m)},${y(left.elevation_m - depth - thickness)}`,
|
|
|
|
|
].join(" ");
|
|
|
|
|
depth += thickness;
|
|
|
|
|
const polygon = document.createElementNS(SVG_NS, "polygon");
|
|
|
|
|
polygon.setAttribute("points", points);
|
|
|
|
|
polygon.setAttribute("class", "b06-chart__pavement");
|
|
|
|
|
svg.append(polygon);
|
|
|
|
|
const spec = entry?.spec;
|
|
|
|
|
const mark = spec ? PAVE_MARKS[spec] : undefined;
|
|
|
|
|
if (!spec || !mark) continue;
|
|
|
|
|
const id = `b06-pave-hatch-${(paveSeq += 1)}`;
|
|
|
|
|
const defs = document.createElementNS(SVG_NS, "defs");
|
|
|
|
|
defs.innerHTML = `<pattern id="${id}" patternUnits="userSpaceOnUse" width="${mark.size}" height="${mark.size}">${mark.marks}</pattern>`;
|
|
|
|
|
const hatch = document.createElementNS(SVG_NS, "polygon");
|
|
|
|
|
hatch.setAttribute("points", points);
|
|
|
|
|
hatch.setAttribute("class", "b06-chart__pavement-hatch");
|
|
|
|
|
hatch.setAttribute("fill", `url(#${id})`);
|
|
|
|
|
hatch.dataset.paveSpec = spec;
|
|
|
|
|
svg.append(defs, hatch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|