Files
Aislo/B05_Profile/B05_Profile_Engine_Sections_Node.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

194 lines
7.5 KiB
Python

"""서버 측점 생성 = 화면과 같은 TS(PLAN 511-B B-2 · 요구 320-4) — 늘 떠 있는 Node
`stations.sections`.
`build_sections`(B03 체인 · 노선 저장 · 재생성 · 넓힘 · 추천 초기 종단)가 부름 — 측점 자리 ·
종류 · 열쇠 · 반경 · 확폭 · 지반 · 틀 · 상단측 =
`B05_Profile/logic/B05_Profile_Sections_Generate.ts`
(화면 묶음 stations · ground 단계와 같은 함수). 파이썬은 머리(schema_version · source ·
coordinate_reference · cad_exchange · options)만 붙임.
DTM · implicit(굳힌 격자 641-1) 지표면만(격자 이진 = `dtm_grid_file`) — 그 밖 ·
Node 못 돌림 = None → 부르는 쪽이 파이썬 `generate_sections`(짝 · 로그 남김).
측점 열쇠(`key`) = 노선 저장 이월 열쇠(`B05_Profile_Route_Save._carry_cross`).
"""
from __future__ import annotations
import logging
from typing import Any
from B05_Profile.B05_Profile_Engine_Sections_Core import (
SECTION_SCHEMA_VERSION,
SectionGenerationOptions,
)
logger = logging.getLogger(__name__)
def plan_pipe(pipe: Any) -> dict[str, Any]:
"""관 정본 → TS `PlanPipe`(누가거리 그대로 · 파이썬 `plan_stations` 가 읽는 칸)."""
return {
"id": getattr(pipe, "id", None),
"chainage_m": float(pipe.chainage_m),
"facility": getattr(pipe, "facility", None) or "pipe",
"start_m": getattr(pipe, "start_m", None),
"end_m": getattr(pipe, "end_m", None),
"options": getattr(pipe, "options", None) or {},
}
def plan_structure(item: Any) -> dict[str, Any]:
"""구조물 정본 → TS `PlanStructure`(JSON 꼴)."""
if hasattr(item, "model_dump"):
return item.model_dump(mode="json")
return dict(item) if isinstance(item, dict) else dict(vars(item))
def structure_table() -> tuple[list[dict[str, Any]], dict[str, Any]]:
"""구조물 종류(`/projects/structure-types` 꼴) · 정의(화면 `useCatalogDefinition` 꼴)."""
from B05_Profile.B05_Profile_Structures_Schema import _read_definition, _stamp
from M02_MasterTemplete.StructOptions.M02_SO_Options import with_visible
types = [item.model_dump(mode="json") for item in with_visible().types]
return types, {"types": types, **_read_definition(*_stamp())}
def stations_input(
xy: list[list[float]],
pipes: list[Any],
structures: list[Any],
plus: list[float],
options: SectionGenerationOptions,
design_curves: list[dict[str, Any]],
station_snap: bool,
station_snap_step: float | None,
) -> dict[str, Any]:
"""Node `stations.list` · `stations.sections` 입력(격자 빼고)."""
types, definition = structure_table()
return {
"line": xy,
"curves": design_curves,
"pipes": [plan_pipe(pipe) for pipe in pipes],
"structures": [plan_structure(item) for item in structures],
"types": types,
"definition": definition,
"plus": [float(at) for at in plus],
"interval_m": options.station_interval_m,
"include_endpoint": options.include_endpoint,
"station_snap": station_snap,
"station_snap_step": station_snap_step,
"cross_half_width_m": options.cross_half_width_m,
"cross_sample_interval_m": options.cross_sample_interval_m,
"long_sample_interval_m": options.long_sample_interval_m,
}
def node_stations(stations: dict[str, Any]) -> list[dict[str, Any]] | None:
"""측점 목록(`buildStations` · 열쇠 · 누가거리 · 종류) — 못 돌림 None."""
from common_util.common_util_calc_runner import run_calc_served
answer = run_calc_served(["stations.list"], {"stations": stations})
if not answer or "error" in answer:
logger.warning("Node 측점 목록 실패: %s", (answer or {}).get("error"))
return None
return answer["results"]["stations.list"]
def node_plan_stations(
groups: list[tuple[list[Any], list[Any], list[float]]],
) -> list[list[dict[str, Any]]] | None:
"""(관 · 구조물 · 추가 측점) 묶음마다 측점 계획(`planStations` · 파이썬 `plan_stations` 짝) —
한 Node 부름 · 못 돌림 None(부르는 쪽이 파이썬 짝)."""
from common_util.common_util_calc_runner import run_calc
if not groups:
return []
types, definition = structure_table()
plan = [
{
"pipes": [plan_pipe(pipe) for pipe in pipes],
"structures": [plan_structure(item) for item in structures],
"plus": [float(at) for at in plus],
}
for pipes, structures, plus in groups
]
try:
results = run_calc(
["stations.plan"],
{"stations": {"types": types, "definition": definition, "plan": plan}},
)
except Exception: # noqa: BLE001 — 파이썬 짝으로 이어 감
logger.exception("Node 측점 계획 실패 — 파이썬 길")
return None
if results is None:
logger.warning("Node 측점 계획 못 돌림 — 파이썬 길")
return None
return results["stations.plan"]
def node_sections(
polyline: list[list[float]],
sampler: Any,
facilities: tuple[list[Any], list[Any], list[float]],
options: SectionGenerationOptions,
*,
source_snapshot: dict[str, Any],
crs: str | None,
design_curves: list[dict[str, Any]],
station_snap: bool,
station_snap_step: float | None,
) -> dict[str, Any] | None:
"""`generate_sections` 와 같은 꼴(+ 측점 `key`) — DTM 아님 · Node 못 돌림 = None."""
from common_util.common_util_calc_runner import run_calc_served
from common_util.common_util_surface_sampler import dtm_grid_file
source = getattr(sampler, "source", None)
if not source:
return None
options.validate()
pipes, structures, plus = facilities
stations = stations_input(
[[float(p[0]), float(p[1])] for p in polyline],
pipes,
structures,
plus,
options,
design_curves,
station_snap,
station_snap_step,
)
stations["grid"] = str(dtm_grid_file(source))
answer = run_calc_served(["stations.sections"], {"stations": stations})
if not answer or "error" in answer:
logger.warning("Node 측점 생성 실패 — 파이썬 길: %s", (answer or {}).get("error"))
return None
out = answer["results"]["stations.sections"]
return {
"schema_version": SECTION_SCHEMA_VERSION,
"status": "completed",
"source": source_snapshot or {},
"coordinate_reference": {
"crs": crs,
"world_axes": {"x": "project_easting", "y": "project_northing", "z": "elevation"},
"units": {"horizontal": "m", "vertical": "m", "angle": "degree"},
},
"cad_exchange": {
"station_origin": "BP",
"chainage_direction": "BP_to_EP",
"cross_offset_sign": {"negative": "right", "positive": "left"},
"cross_local_axes": {"x": "offset_m", "y": "elevation_m"},
"recommended_drawing_datum_m": out["datum"],
},
"options": {
"station_interval_m": options.station_interval_m,
"cross_half_width_m": options.cross_half_width_m,
"cross_sample_interval_m": options.cross_sample_interval_m,
"long_sample_interval_m": options.long_sample_interval_m,
"include_endpoint": options.include_endpoint,
"extra_stations": [list(entry) for entry in options.extra_stations],
},
"longitudinal": out["longitudinal"],
"cross_sections": out["cross_sections"],
"summary": out["summary"],
}