"""묶인 곡선을 **교각점 하나로 갈아 끼워도 같은 선**이 나오는지. 왜 (2026-09-07 실측) — 서버는 처음 만들 때 이어진 꺾임을 한 곡선으로 묶고, 그 곡선의 교각점은 앞뒤 직선을 늘려 만나는 자리라 원본 꺾임점 중 어느 것도 아니다. 그런데 편집은 「꺾임점 하나 = 곡선 하나」로 표현되므로, 묶인 채로 두면 한 번만 손대도 묶음이 흩어지고 **맞춰 둔 반지름이 전부 법정 하한으로 되돌아간다**(R 12~199m → 전부 12m). 그래서 화면이 모달을 열 때 묶인 구간을 그 **교각점 하나**로 갈아 끼운다. 이 시험은 그렇게 갈아 끼운 목록을 서버에 되넣었을 때 **원래와 같은 선**이 나오는지를 지킨다. """ import math from common_util.common_util_route_polyline import build_planned_polyline MIN_RADIUS = 12.0 def _arc_route(radius_m: float) -> list[tuple[float, float]]: points = [(float(x), 0.0) for x in range(-150, 0, 3)] for degree in range(0, 91, 3): angle = math.radians(degree) points.append((radius_m * math.sin(angle), radius_m - radius_m * math.cos(angle))) points += [(radius_m, radius_m + y) for y in range(3, 150, 3)] return points def _flatten(result): """화면이 하는 것과 같은 갈아 끼우기 — 묶인 구간을 교각점 하나로.""" replaced = {curve.node_first: curve for curve in result.curves} dropped = { index for curve in result.curves for index in range(curve.node_first + 1, curve.node_last + 1) } nodes: list[tuple[float, float]] = [] radii: list[float | None] = [] for index, node in enumerate(result.nodes): if index in dropped: continue curve = replaced.get(index) nodes.append(curve.apex if curve else (node.x, node.y)) radii.append(curve.radius_m if curve else None) return nodes, radii def test_교각점으로_갈아_끼워도_같은_선(): for radius in (25.0, 40.0, 80.0): first = build_planned_polyline(_arc_route(radius), min_radius_m=MIN_RADIUS) nodes, radii = _flatten(first) again = build_planned_polyline( nodes, min_radius_m=MIN_RADIUS, simplify=False, curve_flags=[True] * len(nodes), radii=radii, ) assert again.curve_count == first.curve_count, f"R {radius}m 곡선 수가 달라짐" fitted = [c.radius_m for c in first.curves] kept = [c.radius_m for c in again.curves] for one, other in zip(fitted, kept, strict=True): assert math.isclose(one, other, rel_tol=1e-6), f"R {one:.2f} → {other:.2f}" # 선 자체도 거의 같아야 한다 — 정점 수와 양 끝이 맞고 최대 어긋남이 1mm 안. assert len(again.vertices) == len(first.vertices) worst = max(math.dist(a, b) for a, b in zip(first.vertices, again.vertices, strict=True)) assert worst < 1e-3, f"선이 {worst:.4f}m 어긋남" def test_갈아_끼우지_않으면_반지름이_눌린다(): """왜 갈아 끼워야 하는지 못박는다 — 원본 노드를 그대로 되넣으면 하한으로 눌린다.""" first = build_planned_polyline(_arc_route(40.0), min_radius_m=MIN_RADIUS) raw = [(node.x, node.y) for node in first.nodes] again = build_planned_polyline( raw, min_radius_m=MIN_RADIUS, simplify=False, curve_flags=[True] * len(raw), radii=[None] * len(raw), ) assert max(c.radius_m for c in first.curves) > 30.0 assert max(c.radius_m for c in again.curves) <= MIN_RADIUS + 1e-6