- 횡단 장 칸 격자선(도각 층 인쇄 개체) 지움 — 칸은 화면 안내선 겹판(guide.cells · 단면마다 점선) · 안내선 숨기기에 함께 꺼짐 · 넘친 칸 붉은 틀은 그대로 - 옛 확정 · 저장본 장은 열 때 칸선만 걷고 칸 안내선은 지금 배치로(refresh_saved_sheet) - CAD 처음 맞춤 · 전체 맞춤 = 내용 + 작도 영역(가이드) — 표준 횡단도가 내용에만 확대돼 도면 한 장 안 자리가 안 보이던 흠 - 낡은 시험 고침: test_169 칸선 단언 → 칸선 없음 + 칸 안내선 · test_212_3 「남는 검은 선 = 인쇄 칸선 지우지 않음」(212-3 결정) → 요구 343-4 로 칸선 지움 · guide-area 시험 칸 그리기 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
147 lines
6.4 KiB
Python
147 lines
6.4 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""169 도면 그림 영역 지정 · 횡단 격자 표.
|
||
|
||
못박는 것
|
||
- 169-1 그림칸 = 작도 영역 그대로(여백 없음) · 도각 편집이 영역을 싣고 · 저장(어긋나면 옛 값).
|
||
- 169-1 도면 좌표 가이드 영역 = 도각 bbox ↔ 양식 bbox 로 옮긴 영역 · 도각 아닌 것(블록 틀)이면 None.
|
||
- 169-2 · 526-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,
|
||
refresh_saved_sheet,
|
||
)
|
||
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_no_grid_lines_no_block_border_and_guide_cells():
|
||
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"]}
|
||
|
||
# 인쇄 칸선 없음(526-1 · 옛 169-2 `:grid-v0` …) · 장 안 블록 테두리 없음
|
||
for name in ("v0", "v1", "h0", "h1"):
|
||
assert str(uuid5(_POLY_NS, f"{sheet['id']}:{FRAME_LAYER_ID}:grid-{name}")) not in by_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
|
||
# 칸 = 화면 안내선 — 단면마다 하나 · 좌하단 → 위 → 오른쪽 열
|
||
cw, ch = w / 3, h / 2
|
||
expected = [
|
||
[-w / 2, -h / 2, -w / 2 + cw, -h / 2 + ch],
|
||
[-w / 2, -h / 2 + ch, -w / 2 + cw, h / 2],
|
||
[-w / 2 + cw, -h / 2, -w / 2 + 2 * cw, -h / 2 + ch],
|
||
]
|
||
assert drawing["guide_cells"] == [pytest.approx(cell) for cell in expected]
|
||
# 가이드 영역(도면 좌표) = 그림칸 그대로 · 넘침 없음 · 칸 = 단면 수
|
||
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"] == []
|
||
assert guide["cells"] == drawing["guide_cells"]
|
||
|
||
|
||
def test_saved_sheet_strips_grid_lines_and_gets_cells():
|
||
# 옛 확정 · 저장본(칸선 품음) — 칸선만 걷고 칸 안내선은 지금 배치로(526-1)
|
||
engine.use_project_templates(None)
|
||
sources = [_source(i * 20.0, 0.05, 6) for i in range(2)]
|
||
sheet, drawing = _sheet(sources, {"default": [2, 2]})
|
||
grid = [
|
||
{"id": str(uuid5(_POLY_NS, f"{sheet['id']}:{FRAME_LAYER_ID}:grid-{name}"))}
|
||
for name in ("v0", "v2", "h1")
|
||
]
|
||
saved = {"entities": drawing["entities"] + grid}
|
||
refresh_saved_sheet(sheet["id"], saved, lambda: [sheet])
|
||
assert saved["entities"] == drawing["entities"]
|
||
assert saved["guide_cells"] == drawing["guide_cells"] and len(saved["guide_cells"]) == 2
|
||
refresh_saved_sheet("cross_s99999m", saved, lambda: [sheet]) # 지금 배치에 없는 장 = 칸 없음
|
||
assert saved["guide_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
|
||
)
|