- 쌓기 · 최소 장수 함수 지움 · grid_slots(n, 열, 행) 칸 가운데(좌하단 → 위 → 오른쪽) · 1/100 그대로
- 저장 B07_DesignDetail/cross_layout.json {default [4,4], sheets {장 번호: [열, 행]}} · GET · PUT cross-layout
- 배치 바꾸면 담긴 측점이 바뀐 확정 장 풂 · 그 측점 설계 잠정 · CROSS_SHEET_LAYOUT = 3
- 장 나눔이 설계 · 덧그림과 무관 — 목록 · 확정 · 수정에서 덧그림 재기 빠짐
- 좌측 정보 칸 「배치 열 × 행 [적용] · [모든 장 기본]」 → 다시 세워 같은 장 번호 엶
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
148 lines
6.0 KiB
Python
148 lines
6.0 KiB
Python
"""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)]
|
|
sheets = plan_cross_sheets([s["chainage_m"] for s in sources])
|
|
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_sheets_take_grid_count_not_block_size() -> None:
|
|
"""140-3 장 나눔 = 칸 수(기본 4 × 4) — 단면 크기와 무관 · 측점 30개면 16 + 14."""
|
|
sheets = plan_cross_sheets([float(i) for i in range(30)])
|
|
assert [len(s["chainages"]) for s in sheets] == [16, 14]
|
|
|
|
|
|
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
|