diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Cross.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Cross.ts index 00571394c..2f2c41eee 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Cross.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Cross.ts @@ -1,10 +1,12 @@ /* ============================================================================= * D03_PlanAnalysis_UI_Cross.ts - * D03 하 패널 — 누른 측점의 지반선 횡단(PLAN 530-3). 계산 = 화면 TS 즉시(① 짝 `sectionsGround` ↔ - * `generate_sections` · 격자 = 그 연도 DEM 평활본) · 그림 = B05 `buildCrossSvg` 지반만. + * D03 하 패널 — 누른 측점의 지반선 + 예상 횡단(PLAN 530-3 · 544-2). 계산 = 화면 TS 즉시(① 짝 `sectionsGround` ↔ + * `generate_sections` · 격자 = 그 연도 DEM 평활본) · 예상 = `logic/D03_PlanAnalysis_Expect`(표준 횡단 기본값 · + * 계획고 = 중심 지반고 · 표준값 = `sections/context` 세션 캐시) · 그림 = B05 `buildCrossSvg`. * ========================================================================== */ import "../B05_Profile/B05_Profile_UI_Style_RouteEdit.css"; +import { CURRENT_PROJECT_ID_KEY } from "@config/config_frontend"; 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"; @@ -13,7 +15,9 @@ import { sectionsGround, type StationGround, } from "../B05_Profile/logic/B05_Profile_Sections_Ground"; +import { fetchSectionContext } from "../B06_Section/B06_Section_Api_Context"; import type { Vertex } from "./logic/D03_PlanAnalysis_Plan"; +import { expectCross, type ExpectStandard } from "./logic/D03_PlanAnalysis_Expect"; import { PLAN_STATION_INTERVAL_M } from "./D03_PlanAnalysis_UI_Map"; export interface PlanCross { @@ -29,6 +33,17 @@ export interface PlanCross { clear: (text: string) => void; } +/** 표준 횡단 기본값(config · 서버 한 번 · 세션 캐시) — 못 받으면 null(지반선만). */ +export function loadExpectStandard(projectId: string): Promise { + return fetchSectionContext(projectId).then( + (context) => ({ + standard: context.standard_cross_section as ExpectStandard["standard"], + rockBoundaryM: context.rock_boundary_default_offset_m, + }), + () => null, + ); +} + export function createPlanCross(): PlanCross { const root = document.createElement("section"); root.className = "d03-plan__cross"; @@ -51,7 +66,9 @@ export function createPlanCross(): PlanCross { body.replaceChildren(Object.assign(document.createElement("p"), { textContent: text })); delete root.dataset.chainage; }; - clear("평면에서 측점을 누르면 그 자리 지반선 횡단이 보입니다."); + clear("평면에서 측점을 누르면 그 자리 지반선 · 예상 횡단이 보입니다."); + let standard: ExpectStandard | null = null; + let asked: Promise | null = null; return { root, @@ -64,26 +81,42 @@ export function createPlanCross(): PlanCross { } 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); + const draw = (): void => { + const expect = standard ? expectCross(station, standard, grid) : null; + const area = expect + ? ` · 예상(표준 횡단 기본값 · 계획고 = 지반고) 절토 ${expect.design.cut_area_m2.toFixed(2)}㎡ · 성토 ${expect.design.fill_area_m2.toFixed(2)}㎡` + : ""; + head.textContent = `${year}년 · ${name} · 중심 지반고 ${z}${area}`; + 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: expect?.samples ?? station.samples, + design: expect ? { ...expect.design } : null, + }, + Math.max(rect.width, 320), + Math.max(rect.height, 160), + !expect, + ); + body.replaceChildren(plot.svg); + }; + draw(); + if (!standard) { + const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY) ?? ""; + asked ??= loadExpectStandard(projectId); + void asked.then((value) => { + standard = value; + // 그사이 다른 측점을 눌렀으면 그 측점이 다시 그림 + if (value && root.dataset.chainage === String(chainage)) draw(); + }); + } return station; }, };