# -*- 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"]