- 새 _Corridor_Loft_Toe.ts(비탈 끝 거리 고르기 · 측점 고정 · 포락선) · _Corridor_Loft_Grid.ts(Taubin) - _Corridor_Loft.ts 행마다 점 둘 부채꼴 → 격자 · 설계 점 0.3 m 솎기 · 둘레는 지형에 닿은 비탈 끝만 - 사면 실오라기 67 → 1.5 % · 음영 단차 p90 5.6 → 0.02° · 측점 오차 그대로(226 · d22) - test_115_10 새로 · test_115_8 직선 · 꼬임 단언을 격자 · 포락선에 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
68 lines
2.4 KiB
Python
68 lines
2.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""PLAN 115-10 — B05 3D 제안 ③ 사면 모양 평활화 검사.
|
|
|
|
도우미(helper_115_8_corridor_loft.cjs)를 함께 쓴다. 사면 격자(실오라기 없음) · 비탈 끝 선
|
|
꼬임 0(포락선) · Taubin 평활화(고정점 그대로 · 줄어들지 않음) · 측점 단면 = B06 · 이음 틈 0.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def results():
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_115_8_corridor_loft.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=240,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_slope_grid_no_slivers(results):
|
|
# 직선 · 소단 — 사면 삼각형 가로세로비 10 넘는 것 0(행마다 점 둘 실오라기 부채꼴 없음)
|
|
for name in ("straight", "berm"):
|
|
aspect = results[name]["aspect"]
|
|
assert aspect["count"] > 1000 and aspect["over"] == 0, (name, aspect)
|
|
|
|
|
|
def test_curves_few_slivers(results):
|
|
# 곡선 안쪽(행이 모이는 자리) · 두 비탈이 만나는 골 둘레만 조금 — 1.5 % 밑
|
|
for name in ("curve", "bend", "hairpin"):
|
|
aspect = results[name]["aspect"]
|
|
assert aspect["over"] <= 0.015 * aspect["count"], (name, aspect)
|
|
|
|
|
|
def test_toe_line_no_self_crossing(results):
|
|
for name in ("curve", "bend", "hairpin"):
|
|
assert results[name]["toeCross"] == 0, name
|
|
# 급곡선(R 10 m) — 엇갈린 사면 선은 만나는 선(골)에서 멈춤
|
|
assert results["hairpin"]["stats"]["bowtie"] > 0
|
|
|
|
|
|
def test_no_gap_no_failed_constraint(results):
|
|
for name in ("straight", "flip", "curve", "bend", "hairpin", "berm"):
|
|
assert results[name]["gaps"] == 0, name
|
|
assert results[name]["stats"]["failed"] == 0, name
|
|
|
|
|
|
def test_fixed_edges_and_station_section(results):
|
|
r = results["straight"]
|
|
assert r["drapeErr"] < 1e-4 # 비탈 끝 = 지형 위(고정)
|
|
assert r["sectionErr"] < 1e-4 and r["offsetErr"] < 1e-4 # 측점 단면 · 비탈 끝 = B06
|
|
assert results["berm"]["sectionErr"] < 1e-4
|
|
|
|
|
|
def test_taubin_keeps_fixed_and_volume(results):
|
|
r = results["taubin"]
|
|
assert r["fixedMoved"] == 0 # 노견 끝 · 비탈 끝 · 꺾임 그대로
|
|
assert r["roughAfter"] < 0.5 * r["roughBefore"] # 잡음 반 넘게 줄어듦
|
|
assert r["meanShift"] < 0.01 # 평균 높이 안 꺼짐(Taubin)
|