From 88a055ff1982476684380ad69eb19ab6a389ab11 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 22 Oct 2026 12:46:09 +0900 Subject: [PATCH] =?UTF-8?q?fix(510-1=20=EC=9E=90=EB=8F=99=20=EC=A0=9C?= =?UTF-8?q?=EC=95=88=20=ED=9B=84=EB=B3=B4):=20=EA=B0=84=EA=B2=A9=20?= =?UTF-8?q?=EB=B3=B4=EC=B6=A9=20=EA=B8=B0=EC=A4=80=EC=97=90=20=EC=A7=80?= =?UTF-8?q?=EC=9A=B4=20=EA=B5=90=EC=B0=A8=20=ED=9B=84=EB=B3=B4=EB=8F=84=20?= =?UTF-8?q?=EB=84=A3=EC=9D=8C(=EA=B2=80=EC=A6=9D=5Fsub3=20=EC=A7=80?= =?UTF-8?q?=EC=9A=B4=20385=20=EC=98=86=20378=20=ED=9B=84=EB=B3=B4=EA=B0=80?= =?UTF-8?q?=20=EC=84=AC)=20=C2=B7=20=EC=98=9B=20=EC=A0=9C=EC=95=88=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=9D=98=20=EA=B4=80=20=EC=9E=90=EB=A6=AC=20?= =?UTF-8?q?=EC=A4=84=20=EA=B1=B7=EC=9D=8C([=EC=9E=90=EB=8F=99=20=EC=A0=9C?= =?UTF-8?q?=EC=95=88]=20=EB=AA=A9=EB=A1=9D=EA=B3=BC=20=EB=91=90=20?= =?UTF-8?q?=EB=B2=8C=20=EA=B2=B9=EC=B9=A8=20=C2=B7=20=EC=A7=80=EB=8F=84=20?= =?UTF-8?q?=EC=A0=90=EC=84=A0=20=EC=9B=90=20=3D=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=EC=A0=9C=EC=95=88=20=ED=9B=84=EB=B3=B4=EB=A7=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- B05_Profile/B05_Profile_UI_Drainage_Panel.ts | 2 +- B05_Profile/B05_Profile_UI_Drainage_Suggest.ts | 18 ++++++------------ common_util/common_util_stream_crossing.py | 4 ++-- .../tester/test_349_drainage_live_flow.py | 5 +++-- resources/tester/test_510_auto_pipe_propose.py | 7 ++++--- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts index 03e9f3ef5..76b1b7ef4 100644 --- a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts @@ -245,7 +245,7 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra markedChainage, stationIntervalM: MAP_STATION_INTERVAL_M, intervalSpans, - candidates: [...live.suggest.candidates(), ...propose.candidates()], + candidates: propose.candidates(), }); updateImageTransform(); } diff --git a/B05_Profile/B05_Profile_UI_Drainage_Suggest.ts b/B05_Profile/B05_Profile_UI_Drainage_Suggest.ts index 379702fa1..6ba8725a4 100644 --- a/B05_Profile/B05_Profile_UI_Drainage_Suggest.ts +++ b/B05_Profile/B05_Profile_UI_Drainage_Suggest.ts @@ -1,9 +1,8 @@ /* ============================================================================= * B05_Profile_UI_Drainage_Suggest.ts - * 배수유역 칸 제안 목록(347-3) — 관경 · 시설 종류 · 관 자리 후보를 보여 주고 [적용] 한 번에 관경 · 시설만 - * 관 초안으로(관 자리 = [자동 제안] · 369). + * 배수유역 칸 제안 목록(347-3) — 관경 · 시설 종류를 보여 주고 [적용] 한 번에 관 초안으로. * 모으기 · 얹기 규칙은 `logic/B05_Profile_Drainage_Suggest.ts` · 자동 바꿈 없음. - * 관 자리 후보는 배수유역도에도 점선 원으로 그림(`candidates()` → 그리기 판). + * 관 자리 후보 = [자동 제안] 목록(510 · `B05_Profile_UI_Drainage_Propose`) — 여기 안 올림(두 목록 겹침). * ========================================================================== */ import type { @@ -27,8 +26,7 @@ const facilityName = (id: string): string => FACILITY_NAME[id] ?? id; /** 제안 한 줄 글. */ export function suggestionText(item: Suggestion): string { const at = `측점 ${Math.round(item.chainageM)} m`; - if (item.kind === "position") - return `${at} — 관 자리 후보(흐름이 모이는 오목 자리 · [자동 제안])`; + if (item.kind === "position") return at; // 모으지 않음(510 · [자동 제안] 목록) if (item.kind === "facility") return `${at} — ${facilityName(item.from)} → ${facilityName(item.to)} 검토`; return `${at} — 관경 ${item.from === null ? "미정" : `Ø${item.from}`} → Ø${item.to}`; @@ -39,8 +37,6 @@ export interface DrainageSuggest { update(response: DetailBasinResponse): void; /** 노선 · 관이 바뀌어 낡음 — [적용] 끔(옛 노선 기준 제안이 새 노선에 안 들어가게). */ setStale(stale: boolean): void; - /** 관 자리 후보 누가거리 — 배수유역도 점선 원. */ - candidates(): number[]; } export function createDrainageSuggest( @@ -66,9 +62,9 @@ export function createDrainageSuggest( root.append(head, list); let suggestions: Suggestion[] = []; let stale = false; - /** [적용] 켜짐 — 낡지 않고 관경 · 시설 제안이 있을 때(관 자리 후보만이면 할 일 없음). */ + /** [적용] 켜짐 — 낡지 않고 관경 · 시설 제안이 있을 때. */ const paintApply = (): void => { - apply.disabled = stale || !suggestions.some((item) => item.kind !== "position"); + apply.disabled = stale || suggestions.length === 0; apply.title = stale ? "노선이 바뀌어 제안이 낡음 — 새 계산 뒤 적용" : applyTitle; }; @@ -82,7 +78,7 @@ export function createDrainageSuggest( update(response) { suggestions = response.stale ? [] - : collectSuggestions(response.pipe_points, response.basins, response.pipe_candidates ?? []); + : collectSuggestions(response.pipe_points, response.basins, []); root.hidden = suggestions.length === 0; title.textContent = `제안 ${suggestions.length}건`; paintApply(); @@ -98,7 +94,5 @@ export function createDrainageSuggest( stale = next; paintApply(); }, - candidates: () => - suggestions.filter((item) => item.kind === "position").map((item) => item.chainageM), }; } diff --git a/common_util/common_util_stream_crossing.py b/common_util/common_util_stream_crossing.py index 150cdab77..094d3e19a 100644 --- a/common_util/common_util_stream_crossing.py +++ b/common_util/common_util_stream_crossing.py @@ -237,7 +237,7 @@ def propose_pipes( 상태 = held(라벨 짝 관 · 교차 5 m 안 관) · dismissed(지움 표지 짝 · 라벨 = 그 표지) · new. 짝 잡기 = 노선 [저장](`add_crossing_pipes`)과 같은 `claim_crossings`(관 라벨 + 지움 표지 함께). - 간격 보충 = 지금 관 + 새 교차 후보 사이가 최대 간격을 넘는 구간(`suggest_pipe_positions`). + 간격 보충 = 지금 관 + 교차 후보(새 · 지운 관) 사이 최대 간격 넘는 구간(suggest_pipe_positions). """ from common_util.common_util_drainage_detail import suggest_pipe_positions from common_util.common_util_route_geometry import interpolate_vertex @@ -270,7 +270,7 @@ def propose_pipes( } ) if strength_curve is not None: - base = sorted({*taken, *(item["chainage_m"] for item in found if item["state"] == "new")}) + base = sorted({*taken, *(item["chainage_m"] for item in found if item["state"] != "held")}) placed = [ StructureCandidate(chainage_m=c, x=xy[0], y=xy[1], reason="confirmed") for c in base diff --git a/resources/tester/test_349_drainage_live_flow.py b/resources/tester/test_349_drainage_live_flow.py index 13bbc5bb1..753d70263 100644 --- a/resources/tester/test_349_drainage_live_flow.py +++ b/resources/tester/test_349_drainage_live_flow.py @@ -60,8 +60,9 @@ def test_manual_update_answer_lands_after_same_rerun(r): def test_suggestions_and_apply(r): - assert r["suggest"]["shown"] and r["suggest"]["title"] == "제안 2건" - assert len(r["suggest"]["rows"]) == 2 + # 관 자리 후보(200)는 제안 목록에 안 올림 — [자동 제안] 목록 몫(510) + assert r["suggest"]["shown"] and r["suggest"]["title"] == "제안 1건" + assert len(r["suggest"]["rows"]) == 1 points = {p["chainage_m"]: p for p in r["applied"]["points"]} assert points[100]["options"]["pipe_diameter_mm"] == 1200 assert 200 not in points # 관 자리 후보는 [적용]이 안 더함 — [자동 제안] 몫(369) diff --git a/resources/tester/test_510_auto_pipe_propose.py b/resources/tester/test_510_auto_pipe_propose.py index 6169e971a..d2d34de73 100644 --- a/resources/tester/test_510_auto_pipe_propose.py +++ b/resources/tester/test_510_auto_pipe_propose.py @@ -82,9 +82,10 @@ def test_간격_보충_분석_있을_때만(): found = propose_pipes(vertices, crossings, pipes, dismissed, curve) spacing = [f for f in found if f["kind"] == "spacing"] assert spacing and all(f["state"] == "new" and "stream_label" not in f for f in spacing) - # 지금 관 + 새 교차 후보 사이 최대 간격(100 m) 넘는 구간만 · 320 뒤 280 m - taken = [150.0, 252.0, 320.0] - assert all(min(abs(f["chainage_m"] - t) for t in taken) > 0.5 for f in spacing) + # 지금 관 + 교차 후보(새 · 지운 관) 사이 최대 간격(100 m) 넘는 구간만 · 320 뒤 280 m · + # 지운 교차(50) 곁에 간격 보충이 붙지 않음(화면 실측 = 지운 385 옆 378) + taken = [50.0, 150.0, 252.0, 320.0] + assert all(min(abs(f["chainage_m"] - t) for t in taken) > 5.0 for f in spacing) assert any(f["chainage_m"] > 320.0 for f in spacing) assert not [f for f in propose_pipes(vertices, crossings, pipes, dismissed) if f["kind"] == "spacing"]