"""소단 + 다중 무릎에서 **제자리 무릎이 되풀이되어 안 끝나는지** 재현한다. 의심 — 암 경계선의 기울기가 **암 경사와 토사 경사 사이**에 있으면, 경계에 정확히 닿은 자리에서 ① 토사로 바꾸면 다음 걸음이 경계 아래로 내려가 「다시 암」 ② 암으로 바꾸면 다음 걸음이 경계 위로 올라가 「다시 토사」 가 되어 **같은 자리에서 앞뒤로 뒤집힌다**. `share`(보간 비율)가 0 이라 거리가 한 걸음도 안 나가므로 `while dist < limit` 이 끝나지 않는다. """ import signal import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from common_util.common_util_cross_berm import BermSpec, cut_profile_points # noqa: E402 # 경계선 기울기를 **두 설계 경사 사이**에 둔다 — 암 1:0.4 는 수평 1m 에 2.5m 오르고, # 토사 1:1.0 은 1.0m 오른다. 그 사이(1.5m/1m)면 「토사로 바꾸면 경계 아래, 암으로 바꾸면 # 경계 위」가 되어 같은 자리에서 뒤집힌다. BOUNDARY_RISE = 1.5 def boundary(dist: float) -> float: """시작점에서 정확히 만나고, 그 뒤로 두 경사 사이 기울기로 오르는 경계선.""" return 100.0 + dist * BOUNDARY_RISE def run(multi_knee: bool, seconds: int = 8): def on_alarm(signum, frame): # noqa: ARG001 raise TimeoutError("끝나지 않음") try: points = cut_profile_points( 0.0, 100.0, 0.4, 1.0, boundary, BermSpec(0.5, 3.0, 0.0), 50.0, multi_knee ) return f"끝남 · 꼭짓점 {len(points)}개" except RecursionError as exc: return f"RecursionError {exc}" if __name__ == "__main__": import threading for multi in (False, True): result = {"v": None} thread = threading.Thread(target=lambda: result.__setitem__("v", run(multi)), daemon=True) thread.start() thread.join(8) state = result["v"] if not thread.is_alive() else "⚠ 8초 안에 안 끝남 (무한 반복)" print(f"multi_knee={multi}: {state}")