Merge remote-tracking branches 'origin/sub_laptop_1', 'origin/sub_laptop_7' and 'origin/sub_laptop_8' into sub_laptop_4

This commit is contained in:
2026-10-18 18:48:48 +09:00
23 changed files with 577 additions and 36 deletions
+1
View File
@@ -544,6 +544,7 @@ export async function mountRouteEditor(
if (base) markEdited();
return base !== undefined;
},
offStation: () => (stationSnap ? fit.offStationCount(plannedLine, curveInfo, snap()) : 0),
});
bindNodeSplice({
+14 -1
View File
@@ -31,6 +31,8 @@ interface Hold {
start: Vertex;
/** 스냅 미리보기 전 노선(맞추기 전) — 다음 걸음 · 하한 검사는 여기서(맞춤이 쌓이지 않음). */
raw: Vertex[] | null;
/** 누를 때 측점 밖 곡선 수(441) — 미리보기가 이보다 늘면 그 걸음 되돌림. */
off: number;
moved: boolean;
}
@@ -74,8 +76,18 @@ export function bindRouteEditKeys(params: RouteEditPointerParams, dragging: () =
params.draw();
return;
}
now.moved = true;
fitPreview(now, state.planned);
if (now.raw && params.offStation() > now.off) {
// 맞춰도 MC 가 측점 밖에 남는 자리 — 끌기와 같게 그 걸음만 되돌림(441)
const planned = params.state().planned;
now.raw.forEach((vertex, index) => (planned[index] = vertex));
planned[now.index] = node;
fitPreview(now, planned);
status.textContent = `${params.routeHead()} — 곡선 가운데를 측점에 못 맞춰 더 못 옮깁니다.`;
params.draw();
return;
}
now.moved = true;
status.textContent = `${params.routeHead()} — 방향키로 옮기는 중(뗄 때 한 걸음). ${params.curveHint()}`;
params.draw();
}
@@ -123,6 +135,7 @@ export function bindRouteEditKeys(params: RouteEditPointerParams, dragging: () =
before: state.planned.map(([x, y]): Vertex => [x, y]),
start: [node[0], node[1]],
raw: null,
off: params.offStation(),
moved: false,
};
hold = now;
@@ -106,6 +106,8 @@ export interface RouteEditPointerParams {
/** 끄는 중 · 방향키 걸음 미리보기(390-5) — 스냅 켬이면 IP `index` 자리 그대로 MC 를 간격 배수에 ·
* 맞췄으면 true(끔이면 false · 아무 일 없음). */
fitDrag: (index: number) => boolean;
/** 측점 밖 곡선 수(스냅 끔 = 0 · 441 끌기 · 방향키 막힘). */
offStation: () => number;
}
export interface RouteEditPointer {
@@ -191,8 +193,10 @@ export function bindRouteEditPointer(params: RouteEditPointerParams): RouteEditP
/** 이번 끌기에서 **실제로 움직였나** — 그냥 눌러 고르기만 한 것은 되돌릴 걸음이 아니다
* (2026-09-07 실화면: 노드를 클릭만 해도 [되돌리기]가 켜졌다). */
let dragMoved = false;
/** 스냅 미리보기 전 자리(390-5) — 하한 검사는 맞춘 선이 아닌 이것으로(맞춤이 IP 를 ±간격/2 밂). */
/** 스냅 미리보기 전 자리(390-5) — 하한 검사는 맞춘 선이 아닌 이것으로(맞춤이 IP 를 ±간격 밂). */
let dragRaw: Vertex[] | null = null;
/** 누를 때 측점 밖 곡선 수(441) — 미리보기가 이보다 늘면 그 걸음 되돌림(못 맞추는 자리로 못 끎). */
let dragOff = 0;
/** 구조물 측점 마커(399) — 집기 차례 = 재기 다음 맨 앞(409) · 끌기 · 방향키 1 m. */
const marks = bindStructureMarks(params, () => dragNode >= 0 || dragHandle !== null);
@@ -227,6 +231,7 @@ export function bindRouteEditPointer(params: RouteEditPointerParams): RouteEditP
// 교각점을 고정한 자리는 **고르기만** 되고 안 끌린다(2026-09-12 사용자 지시 ①).
dragNode = hitNode >= 0 && state.apexLock[hitNode] !== true ? hitNode : -1;
dragRaw = null;
dragOff = params.offStation();
dragHandle = hitNode >= 0 ? null : handleAt(px, py);
dragMoved = false;
if (hitNode >= 0) {
@@ -353,7 +358,6 @@ export function bindRouteEditPointer(params: RouteEditPointerParams): RouteEditP
// **지키던 자리가 넘어가는 것만** 막는다(계획서 0-9 ④).
const before = curveShortfalls(state.nodeInfo, state.limitRadiusM, state.limitArcM);
const previous = state.planned[dragNode];
dragMoved = true;
state.planned[dragNode] = toMetric(px, py);
params.markEdited(); // 곡선을 그 자리에서 다시 그린다 — 나머지 곡선은 그대로 남는다.
const after = params.state();
@@ -372,6 +376,17 @@ export function bindRouteEditPointer(params: RouteEditPointerParams): RouteEditP
return;
}
fitPreview(state.planned); // 스냅 켬 = 끄는 동안 MC 를 간격 배수에(390-5 · 놓을 때 정본)
if (dragRaw && params.offStation() > dragOff) {
// 맞춰도 MC 가 측점 밖에 남는 자리 — 하한 막힘과 같게 그 걸음만 되돌림(441)
const now = params.state().planned;
dragRaw.forEach((vertex, index) => (now[index] = vertex));
now[dragNode] = previous;
fitPreview(now);
status.textContent = `${params.routeHead()} — 곡선 가운데를 측점에 못 맞춰 더 못 옮깁니다.`;
params.draw();
return;
}
dragMoved = true; // 막힘 검사 뒤 — 막힌 채 놓으면 되돌릴 걸음 없음(433-14)
// 끄는 동안에도 상태줄이 살아 있어야 한다 — 예전에는 여기서 아무 말이 없어
// 「곡선이 사라졌다」는 인상만 남았다(2026-09-07 사용자 지적 ②).
status.textContent = `${params.routeHead()} — 옮기는 중. ${params.curveHint()}`;
@@ -3,7 +3,7 @@
* 측점 스냅 켬 = 곡선 가운데(MC)를 일반측점에(366-3 · 요구 240-11) — 손 편집 평면.
*
* 추천 노선 맞춤(`B05_Profile_Engine_RouteInitial_Station.py` `_try` · `_solve`)을 줄인 꼴:
* · `from`(`fitStart` = 고친 자리 앞)부터 끝까지 차례로 — 고정 아닌 교각점(IP)을 들어오는 접선 따라 ±간격/2 안에서
* · `from`(`fitStart` = 고친 자리 앞)부터 끝까지 차례로 — 고정 아닌 교각점(IP)을 들어오는 접선 따라 ±간격 안에서
* 밀어 MC(BC · EC 누가거리 가운데)를 가까운 일반측점(앞 MC 측점 + 간격 이상 · No.1 이상)에 둠.
* · 곡선 하한을 새로 깨거나(`shortfallCrossed`) 앞 곡선 MC 를 흔들면 버림 → 그 곡선은 그대로.
* · 반지름 · 켬끔은 안 바꿈 — IP 자리만. 합치기 · 곡선 끄기 · 되돌아가기 없음.
@@ -113,7 +113,7 @@ function solve(
if (!(length > 1e-9)) return null;
const ux = (base[0] - before[0]) / length;
const uy = (base[1] - before[1]) / length;
const reach = limits.intervalM / 2;
const reach = limits.intervalM; // 한가운데(18+9 ~ 19+1)도 가까운 측점까지(441 · 반 간격이면 못 닿음)
const clamp = (d: number): number => Math.max(-reach, Math.min(reach, d));
const at = (d: number) => {
const next = planned.slice();