- 새 B06_Section_UI_Cross_Design_Pick.ts — 조각 합침 · 벽 · 본체 밖 조각 · 투명 판정 선 · 치수 · crossZoneAt(139-6 용) · 페이지 한 칸 고름 - 폴리곤 자르기 = A00_Common/b_polygon_clip.ts 공용(B07 Cross_Overlay 에서 옮김 · 바깥 조각 갈래) - 카드 배선: 선 고르면 벽 · 본체 · 면적 풂 + 카드 고름 · 면적 고름도 본체 · 선 풂 - 시험 test_137_design_pick.py + helper_137_design_pick.cjs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018jonfdxn1Xit9bdkNJpE4G
111 lines
4.8 KiB
Python
111 lines
4.8 KiB
Python
"""PLAN 137-2 · 137-3 — B06 보라 선 고름: 직선 조각 · 가림 · 치수 · 구역 · 판정 선 · 페이지 한 칸.
|
||
|
||
짝: `B06_Section/B06_Section_UI_Cross_Design_Pick.ts` · `A00_Common/b_polygon_clip.ts`(B07 에서 옮김) ·
|
||
`B06_Section_UI_Cross_View.ts`(배선 · 하나만). 실제 TS 를 `helper_137_design_pick.cjs` 가 Node 로 돌린다.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
import subprocess
|
||
|
||
import pytest
|
||
|
||
HERE = os.path.dirname(__file__)
|
||
ROOT = os.path.join(HERE, "..", "..")
|
||
|
||
pytestmark = pytest.mark.skipif(
|
||
not os.path.isdir(os.path.join(ROOT, "config", "node_modules")),
|
||
reason="프론트엔드 의존성 미설치",
|
||
)
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def out() -> dict:
|
||
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||
["node", os.path.join(HERE, "helper_137_design_pick.cjs")],
|
||
capture_output=True,
|
||
text=True,
|
||
encoding="utf-8",
|
||
timeout=60,
|
||
)
|
||
assert proc.returncode == 0, proc.stderr
|
||
return json.loads(proc.stdout)
|
||
|
||
|
||
def _src(rel: str) -> str:
|
||
with open(os.path.join(ROOT, rel), encoding="utf-8") as f:
|
||
return f.read()
|
||
|
||
|
||
def test_같은_방향_토막은_직선_조각_하나(out) -> None:
|
||
"""0.5 m 토막 25개 → 성토 사면 · 노면 둘(가운데 꺾임) · 측구 · 절토 사면 = 다섯 · 거꾸로 그린 토막도 합침."""
|
||
assert out["merge"]["segments"] == 25
|
||
assert out["merge"]["pieces"] == [[-6.5, -2.5], [-2.5, 0], [0, 2.5], [2.5, 3], [3, 6]]
|
||
assert out["mergeStructure"] == 2 # 구조물 선은 설계선과 안 합침
|
||
|
||
|
||
def test_벽에_가린_부분은_빼고_보이는_조각만(out) -> None:
|
||
assert out["occlude"]["pieces"] == [[3, 4], [4.5, 6]]
|
||
assert out["occlude"]["covered"] == 0
|
||
|
||
|
||
def test_치수_사면길이_수평_높이_구배(out) -> None:
|
||
fill = out["measure"]["fill"]
|
||
assert (fill["horizontalM"], fill["heightM"], fill["grade"]) == (3, 2, "1:1.50")
|
||
assert abs(fill["lengthM"] - 13**0.5) < 1e-9
|
||
assert out["measure"]["road"]["grade"] == "2.0%" # 노면 = %
|
||
assert out["measure"]["flatSlope"] == "0.0%"
|
||
assert out["label"]["fill"] == "사면길이 3.61m · 수평 3.00m · 높이 2.00m · 1:1.50"
|
||
assert out["label"]["road"] == "길이 2.50m · 수평 2.50m · 높이 0.05m · 2.0%"
|
||
|
||
|
||
def test_구역_도로_절토_성토(out) -> None:
|
||
zone = out["zone"]
|
||
assert zone["road"] == {"zone": "road", "side": "left"}
|
||
assert zone["roadEdge"] == "road"
|
||
assert zone["ditch"] == {"zone": "cut", "side": "left"} # 측구 = 절토
|
||
assert zone["cutSlope"] == {"zone": "cut", "side": "left"}
|
||
assert zone["fillSlope"] == {"zone": "fill", "side": "right"}
|
||
assert zone["structure"] == "fill" # 구조물 트림 선 = 성토
|
||
assert zone["rightCutDitch"] == "cut"
|
||
assert zone["bothFill"] == "fill"
|
||
assert zone["pieceZones"] == ["fill", "road", "road", "cut", "cut"]
|
||
|
||
|
||
def test_실제_배관_측점_조각과_판정_선(out) -> None:
|
||
real = out["real"]
|
||
assert real["pieces"] < real["designLines"] # 토막이 조각으로 합쳐짐
|
||
assert real["structurePieces"] > 0 # 구조물 트림 선도 고름 대상
|
||
assert real["hits"] == real["pieces"]
|
||
assert real["wallCount"] == 2 and real["insideWall"] == 0 # 벽 안 조각 없음
|
||
assert real["hitsBelowStructure"] is True # 구조물 판정면이 위
|
||
assert real["picked"] == [0] and real["stopped"] is True # 카드 고름으로 안 번짐
|
||
assert real["activeCount"] == 1 and real["activeIndex"] == 1
|
||
assert real["labelOn"]["hidden"] is False and real["labelOn"]["text"].startswith("사면길이 ")
|
||
assert real["labelOff"] == {"hidden": True, "text": ""}
|
||
assert set(real["zones"]) <= {"road", "cut", "fill"}
|
||
|
||
|
||
def test_페이지_한_칸_고름(out) -> None:
|
||
assert out["slot"] == {"a1": 2, "a2": None, "b": 1, "cleared": None}
|
||
|
||
|
||
def test_카드_배선_하나만() -> None:
|
||
"""137-3 — 선을 고르면 벽 · 본체 · 면적을 풀고 카드도 고름 · 다른 고름은 선을 풂."""
|
||
view = _src("B06_Section/B06_Section_UI_Cross_View.ts")
|
||
assert "const pickLine = (index: number): void => {" in view
|
||
assert "if (!isSelected) onSelect(section.station_id);" in view
|
||
assert view.count("dropLine();") >= 4 # 본체 · 벽 · 카드 풂 · 면적
|
||
assert "setLineActive(pickedLineAt(section.station_id));" in view # 다시 그려도 되살림
|
||
assert "zoomBar.prepend(linePick.label);" in view # 치수 = [+ − ⤢] 왼쪽
|
||
css = _src("B06_Section/B06_Section_UI_Style_Cross_Areas.css")
|
||
assert ".b06-chart__design-hit.is-active {" in css
|
||
|
||
|
||
def test_폴리곤_자르기는_공용_한_벌() -> None:
|
||
b07 = _src("B07_DesignDetail/B07_DesignDetail_Cross_Overlay.ts")
|
||
assert "function clipSegment(" not in b07 and "function pointInPolygon(" not in b07
|
||
assert 'from "../A00_Common/b_polygon_clip"' in b07
|