diff --git a/B05_Profile/B05_Profile_Engine_Solver.py b/B05_Profile/B05_Profile_Engine_Solver.py index 25f113d8..804d9c8d 100644 --- a/B05_Profile/B05_Profile_Engine_Solver.py +++ b/B05_Profile/B05_Profile_Engine_Solver.py @@ -23,6 +23,7 @@ from config.config_system import ( FOREST_ROAD_MAX_GRADE, FOREST_ROAD_MIN_CURVE_R_M, ROUTE_DEFAULT_GRADE_CLASS, + ROUTE_DIRECT_LINK_CELL_FACTOR, ROUTE_GRID_RES_M, ROUTE_MAX_COST_CELLS, ROUTE_MAX_GRADE, @@ -390,31 +391,43 @@ def solve_optimal_route( full_path_grid: list[tuple[int, int]] = [] segment_bounds: list[dict[str, Any]] = [] + direct_link_max_m = ROUTE_DIRECT_LINK_CELL_FACTOR * target_res + for i in range(len(sequence) - 1): pt_start = sequence[i] pt_end = sequence[i + 1] r_s, c_s, _ = get_grid_indices(pt_start) r_e, c_e, _ = get_grid_indices(pt_end) - segment = single_segment_dijkstra( - r_s, - c_s, - r_e, - c_e, - x_coords_sub, - y_coords_sub, - z_grid_sub, - valid_mask_sub, - dz_dx, - dz_dy, - ap_list, - weights, - max_grade, - target_res, - min_curve_radius_m, - max_uphill_grade, - max_downhill_grade, - ) + # 제어점 쌍이 문턱보다 가까우면 격자 탐색 없이 직결한다. 두 끝은 어차피 + # 원좌표로 되박히므로 이 구간 평면은 원청 계획노선 그대로 보존된다. + # 같은 칸에 스냅돼도 두 항목을 유지해 정점이 합쳐져 사라지지 않게 한다. + # 경사·곡선반경 제약은 이 구간에선 경고(curve_warning_segments)로만 남는다. + if ( + math.hypot(pt_end["x"] - pt_start["x"], pt_end["y"] - pt_start["y"]) + <= direct_link_max_m + ): + segment = [(r_s, c_s), (r_e, c_e)] + else: + segment = single_segment_dijkstra( + r_s, + c_s, + r_e, + c_e, + x_coords_sub, + y_coords_sub, + z_grid_sub, + valid_mask_sub, + dz_dx, + dz_dy, + ap_list, + weights, + max_grade, + target_res, + min_curve_radius_m, + max_uphill_grade, + max_downhill_grade, + ) if not segment: fp_note = "·금지구역(FP)" if fp_list else "" raise ValueError( diff --git a/config/config_system.py b/config/config_system.py index 8f5b1289..db445c46 100644 --- a/config/config_system.py +++ b/config/config_system.py @@ -261,6 +261,9 @@ ROUTE_AVOID_DEFAULT_RADIUS_M = float(os.getenv("ROUTE_AVOID_DEFAULT_RADIUS_M", " ROUTE_DEFAULT_GRADE_CLASS = os.getenv("ROUTE_DEFAULT_GRADE_CLASS", "trunk") ROUTE_MAX_COST_CELLS = int(os.getenv("ROUTE_MAX_COST_CELLS", "4000000")) ROUTE_REQUIRED_POINT_TOLERANCE_M = float(os.getenv("ROUTE_REQUIRED_POINT_TOLERANCE_M", "1.0")) +# 제어점 쌍이 이 배수×비용면 셀보다 가까우면 격자 탐색 없이 직결한다 — 원청 계획노선 +# 보존 (2026-08-30 사용자 확정. 조밀 기준선은 격자 중간점이 못 끼어들어 평면 불변). +ROUTE_DIRECT_LINK_CELL_FACTOR = float(os.getenv("ROUTE_DIRECT_LINK_CELL_FACTOR", "2.0")) # 임도 종류 — 현행 규칙(별표2)의 3종. `branch`(지선)는 규칙에서 폐지됐으나 기존 # 저장분이 남아 있어 값으로는 계속 받는다(화면 선택지에서는 뺀다, 2026-08-19). ROUTE_GRADE_CLASSES = ("trunk", "fire", "work", "branch")