feat(B05): 종단 [자유지정] — 범위 고름 · 클릭 점 측점선 붙음 · 실시간 점선 · 기울기 빨강 · 꺾인 점 종단곡선 · 계획고 편집 캐시(215-1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sDZSjFvoiDjdGpgj3muc3
This commit is contained in:
2026-10-10 15:32:27 +09:00
co-authored by Claude Opus 5.5
parent ad30e1ac12
commit b628df3e93
10 changed files with 1029 additions and 11 deletions
@@ -26,6 +26,8 @@ import {
tiltStraightRun,
} from "./B05_Profile_UI_Profile_Straighten";
import type { IrregularStation } from "./B05_Profile_UI_IrregularStations";
import { createFreeDraw } from "../A00_Common/design/design_profile_free";
import { createFreeView, type FreeChartGeom } from "../A00_Common/design/design_profile_free_view";
/** 방향키 한 번에 움직이는 양(m) — 계획고·누가거리 모두 같다(사용자 확정). */
const KEY_STEP_M = 0.1;
@@ -111,6 +113,18 @@ export function createPanelTools(ctx: PanelToolsContext): PanelTools {
pause: () => (syncPipes(), inner.pause()),
};
// [자유지정] — 적용은 직선화 결과와 같은 길(applyEdits · 이력 · 막기 규칙)(215-1).
const free = createFreeDraw({
base: ctx.base,
alignment: ctx.alignment,
edits: ctx.edits,
apply: (next) => ctx.applyEdits(next),
close: () => tools.clear(),
changed: ctx.refresh,
});
const freeView = createFreeView(free);
let lastGeom: FreeChartGeom | null = null;
const tools = createProfileTools({
onStraighten: (fromM, toM) => {
const base = ctx.base();
@@ -143,12 +157,19 @@ export function createPanelTools(ctx: PanelToolsContext): PanelTools {
return alignment ? hasStraightRuns(alignment) : false;
},
onChanged: ctx.refresh,
onModeChange: (mode) => freeView.mount(lastGeom, mode === "free"),
freeHint: () => free.hint(),
mountOverlay: (geom) => {
lastGeom = geom;
freeView.mount(geom, tools.mode() === "free");
},
});
/** 그래프에서 누른 자리를 도구가 먹는다. */
function handleToolPick(chainageM: number | null): boolean {
const mode = tools.mode();
if (mode === "none") return false;
if (mode === "free") return true; // 자유지정 클릭은 오버레이가 먼저 먹는다.
if (chainageM === null) return tools.handleRunPick(null);
const alignment = ctx.alignment();
if (mode === "shift") {
@@ -283,6 +304,12 @@ export function createPanelTools(ctx: PanelToolsContext): PanelTools {
// 입력칸 안에서는 방향키가 값 조작이므로 손대지 않는다.
if (target && target.closest("input, select, textarea")) return;
const key = event.key;
// [자유지정] 중 Enter 끝 · Esc 취소 · Backspace 점 빼기 — 단추 초점의 Enter 누름도 막는다.
if (tools.mode() === "free" && free.key(key)) {
event.preventDefault();
freeView.redraw();
return;
}
if ((event.ctrlKey || event.metaKey) && (key === "z" || key === "Z")) {
event.preventDefault();
flushHold();