From f72017a6ee76712d204deb866651090fe2c0e767 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Wed, 29 Jul 2026 20:06:57 +0900 Subject: [PATCH] auto: 2026-07-29 20:06 (EOMSANGDON-HOME) --- ...B05_wf2_Route_Engine_Drainage_Watershed.py | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/B05_wf2_Route/B05_wf2_Route_Engine_Drainage_Watershed.py b/B05_wf2_Route/B05_wf2_Route_Engine_Drainage_Watershed.py index 3a77ccdd..3b2f12ba 100644 --- a/B05_wf2_Route/B05_wf2_Route_Engine_Drainage_Watershed.py +++ b/B05_wf2_Route/B05_wf2_Route_Engine_Drainage_Watershed.py @@ -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(