- 표 아래선 = 칸 아래 + 5 mm · 같은 행 표 윗선 · 아랫선 한 높이 · 표 가운데 x = 칸 가운데 - [상세] 글 표 바로 위 · 그림 아래 끝 = 글(없으면 표) 위 8 mm · 도로 중심(offset 0) = 칸 가운데 - 넘침 = 블록 틀이 칸 위 · 옆을 넘을 때 붉은 칸 틀(축척 그대로) - 배치 판 5 — 옛 판 확정 장 안내 글 새 배치로 - test_140 칸 가운데 판정을 새 배치로 · test_174 새 시험 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
122 lines
4.9 KiB
Python
122 lines
4.9 KiB
Python
# -*- 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
|