- 계획고 · 지반고 · 측점 행 = 이웃과 겹치는 칸만 세로쓰기 · 두께 = 이웃 사이 틈 − 1(6 ~ 16 px) · 겹침 없는 칸 그대로 · 지우지 않음 - 곡선 L · R 행도 같은 판정(crowdedThickness) — 1.6 m 이웃에서 16 px 칸끼리 겹치던 것 고침 - logic/B06_Section_Label_Tiers crowdedThickness 새로 · 시험 test_407_4_label_tiers 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
"""PLAN 407-4 — 종단 측점 · 구조물 이름표 비켜 그리기(`logic/B06_Section_Label_Tiers.ts`) ·
|
|
407-5 — B05 종단 아래 표 겹친 칸 세우기(`crowdedThickness` · 두께 = 이웃 사이 틈 − 1).
|
|
|
|
가까운 측점(1.6 m 등)끼리 이름이 겹치면 위 단 · 안 겹치면 제자리(0) · 이름은 지우지 않음 ·
|
|
단 수 위 끝(`MAX_LABEL_TIER`) 넘으면 마지막 단 · 글 폭 짐작(한글 = 글자 크기).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
TS = ROOT / "B06_Section" / "logic" / "B06_Section_Label_Tiers.ts"
|
|
TYPESCRIPT = ROOT / "config" / "node_modules" / "typescript"
|
|
|
|
SCRIPT = r"""
|
|
const ts = require(process.argv[1]);
|
|
const fs = require("fs");
|
|
const js = ts.transpileModule(fs.readFileSync(process.argv[2], "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", js)(box.exports, box);
|
|
const m = box.exports;
|
|
const cases = JSON.parse(process.argv[3]);
|
|
process.stdout.write(JSON.stringify({
|
|
max: m.MAX_LABEL_TIER,
|
|
tiers: cases.map((items) => m.labelTiers(items)),
|
|
widths: ["19+18 (MC)", "20+0", "배수관"].map((t) => m.labelWidthPx(t, 10)),
|
|
thick: [
|
|
m.crowdedThickness([0, 50, 100], 40, 16),
|
|
m.crowdedThickness([100, 108, 200], 40, 16),
|
|
m.crowdedThickness([100, 130, 200], 40, 16),
|
|
m.crowdedThickness([100, 104, null, 106], 40, 16),
|
|
m.crowdedThickness([100, null, 103], 40, 16),
|
|
],
|
|
}));
|
|
"""
|
|
|
|
W = 40.0 # 이름표 폭(px)
|
|
CASES = [
|
|
[{"x": 100, "width": W}, {"x": 200, "width": W}, {"x": 300, "width": W}], # 안 겹침
|
|
[{"x": 100, "width": W}, {"x": 108, "width": 24}], # 1.6 m 이웃 — 겹침
|
|
[{"x": 108, "width": 24}, {"x": 100, "width": W}], # 차례 뒤바뀜(x 로 셈)
|
|
[{"x": 100 + i * 2, "width": W} for i in range(6)], # 여섯 겹 — 위 끝
|
|
[{"x": 100, "width": W}, {"x": 110, "width": W}, {"x": 150, "width": W}], # 셋째는 제자리
|
|
]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def r() -> dict:
|
|
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
|
["node", "-e", SCRIPT, str(TYPESCRIPT), str(TS), json.dumps(CASES)],
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_안_겹치면_제자리(r) -> None:
|
|
assert r["tiers"][0] == [0, 0, 0]
|
|
|
|
|
|
def test_겹치면_위_단(r) -> None:
|
|
assert r["tiers"][1] == [0, 1]
|
|
assert r["tiers"][2] == [1, 0] # 왼쪽 것이 제자리
|
|
|
|
|
|
def test_위_끝_넘으면_마지막_단(r) -> None:
|
|
assert r["tiers"][3] == [0, 1, 2, 3, 3, 3] # 이름은 남음(지우지 않음)
|
|
|
|
|
|
def test_빈_단은_다시_씀(r) -> None:
|
|
assert r["tiers"][4] == [0, 1, 0]
|
|
|
|
|
|
def test_글_폭(r) -> None:
|
|
mc, plain, korean = r["widths"]
|
|
assert mc == pytest.approx(60.0) and plain == pytest.approx(24.0)
|
|
assert korean == pytest.approx(30.0)
|
|
|
|
|
|
def test_표_칸_세우기(r) -> None:
|
|
no, near, wide, empty, floor = r["thick"]
|
|
assert no == [None, None, None] # 안 겹침 = 그대로
|
|
assert near == [7, 7, None] # 1.6 m 이웃(8 px) = 둘 다 세움 · 두께 7
|
|
assert wide == [16, 16, None] # 틈 넓으면 위 끝 16
|
|
assert empty == [6, 6, None, 6] # 빈 칸(null) 건너 이웃 · 아래 끝 6
|
|
assert floor == [6, None, 6]
|