- 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>
106 lines
4.1 KiB
JavaScript
106 lines
4.1 KiB
JavaScript
/* 152-5 노면공 강조 헬퍼 — 포장층 범위 표식 · 고른 노면공 포장층만 is-active · 카드 누름(③ 덮는 구조물)에서 노면공 뺌을
|
|
* Node 로 돌려 표준출력 JSON 한 벌로. TS 는 그 자리에서 트랜스파일 · SVG 그릇은 쓰는 만큼만 흉내.
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
|
|
class FakeNode {
|
|
constructor(tag) {
|
|
this.tagName = tag;
|
|
this.children = [];
|
|
this.dataset = {};
|
|
this.attrs = {};
|
|
this.style = {};
|
|
this._classes = new Set();
|
|
const self = this;
|
|
this.classList = {
|
|
contains: (name) => self._classes.has(name),
|
|
toggle: (name, on) => (on ? self._classes.add(name) : self._classes.delete(name)),
|
|
};
|
|
}
|
|
setAttribute(key, value) {
|
|
this.attrs[key] = String(value);
|
|
if (key === "class") this._classes = new Set(String(value).split(/\s+/).filter(Boolean));
|
|
}
|
|
append(...kids) {
|
|
this.children.push(...kids);
|
|
}
|
|
querySelectorAll(selector) {
|
|
const name = selector.slice(1);
|
|
const all = (node) => node.children.flatMap((kid) => [kid, ...all(kid)]);
|
|
return all(this).filter((kid) => kid.classList.contains(name));
|
|
}
|
|
}
|
|
globalThis.document = { createElementNS: (_, tag) => new FakeNode(tag) };
|
|
|
|
function loadTs(file, stubs = {}) {
|
|
return makeLoader({
|
|
root: ROOT,
|
|
cache: false,
|
|
requireFor: (full) => (request) => {
|
|
if (stubs[request]) return stubs[request];
|
|
throw new Error(`stub 없음: ${request}`);
|
|
},
|
|
}).loadTs(file);
|
|
}
|
|
|
|
const surface = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Design_Surface.ts"), {
|
|
"./logic/B06_Section_Cross_Design_Surface_Geom": loadTs(
|
|
path.join(ROOT, "B06_Section", "logic", "B06_Section_Cross_Design_Surface_Geom.ts"),
|
|
),
|
|
});
|
|
const selection = loadTs(path.join(ROOT, "A00_Common", "design", "design_selection.ts"), {
|
|
"../../common_util/common_util_pipe_match": { PIPE_MATCH_M: 0.51 }, // 찾는 거리 정의 자리(472-6)
|
|
"../b_page_state": { readState: () => null, writeState: () => {} },
|
|
});
|
|
|
|
const out = {};
|
|
|
|
// 포장층 — 같은 측점 노면공 둘(겹침) · 범위 표식
|
|
const svg = new FakeNode("svg");
|
|
const edge = (offset) => ({ offset_m: offset, elevation_m: 100 });
|
|
const design = { carriageway_edges: { left: edge(-2), right: edge(2) }, pavement_thickness_m: 0.2 };
|
|
const entry = (start, end) => ({
|
|
type_id: "pavement_concrete",
|
|
spec: null,
|
|
thickness_m: 0.2,
|
|
start_m: start,
|
|
end_m: end,
|
|
widening_on: true,
|
|
});
|
|
surface.appendPavementOverlay(
|
|
svg,
|
|
design,
|
|
(v) => v,
|
|
(v) => v,
|
|
[entry(0, 40), entry(20, 60)],
|
|
);
|
|
const layers = () => svg.querySelectorAll(".b06-chart__pavement");
|
|
const active = () => layers().map((layer) => layer.classList.contains("is-active"));
|
|
out.marks = layers().map((layer) => ({ ...layer.dataset }));
|
|
surface.highlightPavement(svg, { type_id: "pavement_concrete", start_m: 60, end_m: 20 });
|
|
out.pickSecond = active();
|
|
surface.highlightPavement(svg, { type_id: "gravel_surfacing", start_m: 20, end_m: 60 });
|
|
out.otherType = active();
|
|
surface.highlightPavement(svg, { type_id: "pavement_concrete", start_m: 0, end_m: 40 });
|
|
out.pickFirst = active();
|
|
surface.highlightPavement(svg, undefined);
|
|
out.cleared = active();
|
|
|
|
// 카드 누름 — ③ 덮는 구조물에서 노면공 뺌 · ① id 길은 그대로
|
|
const pave = { structure_id: "pave", type_id: "pavement_concrete", start_m: 0, end_m: 40 };
|
|
const wall = { structure_id: "wall", type_id: "retaining_wall", start_m: 10, end_m: 30 };
|
|
const coverable = (s) => s.type_id !== "pavement_concrete";
|
|
const resolve = (sel, list, fn) => selection.resolveSelection(sel, [], list, fn);
|
|
out.cover = {
|
|
default: resolve({ chainageM: 5, structureId: null }, [pave]).structureId,
|
|
skipped: resolve({ chainageM: 5, structureId: null }, [pave], coverable).structureId,
|
|
wallFirst: resolve({ chainageM: 20, structureId: null }, [pave, wall], coverable).structureId,
|
|
byId: resolve({ chainageM: 5, structureId: "pave" }, [pave], coverable).structureId,
|
|
};
|
|
|
|
process.stdout.write(JSON.stringify(out));
|