# -*- coding: utf-8 -*- """174-1 B07 횡단 장 — 칸 아래 가운데 표 먼저 · 그 위 글 · 그림. 못박는 것 - 표 아래선 = 칸 아래 + 여백 · 같은 행 칸끼리 표 윗선 · 아랫선 한 높이(그림 · 글 크기와 무관). - 표 가운데 x = 칸 가운데 = 도로 중심(offset 0) — 좌우 비대칭 단면도. - [상세] 글은 표 바로 위 · 그림 아래 끝 = 글(없으면 표) 위 8 mm. - 그림이 칸 위 · 옆을 넘으면 overflow_cells(축척 그대로) · 들어가면 없음. - 배치 판 5(옛 판 확정 장 = 옛 배치 안내). """ import pytest from B07_DesignDetail.B07_DesignDetail_Engine_Cad import GROUND_LAYER_ID from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import ( CELL_TABLE_PAD_MM, build_cross_sheet, plan_cross_sheets, ) from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Table import ( cross_note_height, cross_note_lines, cross_table_height, ) from B07_DesignDetail.B07_DesignDetail_Engine_Template import ( entities_bbox, usable_area, use_project_templates, ) from B07_DesignDetail.B07_DesignDetail_Router_Support import CROSS_SHEET_LAYOUT NOTE = {"structure_note": "L형 측구\n집수정 보강"} def _source(chainage: float, slope: float, lo: int, hi: int) -> dict: return { "chainage_m": chainage, "samples": [ {"valid": True, "offset_m": float(x), "elevation_m": 100.0 + slope * x} for x in range(lo, hi + 1) ], } def _sheet(sources: list[dict], designs: list[dict | None], grid: list[int]) -> tuple: use_project_templates(None) sheet = plan_cross_sheets([s["chainage_m"] for s in sources], {"default": grid})[0] sections = [ { "chainage": s["chainage_m"], "source": s, "design": design, "quantity_table": {"ground": 1.0, "planned": 0.5}, "title": "", } for s, design in zip(sources, designs, strict=True) ] return sheet, build_cross_sheet(sheet, sections) def _tables(drawing: dict) -> list[tuple[float, float, float]]: """표마다 (가운데 x, 아랫선 y, 윗선 y) — 배치 순서.""" out = [] for entity in drawing["entities"]: if entity["type"] != "Table": continue shape = entity["shapeData"] left, top = shape["origin"]["x"], shape["origin"]["y"] out.append((left + sum(shape["columnWidths"]) / 2, top - sum(shape["rowHeights"]), top)) return out def test_같은_행_표_한_높이_그림_중심_칸_가운데() -> None: # 2 × 2 — 좌하단 · 좌상단 · 우하단 · 우상단 · 높이 · 좌우 범위 · 글 유무가 다 다름 sources = [ _source(0.0, 0.05, -6, 6), _source(20.0, 0.3, -3, 9), _source(40.0, 0.05, -8, 4), _source(60.0, 0.6, -5, 5), ] designs = [None, NOTE, NOTE, None] sheet, drawing = _sheet(sources, designs, [2, 2]) _w, h = usable_area() cell_h = h / 2 tables = _tables(drawing) assert len(tables) == 4 for (cx, bottom, top), slot in zip(tables, sheet["slots"], strict=True): assert cx == pytest.approx(slot[0]) # 표 가운데 x = 칸 가운데 assert bottom == pytest.approx(slot[1] - cell_h / 2 + CELL_TABLE_PAD_MM) assert top - bottom == pytest.approx(cross_table_height()) # 같은 행(아래 행 = 0 · 2번 · 위 행 = 1 · 3번) 표 윗선 · 아랫선 한 높이 for a, b in ((0, 2), (1, 3)): assert tables[a][1:] == pytest.approx(tables[b][1:]) # 같은 열 표 가운데 x 한 줄 assert tables[0][0] == pytest.approx(tables[1][0]) # 도로 중심(offset 0) = 칸 가운데 · 그림(원지반) 아래 끝 = 글(없으면 표) 위 8 mm grounds = [ entities_bbox([e]) for e in drawing["entities"] if e.get("layerId") == GROUND_LAYER_ID ] for placement, slot, table, design, ground in zip( drawing["cross_placements"], sheet["slots"], tables, designs, grounds, strict=True ): assert placement["ox"] == pytest.approx(slot[0]) note_h = cross_note_height(cross_note_lines(design)) assert ground[1] == pytest.approx(table[2] + note_h + 8.0) assert drawing["overflow_cells"] == [] def test_넘침_위_옆() -> None: w, h = usable_area() # 4 × 4 칸(192.5 × 130 mm) — 0: 높이 넘침(경사 1 · 높이 120 mm + 표) · 1: 오른쪽만 긴 # 단면(-2 ~ 16 m · 폭 180 < 칸 폭이지만 도로 중심 고정이라 오른쪽 넘침) · 2: 들어감 sources = [_source(0.0, 1.0, -6, 6), _source(20.0, 0.05, -2, 16), _source(40.0, 0.05, -5, 5)] _sheet_, drawing = _sheet(sources, [None, None, None], [4, 4]) cw, ch = w / 4, h / 4 cells = [[-w / 2, -h / 2 + ch * j, -w / 2 + cw, -h / 2 + ch * (j + 1)] for j in range(2)] assert drawing["overflow_cells"] == [pytest.approx(c) for c in cells] def test_배치_판_5() -> None: assert CROSS_SHEET_LAYOUT == 5