- 실측 = IP 글 #4d7dff 와 교각선 · 원 #4d7dff 이미 같음 → 정함대로 중심선 #ff4d4d - IP 기호 · R 글 색 그대로 · test_141 색 단정 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
184 lines
6.8 KiB
Python
184 lines
6.8 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"]
|
|
|
|
|
|
def test_blocked_spots_push_farther_with_leader() -> None:
|
|
"""141-2 — 후보가 다 막히면 기호에서 2 · 3 배 먼 자리(지시선) · 작은 축척에 몰린 장."""
|
|
anchor = (0.0, 0.0)
|
|
spot = [{"x": 0.0, "y": -4.0}]
|
|
placed = place_labels(
|
|
[_label("ip", "IP1", spot, anchor), _label("radius", "R=12", spot, anchor)], []
|
|
)
|
|
assert placed[0]["spot"] == spot[0]
|
|
assert placed[1]["spot"] == {"x": 0.0, "y": -8.0, "far": True}
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanLabels import label_entities
|
|
|
|
entities = label_entities("d", placed)
|
|
assert [e["type"] for e in entities] == ["Text", "Text", "PolyLine"]
|
|
|
|
|
|
def test_ip_text_takes_centerline_color() -> None:
|
|
"""153-2 — IP 글 · 지시선 = 노선 중심선 색 · 교각선 · 원 · R 글은 조각 색 그대로."""
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanKinds import _COLORS, _piece_entities
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanLabels import label_entities
|
|
|
|
item = {"name": "IP1", "apex": [100.0, 100.0], "start": [90.0, 100.0], "end": [100.0, 110.0]}
|
|
pieces = {
|
|
"ip": {"items": [item]},
|
|
"radius": {"items": [{"label": "R=12", "middle": [100.0, 98.0], "dir": [0.0, -1.0]}]},
|
|
}
|
|
drawing = build_plan_kind_drawing("plan_x", "시험", (0.0, 0.0, 300.0, 200.0), pieces)
|
|
texts = {e["shapeData"]["label"]: e for e in _texts(drawing)}
|
|
ip_text = texts["IP1"]
|
|
assert ip_text["lineColor"] == _COLORS["centerline"]
|
|
assert ip_text["shapeData"]["options"]["textColor"] == _COLORS["centerline"]
|
|
assert texts["R=12"]["shapeData"]["options"]["textColor"] == _COLORS["radius"]
|
|
marks = [
|
|
e for e in drawing["entities"] if e["layerId"] == "b07-plan-ip" and e["type"] == "PolyLine"
|
|
]
|
|
assert len(marks) == 2 # 교각선 · 원
|
|
assert {e["lineColor"] for e in marks} == {_COLORS["ip"]}
|
|
|
|
labels: list = []
|
|
_piece_entities("d", "ip", {"items": [item]}, lambda p: (p[0], p[1]), labels=labels)
|
|
far = [{**labels[0], "spot": {"x": 0.0, "y": 0.0, "far": True}, "rect": (0, 0, 1, 1)}]
|
|
leader = label_entities("d", far)[1]
|
|
assert leader["lineColor"] == _COLORS["centerline"]
|