# -*- 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 )