⚠ **뿌리** — `tmp/` 는 창 사이에 안 건너감(실측 확인: 상대 창이 놓은 `tmp/_sync_probe.txt` 가 시간을 두고 두 번 봐도 안 보임). 그래서 **정본(등록부 스키마)만 건너가고 그것을 읽는 시험은 안 건너가** 오늘 두 번, 같은 시험이 **연 창은 통과·받은 창은 실패**가 됐음. - `tmp/tests/*` 를 `resources/tester/` 로 **복사**(127 파일). 내용은 **한 줄도 안 고침** - `tmp/tests` 는 **남겨 둠** — 되돌릴 자리(사용자 지시) - 실행: `./venv/Scripts/python.exe -m pytest resources/tester/ -q` 옮기기 전과 **같은 수**: 617 통과 / 22 건너뜀 / 실패 0 ⇒ 이제 시험·예외·까닭이 **정본과 함께** 움직임. 오늘 세운 「예외는 정본 스키마에」와 짝임. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
82 lines
3.6 KiB
Python
82 lines
3.6 KiB
Python
"""묶인 곡선을 **교각점 하나로 갈아 끼워도 같은 선**이 나오는지.
|
|
|
|
왜 (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
|