# -*- 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