feat(B04): 세부유역 경계를 링 목록(외곽+구멍)으로 넓혀 중첩·빈공간 해소
단일 링 자료형이 곧 중첩·빈공간이었다. 아래 유역이 위 유역을 감싸면 구멍이 사라져 위 유역을 통째로 덮고(합성 실측 256㎡ 전량), 한 관의 유역이 두 조각이면 작은 쪽이 사라져 빈공간이 됐다(144㎡). - `polygon_parts()` 신설 — 조각마다 [외곽 링, 구멍 링...], 넓은 조각부터. - `WatershedBasin.boundary_parts` 로 교체. `boundary_xy`(가장 넓은 조각의 외곽)와 `boundary_rings`(편 링 목록)는 파생 속성이라 옛 소비처는 그대로 동작한다. - API 에 `polygon_rings_lonlat` 추가. 저장 GeoJSON 은 구멍을 가진 Polygon, 조각이 여럿이면 MultiPolygon. - 캔버스 4곳(B04 유역화면 채움·선택, B05 배수유역도 채움·선택)은 even-odd 로 한 번에 채우고 `pointInRings()` 로 판정 — 구멍 안을 눌러도 바깥 유역이 잡히지 않는다. 중복이던 지역 `pointInRing` 은 삭제하고 공용 것으로 통일. 검증: 단위 5건 신규(도넛 구멍 보존·조각 2개 보존·파생 속성·빈 경계·조립 경로 전체에서 링 2개), 전체 168 passed, typecheck 통과. 브라우저 — API 가 유역 22개에 링 목록을 실어 보내고, 캔버스 even-odd 실측(가운데 알파 0 / 고리 255)으로 구멍이 실제로 뚫린다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -560,6 +560,25 @@ def polygonize_labels(
|
||||
return merged
|
||||
|
||||
|
||||
def polygon_parts(geometry: Polygon | MultiPolygon) -> list[list[list[tuple[float, float]]]]:
|
||||
"""폴리곤을 **조각 목록**으로 편다 — 조각마다 [외곽 링, 구멍 링...] 순.
|
||||
|
||||
`largest_ring()`은 가장 큰 조각의 외곽 하나만 낸다. 세부유역에서는 그 자리가 곧
|
||||
중첩·빈공간이었다(2026-09-03 합성 실측): 아래 유역이 위 유역을 감싸면 구멍이 사라져
|
||||
위 유역 256㎡가 통째로 덮이고, 한 관의 유역이 두 조각(225㎡+144㎡)이면 작은 144㎡가
|
||||
빠져 빈공간이 됐다. 조각은 넓은 것부터, 좌표는 조각 안에서 외곽 다음에 구멍이다.
|
||||
"""
|
||||
if geometry.is_empty:
|
||||
return []
|
||||
parts = list(geometry.geoms) if geometry.geom_type == "MultiPolygon" else [geometry]
|
||||
result: list[list[list[tuple[float, float]]]] = []
|
||||
for part in sorted(parts, key=lambda item: item.area, reverse=True):
|
||||
rings = [[(float(x), float(y)) for x, y in part.exterior.coords]]
|
||||
rings.extend([(float(x), float(y)) for x, y in hole.coords] for hole in part.interiors)
|
||||
result.append(rings)
|
||||
return result
|
||||
|
||||
|
||||
def largest_ring(geometry: Polygon | MultiPolygon) -> list[tuple[float, float]]:
|
||||
"""폴리곤(또는 멀티폴리곤)에서 가장 큰 조각의 외곽 링 좌표를 뽑는다."""
|
||||
if geometry.is_empty:
|
||||
|
||||
Reference in New Issue
Block a user