From a0bd9c8775135e2ef134f3c9857cec3f71015046 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 7 Sep 2026 08:46:09 +0900 Subject: [PATCH] =?UTF-8?q?fix(B05):=20=ED=95=9C=20=EB=B2=88=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=ED=95=98=EB=A9=B4=20=EB=A7=9E=EC=B6=B0=20=EB=91=94=20?= =?UTF-8?q?=EB=B0=98=EC=A7=80=EB=A6=84=EC=9D=B4=20=ED=95=98=ED=95=9C?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=88=8C=EB=A6=AC=EB=8D=98=20=EA=B2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 실화면에서 잡음 — 곡선 하나만 지워도 나머지 반지름이 **R 12~199m → 전부 12m** 로 되돌아갔음. 원인은 편집 모델과 저장 모델이 다른 것이었음. 서버는 처음 만들 때 이어진 꺾임을 한 곡선으로 묶는데, 그 곡선의 교각점은 앞뒤 직선을 늘려 만나는 자리라 **원본 꺾임점 중 어느 것도 아님**. 편집은 「꺾임점 하나 = 곡선 하나」로 표현되므로, 묶인 채로 두면 한 번만 손대도 묶음이 낱개로 흩어지고 각 자리가 하한으로 떨어졌음. 모달이 자료를 읽을 때 **묶인 구간을 그 교각점 하나로 갈아 끼우게** 함 — 안쪽 꺾임점은 그 곡선이 대신하므로 뺌. 앞뒤 직선과 반지름이 그대로라 그려지는 선은 똑같고, 이제 손대도 안 흩어짐. 서버가 고른 반지름도 함께 들고 가 [확인] 때 되돌려 보냄. 시험 tmp/tests/test_route_polyline_apex_roundtrip.py 2건 — 갈아 끼워도 곡선 수·반지름이 같고 선이 **1mm 안**에서 일치, 그리고 안 갈아 끼우면 실제로 하한으로 눌리는 것(왜 필요한지)도 못박음. 실화면 확인(용화) — 되돌린 뒤 곡선 26곳 R 최대 198.9m → 곡선 하나 지우고 [확인] → 곡선 25곳, **R 42.5·51·198.9m 그대로**. tsc --noEmit 통과 · pytest 432 passed. Co-Authored-By: Claude Opus 5 (1M context) --- B05_Profile/B05_Profile_UI_RouteEdit.ts | 49 ++++++++++++++++++++----- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/B05_Profile/B05_Profile_UI_RouteEdit.ts b/B05_Profile/B05_Profile_UI_RouteEdit.ts index 46525e10..47599d47 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit.ts @@ -667,17 +667,46 @@ export async function openRouteEditModal( // 잡는 것은 **노드**다 — 폴리라인 정점에는 원호 위 점이 섞여 있어 편집 대상이 아니다 // (2026-09-06 사용자 지시: 노드를 제어해 계획노선을 고친다). const nodes = plan.nodes ?? []; - planned = nodes.map((node) => [node.x, node.y] as Vertex); - nodeInfo = nodes.map((node) => ({ - radius_m: node.radius_m, - inner_angle_deg: node.inner_angle_deg, - violations: node.violations ?? [], - })); minRadiusM = plan.min_radius_m ?? 0; - curveInfo = plan.curves ?? []; - // 편집값은 「서버가 준 그대로」에서 시작한다 — 곡선이 있는 자리는 켬, 반지름은 자동. - curveOn = planned.map(() => true); - curveRadius = planned.map(() => null); + // 곡선 성분을 **편집할 수 있는 꼴로 펴 둔다**(2026-09-07). + // + // 서버는 처음 만들 때 이어진 꺾임을 한 곡선으로 묶는다 — 그 곡선의 교각점은 앞뒤 직선을 + // 늘려 만나는 자리라 **원본 꺾임점 중 어느 것도 아니다**. 그런데 편집은 「꺾임점 하나 = + // 곡선 하나」로 표현되므로, 묶인 곡선을 그대로 두면 한 번만 손대도 그 묶음이 낱개로 + // 흩어지고 **맞춰 둔 반지름이 전부 법정 하한으로 되돌아간다**(실측: R 12~199m → 전부 12m). + // + // 그래서 **묶인 구간을 그 교각점 하나로 갈아 끼운다** — 안쪽 꺾임점은 그 곡선이 대신하므로 + // 뺀다. 앞뒤 직선과 반지름이 그대로라 **그려지는 선은 똑같고**, 이제 손대도 안 흩어진다. + const curves = plan.curves ?? []; + const replaced = new Map(); + const dropped = new Set(); + curves.forEach((curve) => { + replaced.set(curve.node_first, curve); + for (let index = curve.node_first + 1; index <= curve.node_last; index += 1) { + dropped.add(index); + } + }); + planned = []; + nodeInfo = []; + curveOn = []; + curveRadius = []; + curveInfo = []; + nodes.forEach((node, index) => { + if (dropped.has(index)) return; + const curve = replaced.get(index); + const at: Vertex = curve ? [curve.apex[0], curve.apex[1]] : [node.x, node.y]; + const seat = planned.length; + planned.push(at); + nodeInfo.push({ + radius_m: curve ? curve.radius_m : node.radius_m, + inner_angle_deg: curve ? curve.inner_angle_deg : node.inner_angle_deg, + violations: curve ? (curve.violations ?? []) : (node.violations ?? []), + }); + curveOn.push(true); + // 서버가 고른 반지름을 **그대로 들고 간다** — 안 그러면 편집 한 번에 하한으로 눌린다. + curveRadius.push(curve ? Math.round(curve.radius_m * 100) / 100 : null); + if (curve) curveInfo.push({ ...curve, node_first: seat, node_last: seat }); + }); picked = -1; syncCurveBar(); if (!planned.length) planned = plannedLine.map((vertex) => [vertex[0], vertex[1]]);