Files
Aislo/resources/tester/test_b07_cross_sheet_pad.py
T
eomsangdonandClaude Opus 5.5 67bba96227 fix(B07): 횡단면도 박스를 단면마다 자기 그림 + 1 mm 로 — 칸 통일 없앰
- 장 배치: 칸을 그 장 가장 큰 블록으로 통일하던 것을 없애고 블록을 자기 크기로 열마다 쌓음(좌하단부터 아래→위, 차면 오른쪽 열)
- 그리는 가로 범위를 선이 있는 데까지로 — 원지반 자료가 짧으면 빈 여유가 박스를 밀던 것
- 블록 크기에 암 경계선 포함(실제 그림과 같은 규칙)
- 옛 배치로 확정된 장은 저장본을 그대로 보이되 [수정] 안내 알림
- 검증_sub4: 박스 ↔ 그림 66개 모두 1.0 mm · 같은 조건 27장 → 20장

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013rJwJMVL4EE31y77TB11AP
2026-10-06 23:11:14 +09:00

152 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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