"""B07 횡단면도 — 단면 블록 테두리 ↔ 안쪽 그림 간격 1 mm (59-1).""" import pytest from B07_DesignDetail.B07_DesignDetail_Engine_Cad import ( CROSS_BORDER_PAD_MM, FRAME_LAYER_ID, build_cross_drawing, ) from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import section_block_size from B07_DesignDetail.B07_DesignDetail_Engine_Template import entities_bbox _SOURCE = { "chainage_m": 20.0, "samples": [ {"valid": True, "offset_m": float(x), "elevation_m": 100.0 + 0.3 * x} for x in range(-10, 11) ], } def test_frame_hugs_section_by_one_mm() -> None: drawing = build_cross_drawing(_SOURCE, "cross_00020m", None, None, None, "") lines = [e for e in drawing["entities"] if e.get("layerId") != FRAME_LAYER_ID] frame = [e for e in drawing["entities"] if e.get("layerId") == FRAME_LAYER_ID] min_x, min_y, max_x, max_y = entities_bbox(lines) f_min_x, f_min_y, f_max_x, f_max_y = entities_bbox(frame) assert CROSS_BORDER_PAD_MM == 1.0 assert f_max_y - max_y == pytest.approx(1.0) assert min_y - f_min_y == pytest.approx(1.0) # 표 없는 블록 크기 = 테두리 크기 width, height = section_block_size(_SOURCE, None, with_table=False) assert height == pytest.approx(f_max_y - f_min_y) assert width == pytest.approx(f_max_x - f_min_x) # ── 68-1 장 배치: 단면마다 자기 박스(칸 통일 없음) ────────────────────────────── from B07_DesignDetail.B07_DesignDetail_Engine_Cad import CROSS_SECTION_MARGIN_M # noqa: E402 from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import ( # noqa: E402 build_cross_sheet, plan_cross_sheets, ) 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 _box(entity: dict) -> tuple[float, float, float, float] | None: if entity.get("type") == "Table": shape = entity["shapeData"] origin = shape["origin"] return ( origin["x"], origin["y"] - sum(shape["rowHeights"]), origin["x"] + sum(shape["columnWidths"]), origin["y"], ) return entities_bbox([entity]) _TABLE = {"ground": 100.0, "planned": 100.0} def test_each_block_hugs_its_own_drawing_by_one_mm() -> None: """크기 다른 단면 셋을 한 장에 — 박스마다 자기 그림(표 포함)에서 사방 1.0 mm.""" sources = [_source(0.0, 0.05), _source(20.0, 0.6, 15), _source(40.0, 0.2, 6)] blocks = [(s["chainage_m"], *section_block_size(s, None, design=None)) for s in sources] sheets = plan_cross_sheets(blocks) assert len(sheets) == 1 sections = [ {"chainage": s["chainage_m"], "source": s, "quantity_table": _TABLE, "title": ""} for s in sources ] drawing = build_cross_sheet(sheets[0], sections) inner = [_box(e) for e in drawing["entities"] if e.get("layerId") != FRAME_LAYER_ID] frames = [p["frame"] for p in drawing["cross_placements"]] sizes = {(round(f[2] - f[0], 1), round(f[3] - f[1], 1)) for f in frames} assert len(sizes) == 3 # 칸 통일 없음 — 박스 크기가 단면마다 다르다 for left, bottom, right, top in frames: mine = [ b for b in inner if b and b[0] >= left - 1e-6 and b[2] <= right + 1e-6 and b[1] >= bottom - 1e-6 and b[3] <= top + 1e-6 ] assert min(b[0] for b in mine) - left == pytest.approx(1.0) assert right - max(b[2] for b in mine) == pytest.approx(1.0) assert min(b[1] for b in mine) - bottom == pytest.approx(1.0) assert top - max(b[3] for b in mine) == pytest.approx(1.0) def test_small_blocks_are_not_widened_by_a_big_one() -> None: """큰 단면 하나 + 작은 단면 여럿 — 칸을 큰 블록으로 통일하던 때보다 한 장에 더 담긴다.""" blocks = [(0.0, 300.0, 300.0)] + [(float(i), 110.0, 60.0) for i in range(1, 30)] sheets = plan_cross_sheets(blocks) # 옛 배치(칸 300×300 → A1 739×499 에 2×1)는 첫 장에 2개였다. assert len(sheets[0]["chainages"]) > 2 assert sum(len(s["chainages"]) for s in sheets) == 30 def test_window_stops_where_lines_end() -> None: """원지반 자료가 여유(1.5 m)보다 짧으면 범위를 선 끝에서 멈춘다 — 빈 여유가 박스를 밀지 않음.""" source = _source(0.0, 0.1, 6) design_line = [ {"offset_m": -6.0, "elevation_m": 99.4}, {"offset_m": -5.5, "elevation_m": 98.0}, {"offset_m": 5.5, "elevation_m": 98.0}, {"offset_m": 6.0, "elevation_m": 100.6}, ] drawing = build_cross_drawing(source, "cross_00000m", design_line, None, None, "") placement = drawing["cross_placements"][0] assert placement["x0"] == pytest.approx(-6.0) assert placement["x1"] == pytest.approx(6.0) assert CROSS_SECTION_MARGIN_M == 1.5 def test_old_confirmed_cross_sheet_is_flagged(tmp_path) -> None: """68-1 전에 확정한 횡단 장은 저장본을 그대로 보이되 「옛 배치」 표시를 단다.""" import json from B07_DesignDetail.B07_DesignDetail_Engine_Cad import DRAWING_FORMAT from B07_DesignDetail.B07_DesignDetail_Router_Support import ( CROSS_SHEET_LAYOUT, _read_drawing, ) stage = tmp_path / "B07_DesignDetail" (stage / "drawings").mkdir(parents=True) saved = {"format": DRAWING_FORMAT, "entities": [], "layers": []} (stage / "drawings" / "cross_s00000m.json").write_text(json.dumps(saved), encoding="utf-8") entry = {"kind": "cross", "label": "횡단면도 1장", "confirmed": True} manifest = {"drawings": {"cross_s00000m": entry}} (stage / "manifest.json").write_text(json.dumps(manifest), encoding="utf-8") _k, _l, drawing, confirmed, _t = _read_drawing(tmp_path, tmp_path / "x.json", "cross_s00000m") assert confirmed and drawing.get("stale_layout") is True entry["layout"] = CROSS_SHEET_LAYOUT (stage / "manifest.json").write_text(json.dumps(manifest), encoding="utf-8") _k, _l, drawing, confirmed, _t = _read_drawing(tmp_path, tmp_path / "x.json", "cross_s00000m") assert confirmed and "stale_layout" not in drawing