auto: 2026-07-29 20:06 (EOMSANGDON-HOME)

This commit is contained in:
2026-07-29 20:06:57 +09:00
parent 4fbaf63a60
commit f72017a6ee
@@ -435,6 +435,51 @@ def _assemble_march_polygon(
return polygon
def _refine_road_edge(polygon: Polygon, road_line: LineString) -> Polygon:
"""경계의 도로변 구간을 도로선 원해상도 좌표로 치환한다.
단순화(simplify)가 도로변 경계를 뭉개 도로를 가로지르는 것을 막는다
(2026-07-29 사용자 지시: 경계 참조를 도로선 해상도와 매칭).
"""
coords = list(polygon.exterior.coords)[:-1]
count = len(coords)
near = [road_line.distance(Point(c)) < 6.0 for c in coords]
if not any(near) or all(near):
return polygon
start = next(i for i in range(count) if not near[i])
coords = coords[start:] + coords[:start]
near = near[start:] + near[:start]
ring: list[tuple[float, float]] = []
i = 0
while i < count:
if not near[i]:
ring.append(coords[i])
i += 1
continue
j = i
while j < count and near[j]:
j += 1
t1 = road_line.project(Point(coords[i]))
t2 = road_line.project(Point(coords[j - 1]))
segment = substring(road_line, min(t1, t2), max(t1, t2))
if segment.geom_type == "LineString" and len(segment.coords) >= 2:
segment_coords = list(segment.coords)
if t1 > t2:
segment_coords.reverse()
ring.extend(segment_coords)
else:
ring.extend(coords[i:j])
i = j
if len(ring) < 4:
return polygon
refined = Polygon(ring).buffer(0)
if refined.geom_type == "MultiPolygon":
refined = max(refined.geoms, key=lambda part: part.area)
if refined.is_empty or refined.geom_type != "Polygon":
return polygon
return refined
def build_watershed_basins(
vertices: list[Any],
candidates: list[StructureCandidate],
@@ -455,7 +500,8 @@ def build_watershed_basins(
if contour_index.tree is None:
logger.warning("표고 속성이 있는 등고선이 없어 유역을 산정하지 못했습니다.")
return []
spot_index = ContourIndex(spot_features, elevation_keys)
# 표고점은 참조하지 않는다(2026-07-29 사용자 지시: 계측 측점 데이터라 오류 유입).
_ = spot_features
road_line = LineString([(vertex.x, vertex.y) for vertex in vertices])
ordered = sorted(candidates, key=lambda item: item.chainage_m)
@@ -569,13 +615,13 @@ def build_watershed_basins(
outlet_z = contour_index.nearest_elevation(outlet, UPHILL_PROBE_RADIUS_M)
if outlet_z is None:
outlet_z = _interpolate_vertex(vertices, candidate.chainage_m)[2]
top_z = max(
contour_index.max_elevation_within(polygon) or outlet_z,
spot_index.max_elevation_within(polygon) or outlet_z,
)
# 표고차는 등고선만으로 계산한다(표고점 미참조 — 사용자 지시).
top_z = contour_index.max_elevation_within(polygon) or outlet_z
boundary_line = polygon.simplify(5.0, preserve_topology=True)
if boundary_line.is_empty or boundary_line.geom_type != "Polygon":
boundary_line = polygon
# 도로변 경계는 단순화 없이 도로선 해상도를 유지한다.
boundary_line = _refine_road_edge(boundary_line, road_line)
boundary = [[float(x), float(y)] for x, y in boundary_line.exterior.coords]
if flow_length <= 0.0:
flow_length = max(