Files
Aislo/resources/tester/test_507_2_stream_pipe_label.py
T
eomsangdonandClaude Opus 5.5 d72481a52e fix(507-2 B05 관): 자동 세류선 관 라벨 · 노선 바꾼 [저장] 관 겹 생성 막음 · 지운 자동 관 지움 표지 — 요구 311-3
- 관 라벨 stream_label = 세류선 UFID · 교차 차례 · 처음 교차점 좌표 · 끌기 · 옵션 고침에도 남음 · 관 PUT 때 id 로 되붙임
- 노선 [저장] = 라벨(관 · 지움 표지)이 같은 세류선 가장 가까운 새 교차점을 짝으로 잡음 · 짝 잡힌 교차엔 관 안 더함
- 지운 자동 관 = pipe_points.json dismissed_streams · 라벨 없던 옛 관은 자리만 → 다음 노선 [저장] 때 라벨
- 라벨 없는 옛 stream 관 = 옛 노선 누가거리 5 m 안 교차 라벨 · 겹친 관 안 지움(로그 수)
- 추천 [적용] = 표지 없음 · [초기화] = 초기값 파일 그대로
- 세류선 교차 셈을 common_util_stream_crossing 으로 옮김(common_util_route_geometry 700줄 넘음)
- 시험 test_507_2_stream_pipe_label · test_494_2 가짜 저장 인자

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:36:00 +09:00

155 lines
6.7 KiB
Python

