Files
Aislo/D03_PlanAnalysis/D03_PlanAnalysis_UI_Cross.ts
T
eomsangdonandClaude Opus 5.5 50e9c1b015 feat(530-3): D03 예정노선 분석 화면 — 평면 · 지점 끌기 · 더 받기 · 갈래 카드 · 측점 · 지반 횡단 · 3D
- 평면 = 위성 + 도엽 등고선 + 다른 갈래(옅게) + 고른 노선 + 측점(누가 = 등록 시작부터) + 지점 끌기 겹
- 끈 지점 = 캐시 · 받기 · 분석 · 보기는 points 로 실어 보냄 · [저장] 때만 D02 규칙으로 정본
- 연도별 갈래 넷 카드(연장 · 최대 기울기 · 위반 수) · 고름 = 캐시 · [저장] = 서버 저장본으로 다시 셈
- 측점 누름 = 하 패널 지반선 횡단(sectionsGround · buildCrossSvg 지반만 인자 · 기본 그대로)
- 3D 모달 = 연도 DEM + 노선 + 측점 막대(코리도 · 구조물 안 부름)
- 화면 계산 logic 짝(pickMode · chainRows · joinedLine ↔ 파이썬) 거울 시험

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:11:23 +09:00

77 lines
3.1 KiB
TypeScript

/* =============================================================================
* D03_PlanAnalysis_UI_Cross.ts
* D03 하 패널 — 누른 측점의 지반선 횡단(PLAN 530-3). 계산 = 화면 TS 즉시(① 짝 `sectionsGround` ↔
* `generate_sections` · 격자 = 그 연도 DEM 평활본) · 그림 = B05 `buildCrossSvg` 지반만.
* ========================================================================== */
import { createWorkflowPanelHandle } from "@ui/ui_template_overlay";
import { stationLabel } from "../common_util/common_util_station";
import type { DtmGrid } from "../common_util/common_util_surface_sampler";
import { buildCrossSvg } from "../B05_Profile/B05_Profile_UI_RouteEdit_Cross_Draw";
import { sectionsGround } from "../B05_Profile/logic/B05_Profile_Sections_Ground";
import type { Vertex } from "./logic/D03_PlanAnalysis_Plan";
import { PLAN_STATION_INTERVAL_M } from "./D03_PlanAnalysis_UI_Map";
export interface PlanCross {
root: HTMLElement;
/** `chainage` = 등록 누가 · `localM` = 그 연도 노선 위 누가. */
show: (chainage: number, year: number, line: Vertex[], localM: number, grid: DtmGrid) => void;
clear: (text: string) => void;
}
export function createPlanCross(): PlanCross {
const root = document.createElement("section");
root.className = "d03-plan__cross";
const handle = createWorkflowPanelHandle("bottom", "down", "횡단");
const head = document.createElement("div");
head.className = "d03-plan__cross-head";
const body = document.createElement("div");
body.className = "d03-plan__cross-body";
root.append(handle.root, head, body);
let open = true;
handle.setOpen(open);
handle.root.addEventListener("click", () => {
open = !open;
root.classList.toggle("is-collapsed", !open);
handle.setOpen(open);
});
const clear = (text: string): void => {
head.textContent = "";
body.replaceChildren(Object.assign(document.createElement("p"), { textContent: text }));
delete root.dataset.chainage;
};
clear("평면에서 측점을 누르면 그 자리 지반선 횡단이 보입니다.");
return {
root,
clear,
show(chainage, year, line, localM, grid) {
const station = sectionsGround(line, [localM], grid).stations[0];
if (!station) return clear("이 측점의 지반을 읽지 못했습니다.");
const name = stationLabel(chainage, PLAN_STATION_INTERVAL_M, 1);
const z = station.center_z === null ? "—" : `${station.center_z.toFixed(2)} m`;
head.textContent = `${year}년 · ${name} · 중심 지반고 ${z}`;
root.dataset.chainage = String(chainage);
const rect = body.getBoundingClientRect();
const plot = buildCrossSvg(
{
status: "success",
chainage_m: chainage,
label: name,
uphill_side: station.uphill_side,
plan_radius_m: null,
curve_widening_m: null,
cross_half_width_m: 20,
samples: station.samples,
design: null,
},
Math.max(rect.width, 320),
Math.max(rect.height, 160),
true,
);
body.replaceChildren(plot.svg);
},
};
}