Files
Aislo/resources/tester/test_212_b07_cross_station_layers.py
T
eomsangdonandClaude Opus 5.5 8230788e96 refactor(b07): 횡단 구조물 얹기 몸통 = Cross_Overlay.placeStructureEntities · Node 가짜 DOM = Node_Dom 파일 (302-2 앞)
- 화면 appendStructureEntities = 정본 상세 읽기 + placeStructureEntities 부름 · 동작 그대로
- 가짜 문서에 addEventListener · removeEventListener 빈 함수 — 화면 모듈이 불러올 때 거는 문서 이벤트로 덧그림 범위 Node 번들이 시작부터 멈추던 흠 (10-04 무렵부터 서버 장 배치가 덧그림 범위 없이 섬)
- 시험 212 = 옮긴 자리에서 글 찾음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
2026-10-13 08:01:33 +09:00

187 lines
7.8 KiB
Python

# -*- coding: utf-8 -*-
"""212-1 · 212-2 B07 횡단 장 — 원지반 고르기 · 측점별 도면층.
못박는 것
- 212-1 옛 확정 장(원지반 층 잠금째 저장)도 열 때 원지반 잠금 풂 · 측점 층 없으면 stale_layers.
- 212-2 장의 측점마다 층 하나(`b08-station-{측점}` · 이름 「횡단 {제목}」) = 원지반 · 계획선 ·
암 그림(자식 선까지) · 표 · 글은 수량표 층 · 격자선 · 도각은 도각 층 · 종류 층 없음.
- 개체 id 는 그대로(층만 바뀜) · placement 에 layer_id · design_ids(화면 덧그림 갈아 끼우기).
- DXF 층 이름 = 측점 층 id 그대로(금지 문자 없음).
- 화면 덧그림도 측점 층 · design_ids 로 서버 설계선 걷음(소스 확인 · typecheck 는 따로).
"""
import json
from pathlib import Path
from uuid import uuid5
import ezdxf
from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
_POLY_NS,
CROSS_TABLE_LAYER_ID,
DESIGN_COLOR,
DESIGN_LAYER_ID,
DRAWING_FORMAT,
FRAME_LAYER_ID,
GROUND_COLOR,
GROUND_LAYER_ID,
ROCK_LAYER_ID,
STRUCTURE_LAYER_ID,
)
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
STATION_LAYER_PREFIX,
build_cross_sheet,
plan_cross_sheets,
)
from B07_DesignDetail.B07_DesignDetail_Engine_Frame_Export import _layer_name, drawing_to_dxf
from B07_DesignDetail.B07_DesignDetail_Engine_Template import use_project_templates
from B07_DesignDetail.B07_DesignDetail_Router_Support import CROSS_SHEET_LAYOUT, _read_drawing
ROOT = Path(__file__).resolve().parents[2]
KIND_LAYERS = {GROUND_LAYER_ID, DESIGN_LAYER_ID, STRUCTURE_LAYER_ID, ROCK_LAYER_ID}
def _source(chainage: float) -> dict:
return {
"chainage_m": chainage,
"samples": [
{"valid": True, "offset_m": float(x), "elevation_m": 100.0 + 0.1 * x}
for x in range(-5, 6)
],
}
def _sheet() -> tuple[dict, dict]:
use_project_templates(None)
chainages = [0.0, 20.0, 40.0, 60.0]
sheet = plan_cross_sheets(chainages, {"default": [2, 2]})[0]
sections = [
{
"chainage": c,
"source": _source(c),
# 암 지반 = 암 경계선도 측점 층으로
"design": {"rock_boundary_offset_m": -1.0} if c == 20.0 else None,
"design_line": [{"offset_m": x, "elevation_m": 100.0} for x in (-3.0, 0.0, 3.0)],
"quantity_table": {"ground": 1.0, "planned": 0.5},
"title": f"No.{int(c // 20)}",
}
for c in chainages
]
return sheet, build_cross_sheet(sheet, sections)
def _flat(entities: list[dict]) -> list[dict]:
out = []
for entity in entities:
out.append(entity)
out.extend(_flat(entity.get("children") or []))
return out
def test_측점마다_층_하나_이름_횡단_No():
_sheet_, drawing = _sheet()
layers = drawing["layers"]
ids = [layer["id"] for layer in layers]
assert ids[:4] == [f"{STATION_LAYER_PREFIX}{c}" for c in (0.0, 20.0, 40.0, 60.0)]
assert [layer["name"] for layer in layers[:4]] == [
"횡단 No.0",
"횡단 No.1",
"횡단 No.2",
"횡단 No.3",
]
assert ids[4:] == [CROSS_TABLE_LAYER_ID, FRAME_LAYER_ID]
assert not KIND_LAYERS & set(ids) # 종류 층 없음 — 빈 층이 안 남음
assert all(layer["isVisible"] and not layer["isLocked"] for layer in layers[:4])
def test_그림은_측점_층_표_글은_수량표_층_격자는_도각():
_sheet_, drawing = _sheet()
flat = _flat(drawing["entities"])
assert not any(e["layerId"] in KIND_LAYERS for e in flat) # 자식 선까지
by_layer: dict[str, list[dict]] = {}
for entity in drawing["entities"]:
by_layer.setdefault(entity["layerId"], []).append(entity)
for chainage in (0.0, 20.0, 40.0, 60.0):
members = by_layer[f"{STATION_LAYER_PREFIX}{chainage}"]
colors = {e["lineColor"] for e in members}
assert GROUND_COLOR in colors and DESIGN_COLOR in colors
assert all(e["type"] == "PolyLine" for e in members)
assert len({e["groupId"] for e in members}) == 1 # 180-1 groupId 그대로
# 암 지반 측점만 점선 암 경계선(종류 = 선 꼴)
rock = [e for e in by_layer[f"{STATION_LAYER_PREFIX}20.0"] if e.get("lineDash")]
assert len(rock) == 1
assert not any(e.get("lineDash") for e in by_layer[f"{STATION_LAYER_PREFIX}0.0"])
assert {e["type"] for e in by_layer[CROSS_TABLE_LAYER_ID]} <= {"Table", "Text"}
assert all("groupId" not in e for e in by_layer[FRAME_LAYER_ID])
def test_id_그대로_placement_layer_id_design_ids():
sheet, drawing = _sheet()
by_id = {e["id"]: e for e in drawing["entities"]}
for placement in drawing["cross_placements"]:
chainage = placement["chainage_m"]
layer_id = f"{STATION_LAYER_PREFIX}{chainage}"
assert placement["layer_id"] == layer_id
seed = f"{sheet['id']}:{chainage}"
# 개체 id 는 종류 층 씨앗 그대로 — 저장본 · 덧그림 짝이 안 흔들림
ground = by_id[str(uuid5(_POLY_NS, f"{seed}:{GROUND_LAYER_ID}"))]
assert ground["layerId"] == layer_id and ground["lineColor"] == GROUND_COLOR
design_ids = placement["design_ids"]
assert design_ids == [str(uuid5(_POLY_NS, f"{seed}:{DESIGN_LAYER_ID}"))]
assert all(by_id[i]["lineColor"] == DESIGN_COLOR for i in design_ids)
def test_DXF_층_이름_측점_층_id(tmp_path: Path):
_sheet_, drawing = _sheet()
for layer in drawing["layers"]:
assert _layer_name(layer["id"]) == layer["id"]
data, _skipped = drawing_to_dxf(drawing)
(tmp_path / "sheet.dxf").write_bytes(data)
names = {layer.dxf.name for layer in ezdxf.readfile(tmp_path / "sheet.dxf").layers}
assert {f"{STATION_LAYER_PREFIX}{c}" for c in (0.0, 20.0, 40.0, 60.0)} <= names
assert not KIND_LAYERS & names
def test_옛_확정_장_원지반_잠금_풂_측점_층_안내(tmp_path: Path):
stage = tmp_path / "B07_DesignDetail"
(stage / "drawings").mkdir(parents=True)
layers = [
{"id": GROUND_LAYER_ID, "name": "원지반", "isVisible": True, "isLocked": True},
{"id": FRAME_LAYER_ID, "name": "도각", "isVisible": True, "isLocked": True},
]
saved = {"format": DRAWING_FORMAT, "entities": [], "layers": layers}
path = stage / "drawings" / "cross_s00000m.json"
path.write_text(json.dumps(saved), encoding="utf-8")
entry = {"kind": "cross", "label": "1장", "confirmed": True, "layout": CROSS_SHEET_LAYOUT}
(stage / "manifest.json").write_text(
json.dumps({"drawings": {"cross_s00000m": entry}}), encoding="utf-8"
)
def read() -> dict:
_k, _l, drawing, confirmed, _t = _read_drawing(
tmp_path, tmp_path / "x.json", "cross_s00000m"
)
assert confirmed
return drawing
drawing = read()
locked = {layer["id"]: layer["isLocked"] for layer in drawing["layers"]}
assert locked == {GROUND_LAYER_ID: False, FRAME_LAYER_ID: True} # 도각은 그대로 잠금
assert drawing.get("stale_layers") is True
# 측점 층으로 확정한 장은 안내 없음
saved["layers"] = [{"id": f"{STATION_LAYER_PREFIX}0", "name": "횡단 No.0"}, layers[1]]
path.write_text(json.dumps(saved), encoding="utf-8")
assert "stale_layers" not in read()
def test_화면_덧그림_측점_층_design_ids():
# 얹는 몸통 = Cross_Overlay.placeStructureEntities(302-2 · 화면 · 인쇄 Node 한 벌)
struct = (ROOT / "B07_DesignDetail/B07_DesignDetail_Cross_Overlay.ts").read_text(
encoding="utf-8"
)
assert "layer_id?: string;" in struct and "design_ids?: string[];" in struct
assert "moveToLayer(entity, placement.layer_id)" in struct
assert "!designIds.has(entity.id as string)" in struct
page = (ROOT / "B07_DesignDetail/B07_DesignDetail_UI_Page.ts").read_text(encoding="utf-8")
assert "response.drawing.stale_layers" in page