Files
Aislo/B05_Profile/B05_Profile_Plus_Stations.py
T
eomsangdonandClaude Opus 5.5 2b7b129566 fix(493-3 화면 ↔ 저장 자리): 추가 측점 = 끌기 동안 땅 위 좌표를 들고 따라감 — 걸음마다 정수 m 에서 다시 놓아 [저장] 자리와 2~4 m 어긋나던 것
- 원인 = 노선 초안 follow 가 추가 측점을 누가거리만 들고 걸음마다 앞 선 위 정수 m 자리에서 다시 투영(반올림 누적) · 서버 [저장]은 정본 좌표에서 한 번 · 관 · 구조물은 좌표를 들고 가 차 0
- followPlusGround(common_util_route_follow) — 같은 누가거리 저장분 · 앞 걸음 좌표에서 따라감 · follow 단계가 걸음 출력마다 좌표 줄을 기억(B05_Profile_Pipeline_Grade)
- 첫 걸음 = 서버 정본 좌표 — GET plus-stations 에 stations(누가거리 · x · y) · 화면 savedPlusRows · 초안 둔 채 열기 = 초안 노선 자리
- 거울 시험 test_493_3_follow_screen_save(직선 · 곡선 교점 · R · 교점 더함 · 지움 · 앞 교점 여러 걸음 오감 = 관 · 구조물 · 추가 측점 화면 자리 = 서버 자리 · 고치기 전 셈 대조 = 2 m 넘게 어긋남)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:45:41 +09:00

103 lines
4.1 KiB
Python

"""추가 측점 정본(`B05_Profile/route/plus_stations.json`) — 구조물 정본 곁(368-2 · 요구 240-21).
사용자가 종단 원지반선에서 넣은 일반 측점(정수 m) · 이름 없음. 자리 정본 = 좌표(x · y) — 노선이
바뀌면 관 · 구조물처럼 새 노선에 투영해 누가거리를 다시 매김(TS `followPlusRows` · Node 입구).
측점 계획에는 `resolve_extra_stations` → `plan_stations(plus=)` 로 들어감(TS `planStations` 짝).
화면은 노선 초안 동안 이 좌표(GET `stations`)를 들고 따라감(TS `followPlusGround` · 493-3) — 거울 시험 =
`resources/tester/test_493_3_follow_screen_save.py`.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
from typing import Any, Sequence
from common_util.common_util_calc_runner import run_calc
from common_util.common_util_json import atomic_write_json
PLUS_STATIONS_FILE_NAME = "plus_stations.json"
def plus_stations_path(project_root: str | Path) -> Path:
return Path(project_root) / "B05_Profile" / "route" / PLUS_STATIONS_FILE_NAME
def load_plus_stations(project_root: str | Path) -> list[dict[str, Any]]:
"""[{chainage_m, x, y}] — 없거나 깨졌으면 빈 목록."""
path = plus_stations_path(project_root)
if not path.is_file():
return []
try:
rows = json.loads(path.read_text(encoding="utf-8")).get("stations") or []
except (OSError, ValueError, AttributeError):
return []
return [
row
for row in rows
if isinstance(row, dict) and isinstance(row.get("chainage_m"), (int, float))
]
def plus_chainages(project_root: str | Path) -> list[float]:
return sorted({float(row["chainage_m"]) for row in load_plus_stations(project_root)})
def save_plus_stations(
project_root: str | Path, chainages: Sequence[float], xy: Sequence[Sequence[float]] | None
) -> list[float]:
"""정수 m 로 맞춰(0 ~ 노선 끝 · 같은 m 하나) 좌표와 함께 씀 → 쓴 누가거리."""
from shapely.geometry import LineString
line = LineString([(float(p[0]), float(p[1])) for p in xy]) if xy and len(xy) > 1 else None
end = float(line.length) if line is not None else float("inf")
values = sorted({float(round(c)) for c in chainages if 0 <= round(c) <= end})
rows = []
for value in values:
point = line.interpolate(value) if line is not None else None
rows.append(
{
"chainage_m": value,
"x": round(float(point.x), 4) if point is not None else None,
"y": round(float(point.y), 4) if point is not None else None,
}
)
path = plus_stations_path(project_root)
if not rows and not path.exists():
return []
os.makedirs(path.parent, exist_ok=True)
atomic_write_json(str(path), {"stations": rows})
return values
def follow_plus_stations(project_root: str | Path, new_xy: Sequence[Sequence[float]]) -> int:
"""노선이 바뀔 때 좌표를 새 노선에 투영해 누가거리를 다시 매김 → 옮긴 수(같은 m 는 하나).
셈 = TS `followPlusRows`(Node 입구 `facility.plus_follow` · 472-4 ①)."""
rows = load_plus_stations(project_root)
if not rows:
return 0
followed = followed_plus_rows(rows, new_xy)
if followed["moved"]:
atomic_write_json(str(plus_stations_path(project_root)), {"stations": followed["rows"]})
return int(followed["moved"])
def followed_plus_rows(rows: list[dict[str, Any]], new_xy: Sequence[Sequence[float]]) -> dict:
"""추가 측점을 새 노선에 투영(저장 안 함) → `{rows, moved}` — 체인 · 추천 초기 종단(476)."""
results = run_calc(
["facility.plus_follow"],
{
"plus": {
"rows": [
{"chainage_m": float(r["chainage_m"]), "x": r.get("x"), "y": r.get("y")}
for r in rows
],
"line": [[float(p[0]), float(p[1])] for p in new_xy],
}
},
)
if results is None:
raise RuntimeError("추가 측점 따라감 실패 — 계산 Node 입구(facility.plus_follow)")
return results["facility.plus_follow"]