feat(b06): 종단 측점선·구조물 알약을 끌어 옮길 수 있게 함

B05 에서만 되던 끌어 옮기기를 B06 종단에도 붙임 — 측점선과 알약 어느 쪽을 끌어도 같은
길을 타고, 관은 예약 이동(저장·확정 때 정본과 배수유역 재분할), 구조물은 정본 이동임.

끌기 판별과 대상 찾기는 새 모듈(B06_Section_UI_Section_View_Menu)로 모아, 종단 화면
본체가 더 커지지 않게 둠.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
This commit is contained in:
2026-09-12 15:54:08 +09:00
co-authored by Claude Opus 5
parent fd3b38f846
commit ce9a83a655
5 changed files with 95 additions and 3 deletions
@@ -25,6 +25,53 @@ export interface SectionStructureEdit {
addStructureType: (chainageM: number, typeId: string) => void;
/** 구조물(관 아님)을 뺀다. */
removeStructure: (structureId: string) => void;
/** 관을 다른 측점으로 옮긴다(측점선·알약 끌기). */
movePipe: (fromChainageM: number, toChainageM: number) => void;
/** 구조물(관 아님)을 다른 측점으로 옮긴다. */
moveStructure: (structureId: string, toChainageM: number) => void;
}
/**
* 측점선·알약을 끌어 놓았다 — 그래프 위 id 로 구조물을 찾아 같은 예약 경로로 보낸다.
* 종단 측점선의 id 는 **종단 정본 측점 id** 라 알약(구조물 id)과 다를 수 있다. 둘 다 받아
* 같은 자리(누가거리)로 맞춘다.
*/
export function moveMarkById(
markId: string,
toChainageM: number,
input: {
structures: ReadonlyArray<StructureInstance>;
stations: ReadonlyArray<{ station_id: string; chainage_m: number }>;
edit: SectionStructureEdit;
},
): void {
const direct = input.structures.find((entry) => String(entry.structure_id) === markId);
if (direct) {
moveStructureMark(input.structures, input.edit, markId, toChainageM);
return;
}
const station = input.stations.find((entry) => String(entry.station_id) === markId);
if (!station) return;
// 측점선 id 로 온 경우 — 그 측점 자리에 선 구조물을 찾는다(관 매칭과 같은 0.51m).
const near = input.structures.find(
(entry) => Math.abs(structureAnchorM(entry) - station.chainage_m) < 0.51,
);
if (near) moveStructureMark(input.structures, input.edit, String(near.structure_id), toChainageM);
}
/** 측점선·알약을 끌었을 때 — 관인지 구조물인지 갈라 같은 예약 경로로 보낸다. */
function moveStructureMark(
structures: ReadonlyArray<StructureInstance>,
edit: SectionStructureEdit,
structureId: string,
toChainageM: number,
): void {
const hit = structures.find((entry) => String(entry.structure_id) === structureId);
if (!hit) return;
const from = structureAnchorM(hit);
if (Math.abs(from - toChainageM) < 0.005) return;
if (isPipeMark(hit)) edit.movePipe(from, toChainageM);
else edit.moveStructure(structureId, toChainageM);
}
/** 알약·우클릭이 쓰는 「관인가」 판정 — 관은 정본이 달라 지우는 길도 다르다. */