feat(B05): 노선 추천 정리 — 알약 다섯 한 줄 · 종단은 갈래가 정함 · 오른쪽 위 [적용]/[닫기] · 지도 안 옵션 겹창 · 추천 토량에 곡선부 확폭(77)

- 알약 = 예상노선 추적(종단 없음) · 영선 · 토공 최소 · 기울기 최소 · 비중 계산(넷은 종단 늘 반영) · 안전 우선 · 계류 횡단 최소 · 공사비 어림 최소 화면에서 뺌
- 「종단 반영」 켬/끔 단추 없앰(추천 창 · 종단 띠) — 띠 · [확인]은 지금 추천 갈래로 종단 여부
- ✕ 없애고 [적용] · [닫기]를 제목줄 오른쪽 위로 · 옵션 칸은 지도 왼쪽 위 작은 겹창 · 창 폭 넓힘
- 적용한 추천 갈래가 있으면 창을 다시 열 때 그 갈래가 골라진 채
- 도움말: 종단 반영 = 측점마다 횡단을 보고 정한 종단(적분값 아님)
- 균형 종단 단면적에 곡선부 확폭(B05 측점 생성과 같은 셈) — 빼서 확정 뒤 성토가 1.7배 벌어졌음(노선 267 같은 계획고: 성 10,102 → 17,819 · 본 설계 16,140)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019EMfGERKUg5nMMNQsyVZ2j
This commit is contained in:
2026-10-07 21:29:25 +09:00
co-authored by Claude Opus 5.5
parent fd1fc8b401
commit 6aa77e1bb7
12 changed files with 282 additions and 237 deletions
@@ -1,6 +1,6 @@
/* =============================================================================
* B05_Profile_UI_RouteEdit_Recommend_Help.ts
* [노선 추천] 모달 오른쪽 설명 칸(계획서 48-2 · 64-2) — 갈래 여덟 · 공통 제약 넷 · 결과 줄 읽는 법.
* [노선 추천] 모달 오른쪽 설명 칸(계획서 48-2 · 64-2 · 77) — 갈래 다섯 · 종단 반영 · 공통 제약 넷 · 결과 줄 읽는 법.
*
* 글은 서버 엔진(`B05_Profile_Engine_RouteInitial*`)이 실제로 하는 일을 따라 적는다 — 엔진을
* 바꾸면 여기 글도 같이 고친다. 갈래 설명은 **한 번에 한 갈래**(쪽) — 위 ◀ ▶ 단추와 「n / 전체」로
@@ -19,11 +19,13 @@ interface HelpEntry {
when: string;
/** 주의할 점. */
caution: string;
/** 「종단 반영」 켬 · 끔이 점수에 미치는 영향(토공 점수를 쓰는 갈래만). */
/** 종단 반영이 이 갈래에 하는 일. */
profile?: string;
}
const LOGIC_HELP: Record<RouteInitialLogic, HelpEntry> = {
type ShownLogic = "follow" | "gradeline" | "earthwork" | "gentle" | "weighted";
const LOGIC_HELP: Record<ShownLogic, HelpEntry> = {
follow: {
summary: "전처리 때 만든 예상노선(점선)을 그대로 따라가는 노선",
how: [
@@ -33,6 +35,7 @@ const LOGIC_HELP: Record<RouteInitialLogic, HelpEntry> = {
],
when: "현장 답사로 정한 노선을 출발점으로 삼을 때 · 가장 빨리 나옴",
caution: "법정 기울기 · 계류 이격을 보장하지 않음 — 못 지킨 구간을 꼭 확인",
profile: "없음 — 전처리 계획선처럼 계획고 = 지반고",
},
gradeline: {
summary: "정한 기울기로 등고선을 비스듬히 건너는 등경사선(영선) 노선",
@@ -54,8 +57,7 @@ const LOGIC_HELP: Record<RouteInitialLogic, HelpEntry> = {
],
when: "토공량 · 사토 처리를 줄여야 할 때",
caution: "비탈면 흙은 빠진 어림값 · 연장이 길어지는지 비교값으로 함께 볼 것",
profile:
"켬 = 후보마다 균형 종단을 세워 절 + 성 + 반입 + 사토 ㎥ 로 비교 · 끔 = 종단 없이 원지반 절 + 성 어림으로 비교(더 빠름)",
profile: "후보마다 균형 종단을 세워 절 + 성 + 반입 + 사토 ㎥ 로 비교",
},
gentle: {
summary: "종단기울기가 가장 순한 노선",
@@ -66,38 +68,6 @@ const LOGIC_HELP: Record<RouteInitialLogic, HelpEntry> = {
when: "차량 주행 · 노면 침식이 걱정되는 노선",
caution: "거리 비용이 작아 돌아가는 긴 노선이 나올 수 있음 — 연장을 확인",
},
safe: {
summary: "급한 옆경사 · 계류 가까운 곳을 피하는 노선",
how: [
"옆경사 35°(약 70%) 이상 · 계류 이격 거리 안을 위험 구간으로 보고 피함",
"후보 중 위험 구간을 지나는 길이가 가장 짧은 것을 고름(같으면 평균 옆경사)",
"35° 기준 = 「35° 이상 전폭 절토」 기술 기준",
],
when: "붕괴 · 유실 위험이 큰 급경사지 · 계곡 가까운 지형",
caution:
"계곡을 따라가는 지형에서는 위험 구간이 어디서나 길어 다른 갈래와 차이가 작음 — 계류 이격 값을 줄여 다시 셈해 볼 것",
},
crossings: {
summary: "계류를 건너는 횟수가 가장 적은 노선",
how: [
"계류 위를 지나는 칸에 벌점을 매겨 길을 찾음",
"후보 중 계류 횡단 수가 가장 적은 것을 고름(같으면 계류에서 더 먼 쪽)",
"10m 안에서 여러 번 건너는 것은 한 번으로 셈",
],
when: "배수관 · 세월교 같은 횡단 구조물을 줄이고 싶을 때",
caution: "소하천 · 지방하천 · 국가하천만 셈 — 작은 세류는 빠짐",
},
cost: {
summary: "토공 · 연장 · 계류 횡단을 한 숫자로 묶은 공사비 어림이 가장 낮은 노선",
how: [
"공사비 어림 = 흙 1㎥ × 1 + 연장 1m × 2 + 계류 횡단 1곳 × 400(흙 ㎥ 상당)",
"같은 비율을 1m 당 값으로 바꿔 길을 찾고, 후보 중 어림값이 가장 낮은 것을 고름",
],
when: "토공 · 연장 · 구조물 수를 한꺼번에 비교하고 싶을 때",
caution: "실제 원가가 아닌 상대값(임시 비율) — 갈래끼리 비교용으로만 볼 것",
profile:
"켬 = 토공 몫을 균형 종단 토량으로 셈 · 끔 = 원지반 절 + 성 어림으로 셈(종단을 세우지 않음)",
},
weighted: {
summary: "예상 · 토공 · 기울기 세 비중(합 100)을 섞어 찾은 노선",
how: [
@@ -113,7 +83,7 @@ const LOGIC_HELP: Record<RouteInitialLogic, HelpEntry> = {
const CRITERIA_HELP: Array<{ name: string; text: string }> = [
{
name: "종단 반영",
text: "켬(기본) = 후보마다 종단을 세워 토공 점수에 넣음 · 끔 = 원지반만 보고 점수를 냄(종단 그림 · 덮개 줄은 안 나옴). 켬으로 [적용]한 노선을 고치지 않고 [확인]하면 그 균형 종단이 첫 계획선이 됨 · 끔 · 손으로 고친 노선은 계획고 = 지반고",
text: "예상노선 추적을 뺀 네 갈래는 늘 반영. 원지반선과 계획선 사이 넓이를 적분한 값이 아니라, 측점(20m)마다 횡단을 세워 절토 · 성토 면적을 보고 그 측점 계획고를 정한 종단 — 그래서 갈래 · 노선에 따라 값의 편차가 큼. 구조물을 뺀 빠른 셈이라 [확인] 뒤 본 설계 값과 차이가 남. [확인]하면 편집 창 아래 띠에 보인 종단이 그대로 첫 계획선이 됨",
},
{
name: "종단기울기 상한(%)",
@@ -152,19 +122,10 @@ const LINES_HELP: Array<{ name: string; text: string }> = [
},
];
const LOGIC_ORDER: RouteInitialLogic[] = [
"follow",
"gradeline",
"earthwork",
"gentle",
"safe",
"crossings",
"cost",
"weighted",
];
const LOGIC_ORDER: ShownLogic[] = ["follow", "gradeline", "earthwork", "gentle", "weighted"];
/** 갈래 설명 쪽 하나 — 고른 갈래(`is-on`)는 테두리로 알린다. */
function logicPage(key: RouteInitialLogic): string {
function logicPage(key: ShownLogic): string {
const entry = LOGIC_HELP[key];
const profile = entry.profile ? `<p><b>종단 반영</b> ${entry.profile}</p>` : "";
return `<article class="b05-routerec__help-item" data-help-logic="${key}" hidden>
@@ -234,5 +195,5 @@ export function syncRecommendHelp(body: HTMLElement, logic: RouteInitialLogic):
});
if (aside.dataset.pickedLogic === logic) return;
aside.dataset.pickedLogic = logic;
showHelpPage(aside, LOGIC_ORDER.indexOf(logic));
showHelpPage(aside, Math.max(0, LOGIC_ORDER.indexOf(logic as ShownLogic)));
}