Merge remote-tracking branch 'origin/sub_laptop_5' into sub_laptop_2
This commit is contained in:
@@ -35,6 +35,7 @@ from shapely.geometry import LineString, Point
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Export import drainage_dir
|
||||
from common_util.common_util_json import atomic_write_json
|
||||
from common_util.common_util_route_geometry import RouteVertex, interpolate_vertex
|
||||
from common_util.common_util_summary_item import parse_summary_item
|
||||
from config.config_system import (
|
||||
DRAINAGE_CACHE_DIRNAME,
|
||||
DRAINAGE_DETAIL_FILENAME,
|
||||
@@ -89,6 +90,8 @@ class PipePoint:
|
||||
# 관이 실제로 놓인 자리(사업지 CRS, m). 노선이 바뀌어도 이 자리는 그대로다.
|
||||
x: float | None = None
|
||||
y: float | None = None
|
||||
# 구조물 집계표 항목(PLAN 21-1 · options 밖) — 없으면 None · 모양은 `common_util_summary_item`
|
||||
summary_item: dict[str, Any] | None = None
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
# 구 형식 저장분이 확장 필드 없이 그대로 다시 저장되도록 기본값은 생략한다.
|
||||
@@ -110,6 +113,8 @@ class PipePoint:
|
||||
if self.x is not None and self.y is not None:
|
||||
payload["x"] = round(float(self.x), 3)
|
||||
payload["y"] = round(float(self.y), 3)
|
||||
if self.summary_item:
|
||||
payload["summary_item"] = self.summary_item
|
||||
return payload
|
||||
|
||||
|
||||
@@ -349,6 +354,7 @@ def parse_pipe_points(values: Any) -> list[PipePoint]:
|
||||
if isinstance(options, dict) and options
|
||||
else None
|
||||
),
|
||||
summary_item=parse_summary_item(item.get("summary_item")),
|
||||
)
|
||||
)
|
||||
points.sort(key=lambda point: point.chainage_m)
|
||||
@@ -399,6 +405,7 @@ def carry_facility_attributes(base: list[PipePoint], reference: list[PipePoint])
|
||||
point.start_m = ref.start_m
|
||||
point.end_m = ref.end_m
|
||||
point.options = ref.options
|
||||
point.summary_item = ref.summary_item
|
||||
return base
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
"""구조물 집계표 항목 참조 `summary_item` — 모양 검사 · 스냅샷 폴더 이름 (PLAN 21-1).
|
||||
|
||||
summary_item = {layer: "system"|"company"|"personal",
|
||||
owner: null|"{회사}"|"{회사}/{사용자}", key: "SS000004", name: "…"}
|
||||
|
||||
구조물 기록(`structures.json` `StructureInstance`) · 관 지점 기록(`pipe_points.json` 점) 두 곳이
|
||||
같은 칸을 씀 — 검사는 여기 한 벌. 없으면 null(옛 파일 호환).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
SUMMARY_LAYERS = ("system", "company", "personal")
|
||||
_KEY = re.compile(r"^SS\d{6}$")
|
||||
_OWNER = {
|
||||
"system": None,
|
||||
"company": re.compile(r"^\d+$"),
|
||||
"personal": re.compile(r"^\d+/\d+$"),
|
||||
}
|
||||
_NAME_MAX = 200
|
||||
|
||||
|
||||
def parse_summary_item(value: Any) -> dict[str, Any] | None:
|
||||
"""모양이 맞으면 `{layer, owner, key, name}` 새 dict · 빈 값은 None · 틀리면 ValueError."""
|
||||
if value is None:
|
||||
return None
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError("집계 항목(summary_item)은 객체여야 합니다.")
|
||||
extra = set(value) - {"layer", "owner", "key", "name"}
|
||||
if extra:
|
||||
raise ValueError(f"집계 항목에 모르는 칸이 있습니다: {', '.join(sorted(extra))}")
|
||||
layer = value.get("layer")
|
||||
if layer not in SUMMARY_LAYERS:
|
||||
raise ValueError("집계 항목 층은 system · company · personal 중 하나입니다.")
|
||||
owner = value.get("owner")
|
||||
rule = _OWNER[layer]
|
||||
if rule is None:
|
||||
if owner is not None:
|
||||
raise ValueError("시스템 층 집계 항목의 owner 는 null 이어야 합니다.")
|
||||
elif not isinstance(owner, str) or not rule.match(owner):
|
||||
shape = "{회사}" if layer == "company" else "{회사}/{사용자}"
|
||||
raise ValueError(f"{layer} 층 집계 항목의 owner 는 「{shape}」 숫자 모양입니다.")
|
||||
key = value.get("key")
|
||||
if not isinstance(key, str) or not _KEY.match(key):
|
||||
raise ValueError("집계 항목 key 는 SS 와 숫자 6자리입니다(예: SS000004).")
|
||||
name = value.get("name")
|
||||
if not isinstance(name, str) or not name.strip() or len(name) > _NAME_MAX:
|
||||
raise ValueError(f"집계 항목 name 은 1~{_NAME_MAX}자 글입니다.")
|
||||
return {"layer": layer, "owner": owner, "key": key, "name": name}
|
||||
|
||||
|
||||
def snapshot_folder_name(item: dict[str, Any]) -> str:
|
||||
"""`{layer}_{owner 슬러그}_{key}` — owner 없음 = `none` · `/` = `-`.
|
||||
|
||||
예: `system_none_SS000004` · `company_3_SS000001` · `personal_3-12_SS000002`.
|
||||
"""
|
||||
owner = item.get("owner")
|
||||
slug = str(owner).replace("/", "-") if owner else "none"
|
||||
return f"{item['layer']}_{slug}_{item['key']}"
|
||||
Reference in New Issue
Block a user