Files
Aislo/resources/tester/test_238_1_save_keeps_structure_stations.py
T
eomsangdonandClaude Opus 5.5 11c75f022a refactor(767-1): 안 쓰는 지면 필터 · 서피스 지움 — 필터 넷(CSF · 격자 최저 · PMF · RANSAC) · 표현 셋(TIN + Taubin 평활 · NURBS · meshfree) · 수치지형도 비교 방식 다섯 · 안 부르는 길 정리
- 필터 = 업체 분류 · 점진 TIN · 둘의 다듬기 판만 · 분석 허용 목록 = Ground 등록부(available_filters) 한 벌
- 표현 = DTM · implicit 만 · 평활 = DTM 만 · config 기본 목록 · PRECOMPUTE · 설정 사전 맞춤(설정 지문 바뀜 — 768 에서 다시 지음)
- 등고선 = 격자 · 굳힌 격자만(삼각망 굽기 · 외곽 맞춤 · implicit RBF 폴백 걷음) · 표본기 · 경로 찾기 tin · nurbs · meshfree 갈래 걷음
- 수치지형도 = 라플라스만(TIN 둘 · TPS · ANUDEM형 · 다중해상도 걷음) · B04 단추 하나
- 안 부르는 길 — B04 JSON 점군 GET · ground-stats GET + TS · B07 옛 계획평면도(라이다) 짓기 · lidar_source · LIDAR_ID · plan_lidar 종류 이름 · SOURCE_FILTER_LABELS · MODEL_METHODS(py) · MESH_* 설정
- 옛 manifest 의 지운 갈래 줄은 DB 로 되살리지 않음 · 옛 csf 행은 미리보기 · 등고선 그대로 열림 · 지운 이름 요청 = 400
- 낡은 글 — Ground · Pipeline 머리 · WF1 「없으면 csf」 · B07 음영 기본 「csf」 → 빈 값 · 등고선 폴백 「csf」 → 404 · B04 3D 보기 처음값 · B05 Schema · B06 Prebuild · 씨닝 설명
- 시험 지움 2 — test_b04_contour_raster · test_b04_contour_equivalence(지운 삼각망 굽기 · 없는 프로젝트를 봐 건너뛰던 것)
- 시험 덜어냄 — test_b04_ground_filters CSF · 격자 최저 네 경우(지운 필터)
- 시험 고침 — 허용 목록 · 형 검사에 걸린 csf · tin · grid_min_z · meshfree · tin_sheet 견본을 ptd · implicit · laplace 로(54_22 · 238_1 · 443 · 342_2 · 346_3 · 351_1 · 442_2 · 271 + helper · 344_1 · 133_1 · 343_2 · 637 · 754_1 · 763_1 깨진 tin → 깨진 implicit · 763_3 · b05 둘 · b06 · sheet_surface TIN(도엽선) 경우 지움) · 이름만 바꿈(273_2 · 343_1 · 343_3 · 624_1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:35:12 +09:00

165 lines
6.2 KiB
Python

"""238-1 B05 [저장]이 구조물 측점을 지우지 않음.
[저장](경로 확정 길 · `_append_irregular_cross_sections`)은 종단 비정규 측점을 통째로 갈아 끼운다.
그 목록을 화면이 보낸 「관 + A군」으로 쓰면 서버가 심어 둔 소단 · 옹벽 · 흙막이 · 독립 기슭막이
시작 · 종료 측점이 빠진다 → 서버 측점 규칙(`resolve_extra_stations`)으로 만든 목록을 씀.
- 사본: 임시 폴더 프로젝트(직선 노선 · 관 하나 + 기슭막이 · 소단 · 옹벽 · 흙막이)
- 앞: B06 [측점 만들기]와 같은 길(서버 목록으로 심음) · 뒤: 화면 목록(관만)을 실은 [저장]
- 판정: 앞뒤 구조물 측점 같음 · 소단 측점(깊이 patch 가 붙는 자리) 남음 · 관 옮김은 반영
"""
import asyncio
import json
from pathlib import Path
import numpy as np
import B05_Profile.B05_Profile_Engine_Sections as sections
import B05_Profile.B05_Profile_Router_Confirm as confirm
from B05_Profile.B05_Profile_Schema import RouteConfirmRequest
from common_util.common_util_drainage_pipes import route_signature
from common_util.common_util_route_geometry import RouteVertex
LINE = [[0.0, 0.0, 100.0], [350.0, 0.0, 100.0]]
ROUTE = "B05_Profile/route/route.geojson"
LONG = "B06_Section/longitudinal/longitudinal.json"
PIPE = {"chainage_m": 150.0, "source": "user", "options": {"pipe_diameter_mm": 800}}
REVET = {
"chainage_m": 301.0,
"source": "user",
"facility": "revetment",
"start_m": 296.0,
"end_m": 316.0,
}
STRUCTURES = [
{"type_id": "soil_guard", "chainage_m": 45.0, "start_m": 41.0, "end_m": 51.0},
{"type_id": "berm", "chainage_m": 201.0, "start_m": 196.0, "end_m": 206.0},
{"type_id": "retaining_wall", "chainage_m": 251.0, "start_m": 246.0, "end_m": 256.0},
]
class _Flat:
def sample_xy(self, xy):
count = len(np.asarray(xy, dtype=np.float64))
return np.full(count, 100.0), np.ones(count, dtype=bool)
def _write(root: Path, rel: str, data) -> None:
path = root / rel
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8")
def _write_pipes(root: Path, points) -> None:
vertices = [RouteVertex(x=p[0], y=p[1], z=p[2], chainage_m=0.0) for p in LINE]
_write(
root,
"B04_PreProcess/drainage/edits/pipe_points.json",
{"route_signature": route_signature(vertices), "points": points},
)
def _project(root: Path) -> None:
_write(root, ROUTE, {"geometry": {"type": "LineString", "coordinates": LINE}})
_write_pipes(root, [PIPE, REVET])
for item in STRUCTURES:
item["placement"] = "interval"
_write(root, "B05_Profile/route/structures.json", {"revision": 1, "structures": STRUCTURES})
regular = [{"chainage_m": float(c), "kind": "regular"} for c in range(0, 351, 20)]
_write(root, LONG, {"stations": regular})
def _irregular(root: Path) -> list[tuple[str, str]]:
data = json.loads((root / LONG).read_text(encoding="utf-8"))
return [
(f"{float(s['chainage_m']):.2f}", s.get("structure"))
for s in data["stations"]
if s.get("kind") == "irregular"
]
def _patch(monkeypatch, root: Path) -> None:
async def _value(value, *_a, **_k):
return value
monkeypatch.setattr(sections, "build_surface_sampler", lambda *_a, **_k: _Flat())
monkeypatch.setattr(confirm, "get_project_storage_relative_path", lambda *_a: _value("p"))
monkeypatch.setattr(confirm, "resolve_stored_project_path", lambda _p: str(root))
monkeypatch.setattr(confirm, "get_latest_section_options", lambda *_a: _value(None))
monkeypatch.setattr(confirm, "get_surface_crs_epsg", lambda *_a: _value(None))
monkeypatch.setattr(
confirm,
"get_longitudinal_section",
lambda *_a: _value({"longitudinal_file_path": LONG}),
)
monkeypatch.setattr(confirm, "sync_cross_section_rows", lambda *_a: _value(0))
def _plant_like_b06(root: Path) -> None:
"""B06 [측점 만들기]와 같은 길 — 서버 목록으로 뜨고 종단에 병합."""
pipes = sections._load_pipe_points(root, LINE)
stations = sections.generate_irregular_sections(
root,
ROUTE,
"ptd",
"implicit",
False,
extra_stations=sections.resolve_extra_stations(root, pipes),
)
confirm._merge_irregular_into_longitudinal(root, LONG, stations)
def _save(root: Path, screen: list[tuple[float, str]]) -> None:
"""B05 [저장] — 화면은 관 · A군 목록만 실어 보냄."""
request = RouteConfirmRequest(
filter_key="ptd",
method="implicit",
surface_model_id=1,
irregular_stations=[{"chainage_m": c, "structure": s} for c, s in screen],
)
assert request.can_regenerate()
asyncio.run(
confirm._append_irregular_cross_sections(
None, "p", {"id": 1, "route_data_path": ROUTE}, request
)
)
def test_save_keeps_server_planted_stations(tmp_path, monkeypatch):
_project(tmp_path)
_patch(monkeypatch, tmp_path)
_plant_like_b06(tmp_path)
before = _irregular(tmp_path)
labels = {label for _key, label in before}
assert {"소단", "옹벽", "흙막이", "기슭막이"} <= labels
assert [k for k, label in before if label == "기슭막이"] == ["296.00", "301.00", "316.00"]
_save(tmp_path, [(150.0, "파형강관 D800")])
assert _irregular(tmp_path) == before
# 소단 깊이(194 · 측점 patch)가 붙는 자리 = 소단 측점 — 그대로 섬
assert [k for k, label in _irregular(tmp_path) if label == "소단"] == [
"196.00",
"201.00",
"206.00",
]
def test_save_follows_moved_pipe(tmp_path, monkeypatch):
_project(tmp_path)
_patch(monkeypatch, tmp_path)
_plant_like_b06(tmp_path)
before = _irregular(tmp_path)
# 관 150 → 165 (관 초안이 [저장] 차례상 먼저 정본에 들어감 · design_save.ts)
_write_pipes(tmp_path, [{**PIPE, "chainage_m": 165.0}, REVET])
_save(tmp_path, [(165.0, "파형강관 D800")])
after = _irregular(tmp_path)
expected = sorted(
[item for item in before if item[0] != "150.00"] + [("165.00", "파형강관 D800")],
key=lambda item: float(item[0]),
)
assert after == expected