- 까닭: 새로 만든 장은 서버 · CAD 걸름 모두 원지반이 잡힘 — 안 잡힌 것은 180-1 앞에 원지반 층 잠금째 저장된 확정 장 또는 반영 전 서버 · 페이지 메모리의 옛 도면
- 확정 장을 열 때 원지반 층 잠금 풂 · 측점 층 없는 확정 장은 stale_layers 안내([수정] 때 새 꼴)
- 장의 측점마다 층 하나(b08-station-{측점} · 「횡단 No.3」) = 원지반 · 계획선 · 구조물 · 암 그림(자식 선까지) · 종류는 색 · 선 꼴 · 표 · 글은 수량표 층 · 종류 층 지움
- 개체 id · groupId 그대로 · placement 에 layer_id · design_ids — 화면 덧그림도 측점 층 · 서버 설계선은 id 로 걷음
- DXF 층 이름 = 측점 층 id
- 새 시험 test_212 · 174 · 180 · 180_2 원지반 찾기를 색으로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
124 lines
4.9 KiB
Python
124 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_COLOR
|
||
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("type") == "PolyLine" and e.get("lineColor") == GROUND_COLOR
|
||
]
|
||
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
|