fix(B05): 시설 속성은 측점이 같은 관에만 붙임 · 옛 관 이동 예약 적용 제거
- 원인: 화면 attach · 서버 carry_facility_attributes 가 거리 제한 없이 가장 가까운 관에 속성을 붙여, 관 수 > 속성 수이거나 관을 이웃 쪽으로 옮기면 BOX · 세월교가 옆 관 측점으로 넘어감 - 고침: 화면 carryIndices ↔ 서버 carry_indices 짝 — 허용 오차 0.05m 안 가장 가까운 원본만 · 한 원본 한 번 · 못 붙인 관은 속성 없음(추천은 기존대로 빈칸에만) · 두 파일 머리에 짝 표기 - 관을 옮기면 속성이 따라감: 지도 끌기(onMove → move) · 되돌리기 · 구조물 폼(follow — 사라진 관 하나 · 새 관 하나일 때) - B06 옛 「관 이동 예약」(culvertmove): 저장 때 읽지도 적용하지도 않음 — flushCulvertOptions · createCulvertOptionWriter 에서 이동 키 제거 - 시험: 거울 시험 test_b05_facility_carry(화면 · 서버 같은 답 · 끌기 · 되돌리기) · 옛 최근접 · 이동 예약 적용 시험을 새 규칙으로 고침 - 확인: ORCA 5180 랩탑_보조 — 세월교(173.09) 8m 앞 165m 에 옵션 없는 관 추가 → 저장 → pipe_points.json 165 = 속성 없음 · 173.09 = ford_bridge · 나머지 11건 전후 같음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RrQ65VtGZbae2VKgYVMhmc
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
|
||||
노선이 바뀌면(`route_signature` 불일치) 좌표가 있는 저장분은 새 노선에 투영해 이월하고,
|
||||
좌표가 없는 구 저장분만 버린다.
|
||||
|
||||
짝: 시설 속성 붙이기 `carry_indices` ↔ 화면 `B05_Profile/B05_Profile_UI_Drainage_Facility.ts`
|
||||
`carryIndices` — 같은 규칙(허용 오차 안 · 한 원본 한 번) · 거울 시험 test_b05_facility_carry.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -352,21 +355,46 @@ def parse_pipe_points(values: Any) -> list[PipePoint]:
|
||||
return points
|
||||
|
||||
|
||||
# 시설 속성을 붙이는 허용 오차(m) — 측점 반올림(0.01m)을 덮되 이웃 관에는 안 닿는 폭.
|
||||
# 화면 `CARRY_TOLERANCE_M` 과 짝.
|
||||
CARRY_TOLERANCE_M = 0.05
|
||||
|
||||
|
||||
def carry_indices(targets: list[float], sources: list[float]) -> list[int | None]:
|
||||
"""관 측점마다 속성을 가져올 원본 번호(못 붙이면 None).
|
||||
|
||||
허용 오차 안 가장 가까운 원본만 · 한 원본은 한 번만 — 화면 `carryIndices` 와 같은 규칙.
|
||||
"""
|
||||
free = list(range(len(sources)))
|
||||
picked: list[int | None] = []
|
||||
for target in targets:
|
||||
best: int | None = None
|
||||
for index in free:
|
||||
gap = abs(sources[index] - target)
|
||||
if gap <= CARRY_TOLERANCE_M and (best is None or gap < abs(sources[best] - target)):
|
||||
best = index
|
||||
if best is not None:
|
||||
free.remove(best)
|
||||
picked.append(best)
|
||||
return picked
|
||||
|
||||
|
||||
def carry_facility_attributes(base: list[PipePoint], reference: list[PipePoint]) -> list[PipePoint]:
|
||||
"""계산기를 거쳐 재구성된 목록에 시설 종류·구간·옵션을 되붙인다.
|
||||
|
||||
세부유역 계산기는 chainage만 다루므로 계산에서 돌아온 목록은 전부 기본 배관이 된다.
|
||||
그대로 저장하면 사용자가 고른 세월교·BOX암거가 배관으로 되돌아간다. 좌표가 미세
|
||||
조정(스냅)될 수 있어 정확 일치가 없으면 가장 가까운 원본에서 승계한다 — 생성 사유를
|
||||
되붙이는 `_retag`(B04 라우터)과 같은 기준이다.
|
||||
세부유역 계산기는 chainage만 다루므로(반올림 0.01m) 계산에서 돌아온 목록은 전부 기본
|
||||
배관이 된다. 그대로 저장하면 사용자가 고른 세월교·BOX암거가 배관으로 되돌아간다.
|
||||
붙이기는 `carry_indices` — 허용 오차 밖의 관은 속성 없이 둔다(옆 관 속성을 가져가지 않음).
|
||||
"""
|
||||
if not reference:
|
||||
return base
|
||||
by_key = {round(ref.chainage_m, 2): ref for ref in reference}
|
||||
for point in base:
|
||||
ref = by_key.get(round(point.chainage_m, 2))
|
||||
if ref is None:
|
||||
ref = min(reference, key=lambda item: abs(item.chainage_m - point.chainage_m))
|
||||
picks = carry_indices(
|
||||
[point.chainage_m for point in base], [ref.chainage_m for ref in reference]
|
||||
)
|
||||
for point, pick in zip(base, picks):
|
||||
if pick is None:
|
||||
continue # 못 붙인 관 = 계산기가 돌려준 기본 배관 그대로(추천은 뒤에서 빈칸에만)
|
||||
ref = reference[pick]
|
||||
point.facility = ref.facility
|
||||
point.start_m = ref.start_m
|
||||
point.end_m = ref.end_m
|
||||
|
||||
Reference in New Issue
Block a user