feat(D03): 측점 횡단 판에 예상 횡단 — 표준 횡단 기본값 설계선 · 절 · 성토 ㎡(PLAN 544-2)
- UI_Cross — 표준값 = sections/context 세션 캐시(한 번) · 받기 전엔 지반선 먼저 · 받으면 같은 측점 다시 그림 - 머리 줄 「예상(표준 횡단 기본값 · 계획고 = 지반고) 절토 · 성토 ㎡」 · 미교차 = 격자로 넓힌 지반 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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<ExpectStandard | null> {
|
||||
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<ExpectStandard | null> | 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;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user