feat(B05): 구조물 컨테이너 병합 1단계 — 계곡 통과 시설·구간 기준점·phase 분리
PLAN 2026-08-17 「B05 구조물 컨테이너 병합」 백엔드. 배관 정본은 유역 계산의 입력이라 저장소를 옮기지 않고 제자리 확장한다. - PipePoint: facility(배관/BOX암거/물넘이/세월교)·start_m/end_m(기준점 앞뒤 구간)·options(세월교 관 종류/크기/수량) 추가. 구 파일은 배관·폭 미지정으로 읽히고 기본값은 저장 시 생략된다(하위 호환). 교량은 임도용이 아니라 없다. - carry_facility_attributes: 세부유역 계산기는 chainage만 다뤄 재구성 목록이 전부 기본 배관이 된다 — 원본에서 종류·구간·옵션을 되붙인다. B04 basins 라우터의 재구성 지점에 적용하고 응답·GeoJSON에도 시설 정보를 싣는다. - StructureInstance: 구간형 chainage_m = 기준점(마킹 위치) 허용, 시작≤기준≤종료 검증, 미지정 시 시점으로 채움(기존 저장분 호환). anchor_m = 기준점. - 레지스트리: 옵션 phase 필드(b05/detail) 신설. required 32건을 detail로 이동 — 필수 원칙은 유지하고 강제 시점만 B06/B07로 미룬다(B05 = 유무·종류·위치 단계, 2026-08-17 사용자 확정). BOX암거·물넘이·세월교(표시용, managed_by= pipe_points)와 A6 노출형 횡단수로·A7 개거(수동) 5종 추가, 총 37종. - Repository: phase=detail 옵션은 B05 저장에서 필수 강제 제외. b05 필수는 기존대로 강제. tmp/tests 88건 통과 (신규: pipe facility 16·span anchor 10·registry 정책 재편). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ from common_util.common_util_drainage_detail import DrainageDetail, build_detail
|
||||
from common_util.common_util_drainage_pipes import (
|
||||
PIPE_SOURCE_USER,
|
||||
PipePoint,
|
||||
carry_facility_attributes,
|
||||
clear_pipe_points,
|
||||
load_pipe_points,
|
||||
parse_pipe_points,
|
||||
@@ -60,9 +61,10 @@ def _build(
|
||||
return None, []
|
||||
if points:
|
||||
_retag(detail.pipes, points)
|
||||
return detail, [
|
||||
PipePoint(chainage_m=pipe.chainage_m, source=pipe.reason) for pipe in detail.pipes
|
||||
]
|
||||
rebuilt = [PipePoint(chainage_m=pipe.chainage_m, source=pipe.reason) for pipe in detail.pipes]
|
||||
# 계산기는 chainage만 다뤄 시설 종류·구간·옵션이 사라진다 — 원본에서 되붙인다
|
||||
# (2026-08-17 계곡 통과 시설: 배관/BOX암거/물넘이/세월교).
|
||||
return detail, carry_facility_attributes(rebuilt, points or [])
|
||||
|
||||
|
||||
def _retag(pipes: list[StructureCandidate], points: list[PipePoint]) -> None:
|
||||
@@ -107,13 +109,15 @@ def _payload(
|
||||
"flow_arrows": detail.flow_arrows,
|
||||
"arrow_spacing_m": detail.arrow_spacing_m,
|
||||
"upstream_lonlat": detail.upstream_lonlat,
|
||||
# 시설 종류·구간·옵션까지 함께 싣는다(as_dict — 기본 배관·폭 0은 필드 생략).
|
||||
"pipe_points": [
|
||||
{
|
||||
**point.as_dict(),
|
||||
"chainage_m": round(pipe.chainage_m, 2),
|
||||
"lonlat": list(to_lonlat(pipe.x, pipe.y)),
|
||||
"source": pipe.reason,
|
||||
}
|
||||
for pipe in detail.pipes
|
||||
for pipe, point in zip(detail.pipes, points)
|
||||
],
|
||||
"basins": [
|
||||
{
|
||||
@@ -172,11 +176,9 @@ def _basin_features(
|
||||
features.append(
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"kind": "pipe",
|
||||
"chainage_m": round(point.chainage_m, 2),
|
||||
"source": point.source,
|
||||
},
|
||||
# 시설 종류·구간·옵션도 함께 남긴다(as_dict — 기본값 생략) — GeoJSON만
|
||||
# 보고도 세월교인지 배관인지 알 수 있어야 한다.
|
||||
"properties": {"kind": "pipe", **point.as_dict()},
|
||||
"geometry": {"type": "Point", "coordinates": list(to_lonlat(pipe.x, pipe.y))},
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user