From 0ce6b43bdc218b5c5fb6f0d5be38698d382746e2 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 3 Sep 2026 19:02:03 +0900 Subject: [PATCH] =?UTF-8?q?fix(B05):=20=EC=A0=84=EC=B2=B4=20=EC=B8=A1?= =?UTF-8?q?=EC=A0=90=20=EA=B3=84=ED=9A=8D=EC=84=A0=EC=97=90=20=EC=A2=85?= =?UTF-8?q?=EB=8B=A8=EA=B3=A1=EC=84=A0=20=EB=B3=B5=EC=9B=90=20=E2=80=94=20?= =?UTF-8?q?=ED=98=B8=EA=B0=80=20=EC=A7=80=EB=B0=98=EA=B3=A0=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=EA=B3=BC=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=BC=AD?= =?UTF-8?q?=EC=A7=93=EC=A0=90=20=EB=B0=98=EB=B3=B5=20=EB=B3=B4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `3651ad98` 의 `only_explicit_curves=True` 로 전체 측점 폴리라인에서 자동 종단곡선이 전부 꺼져, B05 종단 그래프의 계획선이 직선만으로 그려졌음. - `design_ground_following_profile()` — 변화점마다 기본 L(15m) 종단곡선을 다시 삽입. 대칭 종단곡선은 꼭짓점을 지나지 않으므로(중앙종거 |A|·L/8), 호와 측점 세로선의 교점이 지반고가 되도록 꼭짓점 표고를 최대 12회 반복 보정 — `design_pipe_anchored_profile` 과 같은 방식. 결과: 호의 중심이 측점 세로선 위, 좌우 직선과 접선, 계획고 = 지반고. - `rebuild_alignment_profile()` — `GROUND_POLYLINE_BASIS` 곡선 생략 예외 제거. 저장된 `base_pvi` 가 보정된 꼭짓점이라 편집 델타를 지우면 초기선으로 그대로 복귀함. - 프론트는 payload `only_explicit_curves` 를 그대로 따르므로 코드 변경 없음. - 호 크기 기준은 현행 유지(2026-09-03 사용자 결정) — L 고정·R 은 결과값, 법정 최소반경 미만은 경고만. 검증: `tmp/tests/test_b05_ground_profile_curves.py` 4건 + 전체 173건 통과. route 127 실데이터 오프라인 산출에서 호 126개(저장분 0개), 측점 계획고−지반고 최대 0.063mm. Co-Authored-By: Claude Opus 5 (1M context) --- .../B05_Profile_Engine_Grade_Profile.py | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/B05_Profile/B05_Profile_Engine_Grade_Profile.py b/B05_Profile/B05_Profile_Engine_Grade_Profile.py index c38a6a8f..fc7e51db 100644 --- a/B05_Profile/B05_Profile_Engine_Grade_Profile.py +++ b/B05_Profile/B05_Profile_Engine_Grade_Profile.py @@ -153,11 +153,13 @@ def design_ground_following_profile( ) -> tuple[dict[str, Any], dict[str, Any]]: """전체 측점을 변화점으로 삼고 계획고를 원지반고에 맞추는 1차 계획선. - 규칙(2026-09-02 사용자 확정): - - **모든 측점이 변화점**이고 그 표고는 그 자리 지반고 그대로다. 절·성토가 거의 0이다. - - **종단곡선(라운드)은 자동으로 넣지 않는다.** 사용자가 [직선화]로 만든 직선을 - 틸팅할 때 그 변화점에만 R이 지정되고, 그때 곡선이 생긴다 - (`build_alignment(only_explicit_curves=True)`). + 규칙(2026-09-02 사용자 확정 + 2026-09-03 종단곡선 복원): + - **모든 측점이 변화점**이고 그 자리 계획고는 지반고 그대로다. 절·성토가 거의 0이다. + - **변화점마다 종단곡선을 넣는다.** 직선과 직선 사이에는 반드시 호가 있고, 호는 + 변화점 대칭이라 **호의 중심이 측점 세로선 위**에 놓이며 좌우 직선과 접선을 이룬다. + - 대칭 종단곡선은 꼭짓점을 지나지 않으므로 **호와 측점 세로선의 교점이 지반고**가 + 되도록 꼭짓점 표고를 중앙종거만큼 밀어내며 반복 보정한다 + (`design_pipe_anchored_profile` 과 같은 방식). - 기울기는 지형 그대로라 법정 상한을 넘길 수 있다 — 막지 않고 경고만 남긴다 (기존 정책과 같다). @@ -204,6 +206,19 @@ def design_ground_following_profile( if note: warnings.append(note) + # 대칭 종단곡선은 꼭짓점을 지나지 않는다(중앙종거 |A|·L/8) — 보정 없이 곡선을 넣으면 + # 계획고가 지반고에서 뜬다. 호가 측점 세로선과 만나는 점이 지반고가 되도록 꼭짓점을 + # 밀어내며, 표고가 움직이면 대수차도 변하므로 수렴할 때까지 되풀이한다. + target = base_z.copy() + for _ in range(12): + curves, _curve_warnings = build_curves(base_s, base_z, policy) + error = target - evaluate(base_s, base_z, curves, base_s) + error[0] = 0.0 + error[-1] = 0.0 + if float(np.max(np.abs(error))) < 1e-4: + break + base_z = base_z + error + alignment = build_alignment( base_s=base_s, base_z=base_z, @@ -212,7 +227,6 @@ def design_ground_following_profile( stations=stations, policy=policy, edits=dict(edits or {}), - only_explicit_curves=True, ) warnings.extend(alignment["warnings"]) balanced = bool(alignment["balance"]["within_tolerance"]) @@ -449,10 +463,6 @@ def rebuild_alignment_profile( policy = AlignmentPolicy.from_dict(stored.get("policy") or {}) previous = (longitudinal.get("design_profiles") or [{}])[0] - # 전체 측점 폴리라인은 곡선을 자동으로 넣지 않는다 — 재구성도 같은 규칙이어야 - # 편집 델타를 지웠을 때 초기 폴리라인으로 정확히 돌아간다(2026-09-02). - only_explicit = str(previous.get("basis") or "") == GROUND_POLYLINE_BASIS - alignment = build_alignment( base_s=base_s, base_z=base_z, @@ -461,7 +471,6 @@ def rebuild_alignment_profile( stations=list(longitudinal.get("stations") or []), policy=policy, edits=edits, - only_explicit_curves=only_explicit, ) criteria = previous.get("criteria") or {} options = GradeDesignOptions(