feat(509-5 · 509-2 B05 추천 지형): 분석 지형 고르기 = 추천 노선 창 안 · 지형마다 추천 미리 셈 · [적용] = 창 지형이 설계 지형 · 평면은 지형 이름만 · 설계 지형 격자 하나(수치지형도 적용이면 그 격자)

- 전처리 미리 셈이 고를 수 있는 지형마다(설계 지형 먼저 · 수치지형도는 DB 모델 있을 때만) 다섯 갈래 + 초기 종단
- 창 지형 바꿈 = 그 지형 저장본만 · 없으면 409 안내(+[재계산]) · 기본값 판정에서 지형 뺌
- POST /route/initial terrain = 창 지형 · [적용] draft.terrain = 창 지형 · 손 [저장]은 지형 안 바꿈(서버도 as_initial 일 때만)
- 평면 분석 지형 고르기 · 화면 취향(routeedit-terrain) 걷음 · 지반고 · 묶음 초안 = 설계 지형(null) · 적용 뒤 받아 둔 격자 버림
- 시험 test_509_5 · test_509_2 · 걷은 고르기를 보던 옛 시험 새 동작으로(352_3 건너뜀)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:41:20 +09:00
co-authored by Claude Opus 5.5
parent 23fd2f6f8d
commit 4eec3a4b37
30 changed files with 441 additions and 169 deletions
@@ -17,7 +17,11 @@
* 요청했을 때 서버가 답으로 준 값(진짜 기본값)을 기억해 둔 것이다.
* ========================================================================== */
import { fetchRoutePlan, type RoutePlanResponse } from "./B05_Profile_Api_Replan";
import {
fetchRoutePlan,
type AnalysisTerrain,
type RoutePlanResponse,
} from "./B05_Profile_Api_Replan";
import {
fetchPrecomputeProgress,
fetchRouteInitial,
@@ -57,6 +61,8 @@ export interface InitialPanelParams {
planMinRadiusM: () => number;
/** 받은 노선을 편집값으로 싣는다 — 되돌리기 한 걸음으로 쌓인다. */
apply: (snapshot: RouteEditSnapshot, message: string) => void;
/** 추천 창이 고를 지형 · 지금 설계 지형(509-5) — 못 읽었으면 null(설계 지형 하나). */
terrains: () => { sources: AnalysisTerrain[]; design: AnalysisTerrain } | null;
}
export interface InitialPanel {
@@ -126,6 +132,7 @@ export function createInitialPanel(params: InitialPanelParams): InitialPanel {
criteria: RouteInitialCriteria | null,
withProfile: boolean,
recompute: boolean,
terrain: AnalysisTerrain,
): Promise<InitialChoice> {
const response = await fetchRouteInitial(projectId, {
mode: logic,
@@ -133,8 +140,9 @@ export function createInitialPanel(params: InitialPanelParams): InitialPanel {
...(criteria ? { criteria } : {}),
with_profile: withProfile,
...(recompute ? { recompute: true } : {}),
terrain,
});
return normalizeRouteInitial(response, logic, weights, criteria, withProfile);
return { ...normalizeRouteInitial(response, logic, weights, criteria, withProfile), terrain };
}
recommendButton.addEventListener("click", () => {
@@ -158,6 +166,8 @@ export function createInitialPanel(params: InitialPanelParams): InitialPanel {
expected: (plan?.expected ?? []).map(([x, y]) => [x, y]),
current: params.planned().map(([x, y]) => [x, y]),
request,
terrains: params.terrains()?.sources ?? [],
terrain: params.terrains()?.design ?? "las",
progress: () => fetchPrecomputeProgress(projectId),
confirmText: () => applyResetText(projectId),
onApply: (picked) => {
@@ -179,6 +189,7 @@ export function createInitialPanel(params: InitialPanelParams): InitialPanel {
with_profile: choiceWithProfile(picked), // initial_choice 에 남김(420)
},
choiceWithProfile(picked),
picked.terrain ?? null,
);
},
});