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