Files
Aislo/resources/tester/test_169_drawing_area_guide.py
T
eomsangdonandClaude Opus 5.5 ab92de3787 feat(b07): 횡단 장 = 작도 영역 열 × 행 표 격자선 · 장 안 블록 테두리 끔 · 칸 넘침 알림 (169-2)
- 장마다 칸 격자선(세로 열 + 1 · 가로 행 + 1 · 도각 층 · 인쇄 · DXF)
- 단면은 블록 틀 가운데 = 칸 가운데 그대로 · 장 안 블록 테두리 안 그림(측점 한 장은 그대로)
- 칸보다 큰 단면 = overflow_cells → CAD 가이드 붉은 틀 + 화면 알림(축척 그대로)
- 배치 판 4 — 옛 판 확정 장은 「옛 배치」 안내

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
2026-10-10 08:35:39 +09:00

131 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""169 도면 그림 영역 지정 · 횡단 격자 표.
못박는 것
- 169-1 그림칸 = 작도 영역 그대로(여백 없음) · 도각 편집이 영역을 싣고 · 저장(어긋나면 옛 값).
- 169-1 도면 좌표 가이드 영역 = 도각 bbox ↔ 양식 bbox 로 옮긴 영역 · 도각 아닌 것(블록 틀)이면 None.
- 169-2 횡단 장 = 칸 격자선(열 + 1 · 행 + 1 · 칸 경계) · 장 안 블록 테두리 없음 · 큰 단면 → 넘친 칸.
- 169-4 구조물 도각(외곽 좌하단 0,0) 응답에 영역.
"""
import json
from pathlib import Path
from uuid import uuid5
import pytest
from B07_DesignDetail import B07_DesignDetail_Engine_Template as engine
from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
_POLY_NS,
FRAME_LAYER_ID,
build_cross_drawing,
)
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import build_cross_sheet, plan_cross_sheets
from B07_DesignDetail.B07_DesignDetail_Router import _drawing_guide
from M02_MasterTemplete.M02_MasterTemplete_Router_Drawing import structure_frame
ROOT = Path(__file__).resolve().parents[2]
TABLE = {"ground": 100.0, "planned": 100.0}
def _source(chainage: float, slope: float, half: int = 10) -> dict:
return {
"chainage_m": chainage,
"samples": [
{"valid": True, "offset_m": float(x), "elevation_m": 100.0 + slope * x}
for x in range(-half, half + 1)
],
}
def _sheet(sources: list[dict], layout: dict | None = None) -> tuple[dict, dict]:
sheet = plan_cross_sheets([s["chainage_m"] for s in sources], layout)[0]
sections = [
{"chainage": s["chainage_m"], "source": s, "quantity_table": TABLE, "title": ""}
for s in sources
]
return sheet, build_cross_sheet(sheet, sections)
def test_usable_area_is_drawing_area_without_margin():
engine.use_project_templates(None)
x0, y0, x1, y1 = engine.drawing_area()
assert engine.usable_area() == (x1 - x0, y1 - y0) == (770.0, 520.0)
def test_frame_edit_loads_and_saves_area(tmp_path):
engine.use_project_templates(None)
assert engine.frame_template_document()["drawing_area"] == [42.0, 47.0, 812.0, 567.0]
path = engine.save_project_template(tmp_path, [], area=[10, 20, 410, 320])
assert json.loads(path.read_text(encoding="utf-8"))["drawing_area"] == [10, 20, 410, 320]
# 어긋난 값(뒤집힘 · 글자) → 고치기 전 값을 이어 받음
for bad in ([410, 20, 10, 320], ["a", 0, 1, 1], None):
path = engine.save_project_template(tmp_path, [], area=bad)
assert json.loads(path.read_text(encoding="utf-8"))["drawing_area"] == [10, 20, 410, 320]
# 라우터가 요청 도면의 영역을 넘김
router = (ROOT / "B07_DesignDetail/B07_DesignDetail_Router_Frame.py").read_text(
encoding="utf-8"
)
assert 'request.drawing.get("drawing_area")' in router and "area=area" in router
def test_cross_sheet_grid_lines_no_block_border_and_guide_area():
engine.use_project_templates(None)
w, h = engine.usable_area()
sources = [_source(i * 20.0, 0.05, 6) for i in range(3)]
sheet, drawing = _sheet(sources, {"default": [3, 2]})
by_id = {e["id"]: e for e in drawing["entities"]}
def line(name: str) -> tuple[dict, dict]:
entity = by_id[str(uuid5(_POLY_NS, f"{sheet['id']}:{FRAME_LAYER_ID}:grid-{name}"))]
assert entity["layerId"] == FRAME_LAYER_ID
shape = entity["children"][0]["shapeData"]
return shape["startPoint"], shape["endPoint"]
# 격자선 = 세로 열 + 1 · 가로 행 + 1 · 칸 경계 자리 · 그림칸 끝에서 끝까지
for i in range(3 + 1):
a, b = line(f"v{i}")
assert a["x"] == b["x"] == pytest.approx(-w / 2 + w * i / 3)
assert (a["y"], b["y"]) == pytest.approx((-h / 2, h / 2))
for j in range(2 + 1):
a, b = line(f"h{j}")
assert a["y"] == b["y"] == pytest.approx(-h / 2 + h * j / 2)
assert (a["x"], b["x"]) == pytest.approx((-w / 2, w / 2))
assert str(uuid5(_POLY_NS, f"{sheet['id']}:{FRAME_LAYER_ID}:grid-v4")) not in by_id
# 장 안 블록 테두리 없음(측점 한 장 테두리와 같은 id 자리)
for source in sources:
seed = f"{sheet['id']}:{source['chainage_m']}:{FRAME_LAYER_ID}"
assert str(uuid5(_POLY_NS, seed)) not in by_id
# 가이드 영역(도면 좌표) = 그림칸 그대로 · 넘침 없음
guide = _drawing_guide(drawing)
assert guide["area"] == pytest.approx([-w / 2, -h / 2, w / 2, h / 2], abs=1e-3)
assert guide["marks"] == [] and drawing["overflow_cells"] == []
def test_big_section_marks_its_cell():
engine.use_project_templates(None)
w, h = engine.usable_area()
# 4 × 4 칸(192.5 × 130 mm)에 60 m 폭 단면(600 mm) — 첫 칸(좌하단)만 넘침
sources = [_source(0.0, 0.05, 30), _source(20.0, 0.05, 6)]
_sheet_, drawing = _sheet(sources, {"default": [4, 4]})
cw, ch = w / 4, h / 4
assert drawing["overflow_cells"] == [pytest.approx([-w / 2, -h / 2, -w / 2 + cw, -h / 2 + ch])]
assert _drawing_guide(drawing)["marks"] == drawing["overflow_cells"]
def test_station_drawing_border_is_not_a_frame():
# 측점 한 장 — 도각 층에 블록 테두리만 있음 → 가이드 없음(틀린 선 대신)
drawing = build_cross_drawing(_source(0.0, 0.1), "cross_00000m", None, None, TABLE, "")
assert any(e.get("layerId") == FRAME_LAYER_ID for e in drawing["entities"])
assert _drawing_guide(drawing) is None
def test_structure_frame_area_in_frame_coords():
engine.use_project_templates(None)
frame = structure_frame()
min_x, min_y, *_ = engine.entities_bbox(engine.template_entities())
x0, y0, x1, y1 = engine.drawing_area()
assert frame["area"] == pytest.approx(
[x0 - min_x, y0 - min_y, x1 - min_x, y1 - min_y], abs=1e-3
)