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:
@@ -544,6 +544,7 @@ export async function mountRouteEditor(
|
||||
if (base) markEdited();
|
||||
return base !== undefined;
|
||||
},
|
||||
offStation: () => (stationSnap ? fit.offStationCount(plannedLine, curveInfo, snap()) : 0),
|
||||
});
|
||||
|
||||
bindNodeSplice({
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user