feat(B05): 곡선 생략 규칙을 쓰지 않음 — 꺾이는 자리에는 늘 곡선
사용자 지시(2026-09-07) — 「내각 155 이상이면 곡선 생략은 반영하지 말자. 사용자가 계획 평면 노선을 수정할 때 문제가 될 것 같아.」 곡선이 있다 없다 하면 잡는 손잡이도 있다 없다 하고, 조금 폈다는 이유로 곡선이 사라지면 되돌릴 길이 없음. 그래서 별표2 의 155° 생략 규칙을 쓰지 않고 꺾이는 자리에는 전부 곡선을 둠. 상수는 법정 근거를 잃지 않게 남겨만 둠. 실측(용화 예상노선 331점) — 곡선 13 → 26곳, 정점 145 → 181, 반지름 12~28 → 12~199m, 내각 109~177°. 벗어남은 그대로 최대 3.57m · 평균 1.081 → 1.102m (원본 충실도 유지). 시험 하나를 뒤집음 — 「펴진 자리는 곡선을 안 둔다」 → 「펴진 자리에도 곡선을 둔다」. 아주 완만하므로 원본과 거의 겹치는 것도 함께 확인. pytest 420 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,7 +48,12 @@ MAX_REFINE_DEPTH = 3
|
||||
# 원호를 몇 도마다 한 점씩 찍을지 — 촘촘할수록 매끄럽지만 정점이 늘어난다.
|
||||
ARC_STEP_DEG = 5.0
|
||||
|
||||
# 이 값 이상으로 펴진 자리는 곡선을 두지 않는다(별표2: 내각 155° 이상).
|
||||
# 별표2 가 「곡선을 두지 않을 수 있다」고 하는 내각(도) — **지금은 쓰지 않는다.**
|
||||
#
|
||||
# 왜 안 쓰나(2026-09-07 사용자 지시) — 「내각 155 이상이면 곡선 생략은 반영하지 말자.
|
||||
# 사용자가 계획 평면 노선을 수정할 때 문제가 될 것 같아.」 곡선이 있다 없다 하면 잡는
|
||||
# 손잡이도 있다 없다 하고, 조금 폈다는 이유로 곡선이 사라지면 되돌릴 길이 없다. 그래서
|
||||
# **꺾이는 자리에는 늘 곡선을 둔다.** 값은 법정 근거를 잃지 않게 남겨만 둔다.
|
||||
STRAIGHT_INNER_ANGLE_DEG = 155.0
|
||||
|
||||
# 한 곡선으로 **묶을지** 볼 때 쓰는 문턱(도) — 위 155° 와 쓰임이 다르다.
|
||||
@@ -442,7 +447,7 @@ def _line_intersection(
|
||||
|
||||
|
||||
def _curve_runs(
|
||||
cleaned: list[tuple[float, float]], straight_inner_angle_deg: float
|
||||
cleaned: list[tuple[float, float]],
|
||||
) -> list[tuple[int, int]]:
|
||||
"""**한 곡선으로 묶을 꺾임점 구간**을 고른다 — `[(첫 꺾임점, 끝 꺾임점)]`.
|
||||
|
||||
@@ -475,20 +480,8 @@ def _curve_runs(
|
||||
):
|
||||
break
|
||||
end = following
|
||||
# 별표2 의 155° 는 **묶은 뒤 전체 교각**에 적용한다 — 앞뒤 직선이 이루는 내각이
|
||||
# 그만큼 펴져 있으면 곡선을 두지 않는다.
|
||||
apex = (
|
||||
cleaned[index]
|
||||
if index == end
|
||||
else _line_intersection(
|
||||
cleaned[index - 1], cleaned[index], cleaned[end], cleaned[end + 1]
|
||||
)
|
||||
)
|
||||
total_inner = (
|
||||
180.0 if apex is None else _inner_angle_deg(cleaned[index - 1], apex, cleaned[end + 1])
|
||||
)
|
||||
if total_inner < straight_inner_angle_deg:
|
||||
runs.append((index, end))
|
||||
# 곡선을 생략하지 않는다(2026-09-07 사용자 지시) — 꺾이는 자리는 전부 곡선이다.
|
||||
runs.append((index, end))
|
||||
index = end + 1
|
||||
return runs
|
||||
|
||||
@@ -547,7 +540,6 @@ def _split_wide_runs(
|
||||
deduped: list[tuple[float, float]],
|
||||
node_indices: list[int],
|
||||
min_radius_m: float,
|
||||
straight_inner_angle_deg: float = STRAIGHT_INNER_ANGLE_DEG,
|
||||
) -> list[tuple[int, int]]:
|
||||
"""묶는 것이 **손해면 도로 쪼갠다** — 한 곡선으로 펴서 원본에서 더 멀어지면 안 묶는다.
|
||||
|
||||
@@ -580,15 +572,7 @@ def _split_wide_runs(
|
||||
if merged_mean <= apart_mean and merged_max <= max(apart_max, MERGE_MAX_GAP_M):
|
||||
result.append((first, last))
|
||||
else:
|
||||
# 쪼갤 때 **별표2 의 155° 를 다시 본다** — 묶여 있을 때는 전체 교각이 기준을
|
||||
# 넘었더라도, 낱개로 떼면 펴진 자리(내각 155° 이상)가 나온다. 다시 안 보면
|
||||
# 그런 자리에도 곡선이 생긴다(2026-09-07 실측: 내각 159° 에 R 12m 원호).
|
||||
result.extend(
|
||||
(index, index)
|
||||
for index in range(first, last + 1)
|
||||
if _inner_angle_deg(cleaned[index - 1], cleaned[index], cleaned[index + 1])
|
||||
< straight_inner_angle_deg
|
||||
)
|
||||
result.extend((index, index) for index in range(first, last + 1))
|
||||
return result
|
||||
|
||||
|
||||
@@ -597,7 +581,6 @@ def build_planned_polyline(
|
||||
*,
|
||||
min_radius_m: float,
|
||||
hairpin_min_radius_m: float = 10.0,
|
||||
straight_inner_angle_deg: float = STRAIGHT_INNER_ANGLE_DEG,
|
||||
simplify: bool = True,
|
||||
) -> PlannedPolyline:
|
||||
"""점 묶음을 계획노선 폴리라인으로 바꾼다.
|
||||
@@ -629,11 +612,9 @@ def build_planned_polyline(
|
||||
cleaned[index - 1], cleaned[index], cleaned[index + 1]
|
||||
)
|
||||
|
||||
runs = _curve_runs(cleaned, straight_inner_angle_deg)
|
||||
runs = _curve_runs(cleaned)
|
||||
if node_indices is not None:
|
||||
runs = _split_wide_runs(
|
||||
runs, cleaned, deduped, node_indices, min_radius_m, straight_inner_angle_deg
|
||||
)
|
||||
runs = _split_wide_runs(runs, cleaned, deduped, node_indices, min_radius_m)
|
||||
vertices: list[tuple[float, float]] = [cleaned[0]]
|
||||
curves: list[RouteCurve] = []
|
||||
cursor = 0 # 아직 선에 안 실은 첫 꺾임점
|
||||
|
||||
Reference in New Issue
Block a user