# -*- 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)