diff --git a/A00_Common/b_page_state.ts b/A00_Common/b_page_state.ts index 60ee6b9dd..8250c2cce 100644 --- a/A00_Common/b_page_state.ts +++ b/A00_Common/b_page_state.ts @@ -75,6 +75,8 @@ export const STATE_REGISTRY = { "routeedit-locks": { bucket: "pref", scope: "project" }, /** B05 계획노선 편집 창 — 분석 지형(las · sheet). 확정 지표면은 안 바꿈 */ "routeedit-terrain": { bucket: "pref", scope: "project" }, + /** B05 계획노선 편집 창 — 측점 스냅 간격(0.1 · 1 · 10 · station) */ + "routeedit-snap-step": { bucket: "pref", scope: "project" }, "masshaul-open": { bucket: "pref", scope: "global", diff --git a/B05_Profile/B05_Profile_UI_RouteEdit.ts b/B05_Profile/B05_Profile_UI_RouteEdit.ts index 540c6e57a..e74c3bf2e 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit.ts @@ -91,6 +91,7 @@ import { import type { DesignPageHost } from "../A00_Common/design/design_page"; import * as draftLink from "./B05_Profile_UI_RouteEdit_Draft"; import { bindRouteShift } from "./B05_Profile_UI_RouteEdit_Shift"; +import { bindStationSnap, paintStationSnap } from "./B05_Profile_UI_RouteEdit_SnapStep"; import * as fit from "./logic/B05_Profile_RouteEdit_StationFit"; import "./B05_Profile_UI_Style_RouteEdit.css"; @@ -173,11 +174,7 @@ export async function mountRouteEditor( curveSpans(line, curveInfo), ); }; - const setStationSnap = (on: boolean): void => { - stationSnap = on; - stationSnapButton.classList.toggle("is-active", on); - stationSnapButton.setAttribute("aria-pressed", String(on)); - }; + const setStationSnap = (on: boolean) => paintStationSnap(stationSnapButton, (stationSnap = on)); /** 되돌리기 사진첩 — 노선을 읽은 뒤에 선다(그전에는 되돌릴 것이 없다). */ let history: RouteEditHistory | null = null; let meta: VWorldMeta | null = null; @@ -264,8 +261,8 @@ export async function mountRouteEditor( const slope = createSlopeLabels({ projectId, isClosed: () => closed, onChange: () => draw() }); /** 1m 간격 등고선 켬끔 — 기본 꺼짐(계획서 18 ②). */ const showMinorContours = bindMinorContourToggle(minorContourButton, () => draw()); - stationSnapButton.addEventListener("click", () => { - setStationSnap(!stationSnap); + const snapStepM = bindStationSnap(chrome, projectId, stationIntervalM, (toggle) => { + if (toggle) setStationSnap(!stationSnap); if (stationSnap && history) applyEdit("곡선 가운데(MC)를 일반측점에 맞췄습니다."); // 전체 · 한 걸음 draw(); }); @@ -416,7 +413,7 @@ export async function mountRouteEditor( violationCount: nodeInfo.filter((node) => node.violations.length).length, minRadiusM, fresh: nodeInfo.length === 0, - offStation: stationSnap ? fit.offStationCount(plannedLine, curveInfo, stationIntervalM) : 0, + offStation: stationSnap ? fit.offStationCount(plannedLine, curveInfo, snapStepM()) : 0, }); // ── 곡선 라벨 — 고른 꺾임점 옆에 뜨는 조작 패널. 배선은 `_CurveBar` 몫 ── @@ -450,7 +447,7 @@ export async function mountRouteEditor( /** 한 번의 편집을 마무리한다 — 다시 그리고, 라벨·상태줄을 맞추고, 되돌리기에 쌓는다. * 측점 스냅 켬이면 고친 자리 앞 곡선부터 MC 를 일반측점에(366-3 · 되살림 `fitting=false` 은 안 맞춤). */ function applyEdit(message: string, record = true, fitting = true): void { - const limits = { minRadiusM, limitRadiusM, limitArcM, intervalM: stationIntervalM }; + const limits = { minRadiusM, limitRadiusM, limitArcM, intervalM: snapStepM() }; const from = fit.fitStart(history?.current?.(), snapshotNow()); if (stationSnap && fitting) planned = fit.fitCurveStations(snapshotNow(), limits, from); markEdited(); @@ -574,6 +571,7 @@ export async function mountRouteEditor( getMeta: () => meta, // 돌린 지도에서는 손이 민 방향과 그림이 움직일 방향이 다르다 — 거꾸로 돌려 넘긴다. unrotateDelta: rotation.unrotateDelta, + rotateWheel: rotation.wheel, // Ctrl+휠 = 5° 돌리기(390-3) draw, }); diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts index 6c1273f5e..faa7659c5 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts @@ -110,6 +110,16 @@ export function createRouteEditChrome( + +