diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts index 1f88a7a86..89e44c769 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts @@ -236,6 +236,32 @@ export function drawRouteEditScene(context: CanvasRenderingContext2D, scene: Rou style.getPropertyValue("--color-text-secondary") || "#9ca3af", 1.6, ); + // 곡선 시작·끝점 — 잡아서 직선 각도와 R 을 함께 바꾸는 손잡이(2026-09-07 사용자 지시). + // **속을 비우고 테두리를 굵게** 그린다 — 선·노드와 색이 같으면 눈에도 안 띄고 집기도 어렵다. + // 예상노선 뒤 · 노선 앞(414-2) — 노선이 네모 위를 지나감 · 고른 곡선은 `drawPickedCurve` 가 위에. + context.save(); + context.lineWidth = 2; + scene.curveInfo.forEach((curve) => { + // **늘 보인다**(2026-09-07 사용자 지시) — 직선이 곡선에 닿는 자리는 손잡이이기 이전에 + // **읽을 정보**다. 한때 고른 곡선만 내보였더니 「표기가 다 사라졌다」는 지적을 받았다. + // 노드를 못 집던 문제는 집기 우선순위(노드가 먼저)로 따로 풀었으므로 다 내놓아도 된다. + if (scene.curveOn[curve.node_first] === false) return; // 곡선을 지운 자리에는 접선점도 없다. + // 고른 곡선은 속을 채워 도드라지게 — 지금 끌 수 있는 것이 무엇인지 보이게. + const isPicked = curve.node_first === scene.picked; + [curve.start, curve.end].forEach((point) => { + const [x, y] = toScreen([point[0], point[1]]); + context.beginPath(); + const size = isPicked ? CURVE_HANDLE_PX + 1 : CURVE_HANDLE_PX; + context.rect(x - size, y - size, size * 2, size * 2); + context.fillStyle = isPicked + ? style.getPropertyValue("--map-route") || "#f97316" + : style.getPropertyValue("--map-halo") || "rgba(255,255,255,0.95)"; + context.fill(); + context.strokeStyle = style.getPropertyValue("--map-route") || "#f97316"; + context.stroke(); + }); + }); + context.restore(); // 선은 **폴리라인**(원호 포함)을 그리고, 잡는 동그라미는 **노드**에만 찍는다. // 노드를 옮기는 동안에는 폴리라인이 없으므로 노드를 곧바로 이어 미리 보인다. strokePolyline( @@ -294,29 +320,6 @@ export function drawRouteEditScene(context: CanvasRenderingContext2D, scene: Rou } }); - // 곡선 시작·끝점 — 잡아서 직선 각도와 R 을 함께 바꾸는 손잡이(2026-09-07 사용자 지시). - // **속을 비우고 테두리를 굵게** 그린다 — 선·노드와 색이 같으면 눈에도 안 띄고 집기도 어렵다. - context.lineWidth = 2; - scene.curveInfo.forEach((curve) => { - // **늘 보인다**(2026-09-07 사용자 지시) — 직선이 곡선에 닿는 자리는 손잡이이기 이전에 - // **읽을 정보**다. 한때 고른 곡선만 내보였더니 「표기가 다 사라졌다」는 지적을 받았다. - // 노드를 못 집던 문제는 집기 우선순위(노드가 먼저)로 따로 풀었으므로 다 내놓아도 된다. - if (scene.curveOn[curve.node_first] === false) return; // 곡선을 지운 자리에는 접선점도 없다. - // 고른 곡선은 속을 채워 도드라지게 — 지금 끌 수 있는 것이 무엇인지 보이게. - const isPicked = curve.node_first === scene.picked; - [curve.start, curve.end].forEach((point) => { - const [x, y] = toScreen([point[0], point[1]]); - context.beginPath(); - const size = isPicked ? CURVE_HANDLE_PX + 1 : CURVE_HANDLE_PX; - context.rect(x - size, y - size, size * 2, size * 2); - context.fillStyle = isPicked - ? style.getPropertyValue("--map-route") || "#f97316" - : style.getPropertyValue("--map-halo") || "rgba(255,255,255,0.95)"; - context.fill(); - context.strokeStyle = style.getPropertyValue("--map-route") || "#f97316"; - context.stroke(); - }); - }); context.restore(); drawPickedCurve(context, scene, style); drawPickHover(context, scene, line, style, NODE_R); diff --git a/resources/tester/test_381_3_routeedit_node_pick.py b/resources/tester/test_381_3_routeedit_node_pick.py index 977ab495c..f4f56f738 100644 --- a/resources/tester/test_381_3_routeedit_node_pick.py +++ b/resources/tester/test_381_3_routeedit_node_pick.py @@ -23,12 +23,23 @@ def test_노드는_라벨_뒤_맨_위_회전_안(): scene = render[render.index("export function drawRouteEditScene(") :] scene = scene[: scene.index("context.restore(); // 회전 끝")] labels = scene.index("drawContourLabels(context, scene, band, style);") - for later in ("scene.planned.forEach(", "scene.curveInfo.forEach(", "drawPickHover("): + for later in ("scene.planned.forEach(", "drawPickedCurve(", "drawPickHover("): assert labels < scene.index(later), later for earlier in ("drawStationMarks(", "scene.overStations?.(", "drawMeasureMarks("): assert scene.index(earlier) < labels, earlier +def test_곡선_네모는_예상노선_뒤_노선_앞(): + """414-2 — 모든 곡선 BC · EC 네모 = 예상노선 뒤 · 노선 앞(노선이 네모 위를 지나감).""" + render = _read("B05_Profile_UI_RouteEdit_Render.ts") + scene = render[render.index("export function drawRouteEditScene(") :] + expected = scene.index("scene.expected,") + squares = scene.index("scene.curveInfo.forEach(") + route = scene.index("strokePolyline(", squares) + assert expected < squares < route + assert scene[route:].split(",")[2].strip() == "line" + + def test_집기_맴돔_한_함수(): pointer = _read("B05_Profile_UI_RouteEdit_Pointer.ts") assert "pickAtScreen(" in pointer