# -*- coding: utf-8 -*-
"""507-2 자동 세류선 관 라벨 — 노선 바꾼 [저장] 에 관이 여럿 생기던 흠(요구 311-3).
못박는 것
- 라벨 = 세류선 지물 id · 교차 차례 · 처음 교차점 좌표 · 끌어 source 가 user 로 바뀌어도 남음 ·
파일 · 화면 PUT(라벨 모름)을 지나도 id 로 되붙음.
- 노선 바꾼 [저장] 두 번 = 같은 세류선 라벨 관이 있으면(옮겼어도) 안 더함 · 관 수 그대로.
- 지운 자동 관 = 지움 표지 · 다시 안 생김(라벨 없던 옛 관도 자리로 남겨 다음 [저장] 때 라벨로).
- 초기값([적용]) = 지움 표지 없음 · 새 교차 관 · save_pipe_points 표지 None = 파일 것 그대로.
- 라벨 없는 옛 stream 관 = 옛 노선 교차 5 m 안이면 라벨 · 겹친 관은 안 지우고 수만 셈.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
import B05_Profile.B05_Profile_Route_Save as save # noqa: E402
import common_util.common_util_drainage_pipes as drainage_pipes # noqa: E402
from B05_Profile.B05_Profile_Route_Save_Parts import vertices_of # noqa: E402
from common_util.common_util_drainage_pipes import ( # noqa: E402
PIPE_SOURCE_STREAM,
PipePoint,
parse_pipe_points,
)
from common_util.common_util_stream_crossing import ( # noqa: E402
adopt_labels,
find_stream_crossings,
keep_labels,
)
OLD = [[0.0, 0.0], [100.0, 0.0], [200.0, 0.0], [300.0, 0.0], [400.0, 0.0]]
# 앞 측점 노선을 북으로 — 세류선 교차가 30 m · 45 m 옮음(5 m 솎기 넘음)
NEW1 = [[0.0, 0.0], [100.0, 0.0], [200.0, 60.0], [300.0, 0.0], [400.0, 0.0]]
NEW2 = [[0.0, 0.0], [100.0, 0.0], [200.0, 90.0], [300.0, 0.0], [400.0, 0.0]]
STREAMS = [
{
"type": "Feature",
"properties": {"UFID": "S1", "구분": "세류"},
"geometry": {"type": "LineString", "coordinates": [[150.0, -50.0], [150.0, 120.0]]},
}
]
def _points(xy) -> list[dict[str, float]]:
return [{"x": x, "y": y} for x, y in xy]
def _save(old: list[PipePoint], old_xy, new_xy, dismissed=None) -> tuple[list[PipePoint], int]:
pairs, crossing, _ = save.followed_pipes(old, old_xy, _points(new_xy), STREAMS, dismissed)
return [pipe for _, pipe in pairs], crossing
def _legacy() -> PipePoint:
"""라벨 없는 옛 자동 관(옛 노선 교차 (150, 0))."""
return PipePoint(chainage_m=150.0, source=PIPE_SOURCE_STREAM, x=150.0, y=0.0, id="p15000")
def test_교차점에_세류선_id():
found = find_stream_crossings(vertices_of(OLD), STREAMS)
assert [(c.stream_id, round(c.x), round(c.y)) for c in found] == [("S1", 150, 0)]
def test_노선_바꾼_저장_두_번_관_수_그대로():
pipes, crossing = _save([_legacy()], OLD, NEW1)
assert crossing == 0 and len(pipes) == 1 # 고치기 전 = 옛 관 + 새 관 둘
label = pipes[0].stream_label
assert label == {"stream": "S1", "order": 1, "x": 150.0, "y": 0.0} # 처음 교차점
# 파일을 지나도 라벨 그대로 · 두 번째 노선 [저장]
again = parse_pipe_points([pipe.as_dict() for pipe in pipes])
pipes2, crossing2 = _save(again, NEW1, NEW2)
assert crossing2 == 0 and len(pipes2) == 1 and pipes2[0].stream_label == label
def test_끌어_user_로_바뀌어도_라벨_남음():
pipes, _ = _save([_legacy()], OLD, NEW1)
moved = pipes[0]
moved.source, moved.x, moved.y = "user", 170.0, 40.0 # 끌기 = user
pipes2, crossing2 = _save(parse_pipe_points([moved.as_dict()]), NEW1, NEW2)
assert crossing2 == 0 and len(pipes2) == 1 and pipes2[0].stream_label["stream"] == "S1"
def test_화면_PUT_라벨_되붙임():
stored = [
PipePoint(chainage_m=150.0, id="p15000", stream_label={"stream": "S1", "x": 1, "y": 2})
]
request = [PipePoint(chainage_m=152.0, id="p15000", source="user")] # 화면은 라벨 모름
dismissed: list = []
keep_labels(request, stored, dismissed)
assert request[0].stream_label == stored[0].stream_label and dismissed == []
def test_지운_자동_관_다시_안_생김():
pipes, _ = _save([_legacy()], OLD, NEW1)
dismissed: list = []
keep_labels([], pipes, dismissed) # 사용자가 지우고 [저장]
assert dismissed == [pipes[0].stream_label]
after, crossing = _save([], NEW1, NEW2, dismissed)
assert crossing == 0 and after == []
def test_라벨_없던_옛_관_지움도_다시_안_생김():
dismissed: list = []
keep_labels([], [_legacy()], dismissed)
assert dismissed == [{"x": 150.0, "y": 0.0}] # 자리만
after, crossing = _save([], OLD, NEW1, dismissed)
assert crossing == 0 and after == []
assert dismissed[0]["stream"] == "S1" # 다음 [저장] 때 라벨로
def test_사용자_관_지움은_표지_없음():
dismissed: list = []
keep_labels([], [PipePoint(chainage_m=50.0, x=50.0, y=0.0)], dismissed)
assert dismissed == []
def test_초기값_적용_새_교차_관():
pipes, crossing = _save([], [], NEW1, [])
assert crossing == 1 and pipes[0].stream_label["stream"] == "S1"
assert pipes[0].stream_label["y"] == 30.0
def test_지움_표지_파일(monkeypatch, tmp_path):
path = tmp_path / "pipe_points.json"
monkeypatch.setattr(drainage_pipes, "pipe_points_path", lambda _stored: path)
mark = [{"stream": "S1", "order": 1, "x": 150.0, "y": 0.0}]
drainage_pipes.save_pipe_points("x", "sig", [], None, mark)
drainage_pipes.save_pipe_points("x", "sig", [PipePoint(chainage_m=5.0)]) # None = 그대로
assert json.loads(path.read_text("utf-8"))["dismissed_streams"] == mark
assert drainage_pipes.read_dismissed(path) == mark
drainage_pipes.save_pipe_points("x", "sig", [], None, []) # [적용] = 표지 없음
assert "dismissed_streams" not in json.loads(path.read_text("utf-8"))
def test_겹친_옛_관_안_지우고_셈():
twin = PipePoint(chainage_m=152.0, source=PIPE_SOURCE_STREAM, x=152.0, y=0.0, id="p15200")
old = [_legacy(), twin]
overlap = adopt_labels(old, [], find_stream_crossings(vertices_of(OLD), STREAMS), OLD)
assert overlap == 1
assert old[0].stream_label and not old[1].stream_label # 가까운 관만 라벨
pipes, crossing = _save(parse_pipe_points([p.as_dict() for p in old]), OLD, NEW1)
assert crossing == 0 and len(pipes) == 2 # 둘 다 그대로 · 새 관 없음
def test_옆_다른_선_위_옛_관도_라벨():
"""옛 관 좌표가 다른 선 위(옆 15 m · 검증_sub3 실측) — 옛 노선 누가거리로 5 m 안이면 라벨."""
side = PipePoint(chainage_m=150.0, source=PIPE_SOURCE_STREAM, x=151.0, y=15.0, id="p15000")
pipes, crossing = _save([side], OLD, NEW1)
assert crossing == 0 and len(pipes) == 1 and pipes[0].stream_label["stream"] == "S1"