diff --git a/common_util/common_util_drainage_detail.py b/common_util/common_util_drainage_detail.py index 0f3961ea0..ac93ca754 100644 --- a/common_util/common_util_drainage_detail.py +++ b/common_util/common_util_drainage_detail.py @@ -26,7 +26,7 @@ from __future__ import annotations import json import logging -from dataclasses import dataclass, field +from dataclasses import dataclass, field, replace from pathlib import Path from typing import Any @@ -66,6 +66,10 @@ _SCORE_WEIGHT_STRENGTH = 0.7 _SCORE_WEIGHT_SAG = 0.3 # 성토부(내리막)는 물이 노선 밖으로 빠지므로 관 위치로 덜 선호한다. _SCORE_FILL_PENALTY = 0.5 +# [자동 제안] 전체 자동(369) — 새 자리에서 이만큼(m) 안의 지금 관 = 같은 관(그 자리 그대로 · +# 속성 이어받음). 화면 `SAME_PIPE_M`(제안 · 같은 유역)과 같은 값 — 노선 따라감으로 cm 어긋난 +# 세월교도 같은 관. +SAME_PIPE_M = 0.5 @dataclass @@ -201,6 +205,19 @@ def build_detail( # 자동 관 자리 = 정수 m · 일반 측점 1 m 안이면 그 측점(234-1) — 확정본(위)은 단추로만 placed = place_pipes(vertices, base, routing.strength_curve, fill=auto is not None) pipes = snap_candidates(placed, vertices) + if confirmed_chainages: + kept = pipes_from_chainages(vertices, confirmed_chainages) + pipes = [ + replace( + min( + (k for k in kept if abs(k.chainage_m - pipe.chainage_m) <= SAME_PIPE_M), + key=lambda k: abs(k.chainage_m - pipe.chainage_m), + default=pipe, + ), + reason=pipe.reason, + ) + for pipe in pipes + ] candidates = suggest_pipe_positions(vertices, pipes, routing.strength_curve) detail = DrainageDetail( diff --git a/resources/tester/test_369_drainage_auto.py b/resources/tester/test_369_drainage_auto.py index 2022901a8..e342a71ea 100644 --- a/resources/tester/test_369_drainage_auto.py +++ b/resources/tester/test_369_drainage_auto.py @@ -56,7 +56,7 @@ def test_all_은_세류선_더하기_100m_보충_지금_목록_무시(tmp_path): reasons = [p.reason for p in detail.pipes] places = [p.chainage_m for p in detail.pipes] assert reasons.count("stream") == 1 and reasons.count("spacing") == 2 - assert 150.0 in places and 10.0 not in places + assert 150.02 in places and 10.0 not in places # 세류선 150 m 0.5 m 안의 지금 관 = 그 자리 gaps = np.diff([0.0, *places, 300.0]) assert gaps.max() <= 100.0 and not detail.pipe_candidates @@ -78,7 +78,7 @@ def _build(tmp_path, monkeypatch, points, auto): def test_all_같은_자리_관은_속성_id_유지_새_관은_기본값(tmp_path, monkeypatch): kept = PipePoint( - chainage_m=150.03, + chainage_m=150.3, # 세류선 150 m 에서 0.3 m — 노선 따라감으로 어긋난 같은 관 source="user", facility="ford_bridge", options={"ford_width_m": 4.0}, @@ -88,6 +88,7 @@ def test_all_같은_자리_관은_속성_id_유지_새_관은_기본값(tmp_path _, carried = _build(tmp_path, monkeypatch, [gone, kept], "all") ford = [p for p in carried if p.id == "keep"] assert len(ford) == 1 and ford[0].facility == "ford_bridge" and ford[0].source == "user" + assert ford[0].chainage_m == 150.3 # 그 자리 그대로 assert all(p.id != "gone" for p in carried) fresh = [p for p in carried if p.id != "keep"] assert len(fresh) == 2 and all(p.source == "spacing" for p in fresh)