Files
Aislo/resources/tester/test_259_detail_region.py
T
eomsangdonandClaude Opus 5.5 eaf9337638 fix(b06): 상세 고름 — 공용 팬 누름마다 moved 풂 · 암 경계선 나눔 · 고름 (259-1)
- 가운데 단추 팬 뒤 왼쪽 누름 click 삼킴 없앰(거리이정표 다이어그램 같은 줄)
- 암 경계선 조각 고름 · 서버 pick_lines rock 짝 · 스키마 · 타입 rock

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
2026-10-11 14:02:18 +09:00

116 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
"""PLAN 259 — B06 [상세] 영역 · 길이 · 표 강조.
못박는 것
- 259-1 공용 팬(`A00_Common/b_svg_zoom_pan.ts`) — 가운데 단추 팬 뒤 왼쪽 누름 click 이 안 삼켜짐 ·
거리이정표 꼴(빈 곳 왼쪽 끌기 팬)은 끌기 끝 click 만 막음.
- 259-1 암 경계선 — 설계선과 만나는 점에서 나뉨 · 고름 값 · 저장 꼴 · 서버 `pick_lines` 거울 ·
암 프리셋 아니면 다시 고름.
./venv/Scripts/python.exe -m pytest resources/tester/test_259_detail_region.py -q
"""
import json
import os
import subprocess
from pathlib import Path
import pytest
from B06_Section.B06_Section_Schema import CrossSectionPatch
from B07_DesignDetail.B07_DesignDetail_Engine_Cross_Table_Edit import cell_value, pick_lines
ROOT = Path(__file__).resolve().parents[2]
HERE = Path(__file__).resolve().parent
LINE = [(-6.0, 104.0), (-2.0, 98.0), (2.0, 98.0), (6.0, 104.0)]
DESIGN = {
"design_elevation_m": 98.0,
"geometry_preset": "rock",
"rock_boundary_offset_m": -1.0,
"road_edges": {
"left": {"offset_m": 2.0, "elevation_m": 98.0},
"right": {"offset_m": -2.0, "elevation_m": 98.0},
},
"design_line": [{"offset_m": x, "elevation_m": y} for x, y in LINE],
}
SAMPLES = [{"offset_m": x, "elevation_m": 100.0, "valid": True} for x in (-10, -5, 0, 5, 10)]
AXES = {
"widthPx": 600,
"heightPx": 300,
"pixelsPerMeter": 10,
"maxOffset": 14,
"displayMax": 110,
"elevationMid": 100,
"exaggeration": 2,
}
ROCK_X = 2 + 4 / 6 # 경사(4 : 6)가 암 경계선 99 m 와 만나는 offset
pytestmark = pytest.mark.skipif(
not (ROOT / "config" / "node_modules").is_dir(), reason="프론트엔드 의존성 미설치"
)
@pytest.fixture(scope="module")
def out() -> dict:
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HERE / "helper_259_detail_region.cjs")],
input=json.dumps({"design": DESIGN, "samples": SAMPLES, "axes": AXES}),
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
cwd=os.fspath(ROOT),
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
# ── 259-1 공용 팬 ────────────────────────────────────────────────────────
def test_가운데_단추_팬_뒤_왼쪽_누름_통과(out):
assert out["panMiddle"] == {"firstClickStopped": False, "secondClickStopped": False}
def test_거리이정표_왼쪽_끌기_팬은_끌기_click_만_막음(out):
assert out["panLeft"] == {"afterDragStopped": True, "nextClickStopped": False}
# ── 259-1 암 경계선 나눔 · 고름 ───────────────────────────────────────────
def test_암_경계선이_설계선과_만나는_점에서_나뉨(out):
rock = [p for p in out["pieces"] if p["line"] == "rock"]
assert len(rock) == 3
ends = sorted(round(p["points"][0][0], 4) for p in rock)
assert ends == pytest.approx([-10.0, -ROCK_X, ROCK_X], abs=1e-3)
# 설계 경사도 암 경계선에서 잘림(경사 끝 · 암 교점 · 원지반 교점)
design_ends = {
round(q[0], 3)
for p in out["pieces"]
if p["line"] == "design"
for q in (p["points"][0], p["points"][-1])
}
assert round(ROCK_X, 3) in design_ends
def test_암_경계선_고름_값_저장_꼴(out):
length = 2 * ROCK_X
assert out["rockLength"] == pytest.approx(length, abs=1e-3)
assert out["rockLabel"] == f"암 경계선 길이 {length:.2f}m\n수평 {length:.2f}m · 높이 0.00m"
source = out["rockSource"]
assert source["src"] == "length" and source["pieces"][0]["line"] == "rock"
patch = CrossSectionPatch(chainage_m=40.0, detail_table={"cells": {"fence": source}})
assert patch.model_dump()["detail_table"]["cells"]["fence"]["pieces"][0]["line"] == "rock"
def test_암_경계선_서버_거울(out):
number, _text, again = cell_value(out["rockSource"], DESIGN, SAMPLES)
assert not again and number == pytest.approx(out["rockLocal"], abs=1e-6)
assert pick_lines(DESIGN, SAMPLES)["rock"] == [[(x, 99.0) for x in (-10, -5, 0, 5, 10)]]
# 토사 프리셋이면 암 경계선 없음 → 다시 고름
soil = {**DESIGN, "geometry_preset": "soil"}
assert pick_lines(soil, SAMPLES)["rock"] == []
assert cell_value(out["rockSource"], soil, SAMPLES) == (None, None, True)