feat(B05): 계획 종단선이 횡단배수 최소고를 자동 확보
계획선의 변화점(PVI)은 배수유역이 확정한 배관 배치 측점이다. 그 자리 계획고를 지반고와 같게 두면 관·구체가 들어갈 자리가 없어, 시설 제원만큼 들어 올린다. - common_util_drainage_pipes: facility_clearance_m()/pipe_anchor_clearances() 신설 (정본 산식) — 배수관 관경+토피 0.5, BOX암거 구체높이+토피 0.5, 물넘이·세월교는 좌측 패널이 설계유량으로 산출한 월류 높이(ford_height_m) - Engine_Sections: 관 지점에서 시설 여유를 함께 읽어(_load_pipe_anchors) 전달 - Engine_Grade_Profile: 앵커 목표 표고 = 지반고 + 시설 여유 - Profile_MinCover(화면 경고): 세월교·물넘이를 월류 높이 기준으로 추가. 백엔드가 정본이고 이쪽은 편집 중 즉시 경고용 사본 — 값 일치는 테스트로 잠금 검증: 재생성한 계획선의 배관 측점 실측 — Ø1000 +1.50 / 세월교 +0.30 / BOX +2.50 / Ø800 +1.30 (전부 요구 여유와 일치), 화면 경고 소거 확인. pytest 10/10, tsc·ruff 통과 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,11 @@ from B05_Profile.B05_Profile_Engine_Sections_Core import (
|
||||
SectionGenerationOptions,
|
||||
generate_sections,
|
||||
)
|
||||
from common_util.common_util_drainage_pipes import parse_pipe_points, route_signature
|
||||
from common_util.common_util_drainage_pipes import (
|
||||
parse_pipe_points,
|
||||
pipe_anchor_clearances,
|
||||
route_signature,
|
||||
)
|
||||
from common_util.common_util_json import atomic_write_json
|
||||
from common_util.common_util_route_geometry import RouteVertex
|
||||
from common_util.common_util_surface_sampler import build_surface_sampler
|
||||
@@ -89,7 +93,9 @@ def _cross_summary(cross_section: dict[str, Any]) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _load_pipe_chainages(project_root: Path, polyline: list[list[float]]) -> list[float]:
|
||||
def _load_pipe_anchors(
|
||||
project_root: Path, polyline: list[list[float]]
|
||||
) -> tuple[list[float], dict[float, float]]:
|
||||
"""배수유역도가 확정한 배관 배치 측점(누가거리)을 읽는다.
|
||||
|
||||
관 지점 파일에는 저장 당시 노선 지문이 함께 있다 — 노선이 바뀌었으면 버린다
|
||||
@@ -103,12 +109,12 @@ def _load_pipe_chainages(project_root: Path, polyline: list[list[float]]) -> lis
|
||||
/ DRAINAGE_PIPE_POINTS_FILENAME
|
||||
)
|
||||
if not path.is_file():
|
||||
return []
|
||||
return [], {}
|
||||
try:
|
||||
document = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
logger.warning("B05 계획선: 관 지점 파일을 읽지 못했습니다 (%s)", path)
|
||||
return []
|
||||
return [], {}
|
||||
vertices = [
|
||||
RouteVertex(
|
||||
x=float(p[0]), y=float(p[1]), z=float(p[2]) if len(p) > 2 else 0.0, chainage_m=0.0
|
||||
@@ -117,8 +123,12 @@ def _load_pipe_chainages(project_root: Path, polyline: list[list[float]]) -> lis
|
||||
]
|
||||
if str(document.get("route_signature") or "") != route_signature(vertices):
|
||||
logger.info("B05 계획선: 노선이 바뀌어 저장된 관 지점을 쓰지 않습니다.")
|
||||
return []
|
||||
return [pipe.chainage_m for pipe in parse_pipe_points(document.get("points"))]
|
||||
return [], {}
|
||||
points = parse_pipe_points(document.get("points"))
|
||||
# 시설 제원이 요구하는 최소 여유(관경+토피 등)를 함께 넘긴다 — 계획선이 그만큼
|
||||
# 들려야 관·구체가 들어갈 자리가 생긴다(2026-08-23 사용자 지시).
|
||||
clearances = {chainage: clearance for chainage, clearance in pipe_anchor_clearances(points)}
|
||||
return [pipe.chainage_m for pipe in points], clearances
|
||||
|
||||
|
||||
def _append_design_profiles(
|
||||
@@ -126,6 +136,7 @@ def _append_design_profiles(
|
||||
grade_options: GradeDesignOptions | None,
|
||||
station_interval_m: float | None = None,
|
||||
pipe_chainages: list[float] | None = None,
|
||||
pipe_clearances: dict[float, float] | None = None,
|
||||
) -> dict[str, Any] | None:
|
||||
"""종단 계획선을 산출해 longitudinal에 붙이고 요약을 반환한다.
|
||||
|
||||
@@ -147,6 +158,7 @@ def _append_design_profiles(
|
||||
grade_options,
|
||||
pipe_chainages,
|
||||
station_interval_m=station_interval_m,
|
||||
pipe_clearances=pipe_clearances,
|
||||
)
|
||||
except (ValueError, KeyError, ArithmeticError):
|
||||
logger.exception("B05 배관 정착 계획선 산출 실패 — 직선 분할 선형으로 대체")
|
||||
@@ -261,12 +273,14 @@ def run_section_generation(
|
||||
cross_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 종단면 저장 (계획선은 저장 직전에 종단 데이터에 붙인다)
|
||||
pipe_anchors = _load_pipe_anchors(project_root, polyline)
|
||||
grade_summary = _append_design_profiles(
|
||||
result["longitudinal"],
|
||||
grade_options,
|
||||
(result.get("options") or {}).get("station_interval_m"),
|
||||
# 1차 계획선의 변화점 = 배수유역도가 확정한 배관 배치 측점.
|
||||
pipe_chainages=_load_pipe_chainages(project_root, polyline),
|
||||
pipe_chainages=pipe_anchors[0],
|
||||
pipe_clearances=pipe_anchors[1],
|
||||
)
|
||||
# 계획선 경사 기반 포장 제안(법정 상한 초과 측점) — 비치명적.
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user