Files
Aislo/resources/tester/test_141_b07_plan_labels.py
T
eomsangdonandClaude Opus 5.5 d26b991fb3 feat(B07): 평면도 글 자리 잡기 — 우선순위 · 후보 자리 · 지시선 · 비탈 기하 분리(141-1)
- 새 Engine_Cad_PlanLabels — 시종점 > 측점 NO > IP > R > 배수 > 대피소 차례로 후보 중 첫 빈 자리 · 장애물 IP 표 · 필지 상자 · 먼 자리엔 지시선
- 조각 글은 후보째 모아 build_plan_kind_drawing 이 자리 정한 뒤 그림 · R 실거리 4 m 대신 종이 mm 후보
- 비탈 · 노선 따라가기 기하 = 새 Engine_Cad_PlanSlope(PlanKinds 700줄 넘어 분리 · import 길 그대로)
- sub6 초안 반영 · 검증_sub8 실측 겹친 글 쌍 지형 12 → 0 · 새 test_141

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
2026-10-09 15:06:52 +09:00

140 lines
4.6 KiB
Python

# -*- coding: utf-8 -*-
"""141-1 B07 평면도 글자 겹침 피하기.
못박는 것
- 우선순위 = 시종점 > 측점 NO > IP > R > 배수 > 대피소 — 앞 글이 첫 후보(옛 자리)를 가짐.
- 후보 중 첫 빈 자리 · 모두 막히면 첫 후보 그대로(글은 남음).
- 장애물(IP 표 · 필지 상자) 비켜 감.
- 가까운 IP · R · 배수 둘 · NO.0 + 시점 한 장 → 글 사각 겹침 0 · 글 모두 남음.
- 멀리 놓인 글(후보 far)엔 지시선.
"""
from itertools import combinations
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanKinds import build_plan_kind_drawing
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanLabels import (
overlaps,
place_labels,
text_rect,
)
def _label(piece: str, label: str, spots: list[dict], anchor=None) -> dict:
return {
"piece": piece,
"seed": f"s:{piece}:{label}",
"label": label,
"size": 2.5,
"layer": "l",
"color": "#fff",
"anchor": anchor,
"candidates": spots,
}
def test_priority_keeps_first_spot_and_next_moves() -> None:
spot = [{"x": 0.0, "y": 0.0}, {"x": 0.0, "y": 10.0}]
placed = place_labels([_label("refuge", "대피소", spot), _label("endpoints", "시점", spot)], [])
by = {item["piece"]: item["spot"] for item in placed}
assert by["endpoints"] == spot[0] # 시종점이 먼저 — 옛 자리
assert by["refuge"] == spot[1]
def test_all_blocked_falls_back_to_first() -> None:
spot = [{"x": 0.0, "y": 0.0}]
placed = place_labels([_label("ip", "IP1", spot), _label("radius", "R=12", spot)], [])
assert [item["spot"] for item in placed] == [spot[0], spot[0]] # 글은 남음
def test_obstacle_is_avoided() -> None:
spots = [{"x": 0.0, "y": 0.0}, {"x": 30.0, "y": 0.0}]
placed = place_labels([_label("ip", "IP1", spots)], [(-5.0, -5.0, 5.0, 5.0)])
assert placed[0]["spot"] == spots[1]
def _texts(drawing: dict) -> list[dict]:
return [
e
for e in drawing["entities"]
if e["type"] == "Text"
and e["layerId"].startswith("b07-plan-")
and e["layerId"] != "b07-plan-title"
]
def _rect(entity: dict) -> tuple:
shape = entity["shapeData"]
opts = shape["options"]
direction = (opts["textDirection"]["x"], opts["textDirection"]["y"])
return text_rect(
shape["label"],
shape["basePoint"]["x"],
shape["basePoint"]["y"],
opts["fontSize"],
opts["textAlign"],
direction,
)
def test_crowded_sheet_has_no_overlapping_labels() -> None:
box = (0.0, 0.0, 300.0, 200.0)
pieces = {
"ip": {
"items": [
{
"name": "IP1",
"apex": [100.0, 100.0],
"start": [90.0, 100.0],
"end": [100.0, 110.0],
},
{
"name": "IP2",
"apex": [103.0, 101.0],
"start": [95.0, 101.0],
"end": [103.0, 111.0],
},
]
},
"radius": {
"items": [
{"label": "R=12", "middle": [100.0, 98.0], "dir": [0.0, -1.0]},
{"label": "R=15", "middle": [103.0, 99.0], "dir": [0.0, -1.0]},
]
},
"drainage": {
"items": [
{"x": 101.0, "y": 96.0, "label": "D800 L=8.0"},
{"x": 102.0, "y": 95.0, "label": "D600 L=6.0"},
]
},
"station": {
"items": [
{"x": 50.0, "y": 50.0, "nx": 0.0, "ny": 1.0, "label": "NO.0", "major": True},
]
},
"endpoints": {
"items": [{"label": "시점 NO.0", "x": 50.0, "y": 50.0, "nx": 0.0, "ny": 1.0}]
},
}
drawing = build_plan_kind_drawing("plan_x", "시험", box, pieces)
texts = _texts(drawing)
labels = sorted(e["shapeData"]["label"] for e in texts)
assert labels == sorted(
["IP1", "IP2", "R=12", "R=15", "D800 L=8.0", "D600 L=6.0", "NO.0", "시점 NO.0"]
)
pairs = [
(a["shapeData"]["label"], b["shapeData"]["label"])
for a, b in combinations(texts, 2)
if overlaps(_rect(a), _rect(b))
]
assert pairs == []
def test_far_spot_draws_leader() -> None:
near = [{"x": 0.0, "y": 0.0}, {"x": 40.0, "y": 0.0, "far": True}]
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanLabels import label_entities
placed = place_labels([_label("ip", "IP1", near, (0.0, 0.0))], [(-3.0, -3.0, 3.0, 3.0)])
entities = label_entities("plan_x", placed)
assert [e["type"] for e in entities] == ["Text", "PolyLine"]