auto: 2026-07-26 20:05 (ESD_LAPTOP)
This commit is contained in:
@@ -45,7 +45,8 @@ _POLY_NS = UUID("9dd28aab-cee5-4df6-b8ae-b9167fbde9a8")
|
||||
# v4: 종단 그래프 축·회색 측점 세로선·기준선(datum) + 테이블 눈금·세로쓰기·구배 원 표기.
|
||||
# v5: 횡단 콘텐츠 bbox 중심 정렬(경사 드리프트 제거) + 외곽 테두리 제거.
|
||||
# v6: 외곽 테두리 복구 (콘텐츠 중심 정렬 유지, 노선 공통 크기 사각형).
|
||||
DRAWING_FORMAT = 6
|
||||
# v7: 종단도 A1 도각 템플릿 프레임 병합 (b07-frame 잠금 레이어).
|
||||
DRAWING_FORMAT = 7
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -23,6 +23,7 @@ from B07_wf4_DesignDetail.B07_wf4_DesignDetail_Engine_Cad import (
|
||||
DESIGN_COLOR,
|
||||
DESIGN_LAYER_ID,
|
||||
DRAWING_FORMAT,
|
||||
FRAME_LAYER_ID,
|
||||
GROUND_COLOR,
|
||||
GROUND_LAYER_ID,
|
||||
LONG_SPLIT_STATION_COUNT,
|
||||
@@ -43,6 +44,10 @@ from B07_wf4_DesignDetail.B07_wf4_DesignDetail_Engine_Cad import (
|
||||
polyline_entity,
|
||||
station_no_label,
|
||||
)
|
||||
from B07_wf4_DesignDetail.B07_wf4_DesignDetail_Engine_Template import (
|
||||
entities_bbox,
|
||||
frame_entities,
|
||||
)
|
||||
|
||||
# 종단 전용 레이어: 그래프 축·격자(잠금 — 참조용, 편집 제외).
|
||||
LONG_GRID_LAYER_ID = "b07-long-grid"
|
||||
@@ -639,6 +644,11 @@ def build_longitudinal_drawing(
|
||||
)
|
||||
)
|
||||
|
||||
# A1 도각 프레임: 콘텐츠 bbox를 감싸도록 배치 (잠금 레이어, 좌표는 콘텐츠 불변).
|
||||
bbox = entities_bbox(entities)
|
||||
if bbox:
|
||||
entities.extend(frame_entities(drawing_id, bbox))
|
||||
|
||||
return {
|
||||
"format": DRAWING_FORMAT,
|
||||
"entities": entities,
|
||||
@@ -647,5 +657,6 @@ def build_longitudinal_drawing(
|
||||
_layer(DESIGN_LAYER_ID, "Design Plan"),
|
||||
_layer(LONG_GRID_LAYER_ID, "Graph Grid", locked=True),
|
||||
_layer(LONG_TABLE_LAYER_ID, "Station Table"),
|
||||
_layer(FRAME_LAYER_ID, "Frame", locked=True),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
"""B07 도각 템플릿 병합 — openwebcad JSON 템플릿을 도면 콘텐츠 둘레에 배치한다.
|
||||
|
||||
resources/dwg_analysis/templete/의 사전 변환 템플릿(A1 도각 등)을 로드해,
|
||||
도면 콘텐츠 bbox에 맞춰 균등 스케일·이동시킨 뒤 잠금 프레임 레이어
|
||||
(b07-frame) 엔티티로 병합한다. 콘텐츠 좌표(m)는 건드리지 않는다 —
|
||||
템플릿 쪽을 확대해 콘텐츠를 감싼다.
|
||||
|
||||
A1 템플릿 기하(변환 시점 고정값): 전체 840x594, 하단 y17~47 표제란,
|
||||
내부 작도 영역 (42, 47) ~ (812, 567).
|
||||
"""
|
||||
|
||||
import json
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from uuid import uuid5
|
||||
|
||||
from B07_wf4_DesignDetail.B07_wf4_DesignDetail_Engine_Cad import (
|
||||
_ENTITY_NS,
|
||||
FRAME_LAYER_ID,
|
||||
)
|
||||
|
||||
_TEMPLATE_DIR = Path(__file__).resolve().parent.parent / "resources" / "dwg_analysis" / "templete"
|
||||
|
||||
A1_TEMPLATE = "00_templete_A1"
|
||||
# A1 내부 작도 영역(템플릿 좌표) — 콘텐츠가 이 영역 중앙에 오도록 배치한다.
|
||||
_A1_INNER = (42.0, 47.0, 812.0, 567.0)
|
||||
_CONTENT_MARGIN = 0.05 # 내부 작도 영역 대비 콘텐츠 여백 비율(각 방향 5%)
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def _load_template(name: str) -> dict[str, Any] | None:
|
||||
path = _TEMPLATE_DIR / f"{name}.json"
|
||||
if not path.exists():
|
||||
return None
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def entities_bbox(entities: list[dict[str, Any]]) -> tuple[float, float, float, float] | None:
|
||||
"""엔티티 목록의 (min_x, min_y, max_x, max_y). 좌표가 없으면 None."""
|
||||
xs: list[float] = []
|
||||
ys: list[float] = []
|
||||
|
||||
def _collect(entity: dict[str, Any]) -> None:
|
||||
shape = entity.get("shapeData") or {}
|
||||
for key in ("startPoint", "endPoint", "basePoint", "point"):
|
||||
p = shape.get(key)
|
||||
if isinstance(p, dict):
|
||||
xs.append(float(p["x"]))
|
||||
ys.append(float(p["y"]))
|
||||
center = shape.get("center")
|
||||
if isinstance(center, dict):
|
||||
r = float(shape.get("radius", 0.0))
|
||||
xs.extend((float(center["x"]) - r, float(center["x"]) + r))
|
||||
ys.extend((float(center["y"]) - r, float(center["y"]) + r))
|
||||
for child in entity.get("children") or []:
|
||||
_collect(child)
|
||||
|
||||
for entity in entities:
|
||||
_collect(entity)
|
||||
if not xs:
|
||||
return None
|
||||
return (min(xs), min(ys), max(xs), max(ys))
|
||||
|
||||
|
||||
def _transform_entity(
|
||||
entity: dict[str, Any], seed: str, scale: float, dx: float, dy: float
|
||||
) -> dict[str, Any]:
|
||||
"""템플릿 엔티티를 스케일+이동 복사한다. id는 도면별 결정적 재생성."""
|
||||
out = dict(entity)
|
||||
out["id"] = str(uuid5(_ENTITY_NS, seed))
|
||||
out["layerId"] = FRAME_LAYER_ID
|
||||
shape = entity.get("shapeData")
|
||||
if isinstance(shape, dict):
|
||||
new_shape = dict(shape)
|
||||
for key in ("startPoint", "endPoint", "basePoint", "point", "center"):
|
||||
p = shape.get(key)
|
||||
if isinstance(p, dict):
|
||||
new_shape[key] = {"x": p["x"] * scale + dx, "y": p["y"] * scale + dy}
|
||||
if "radius" in shape:
|
||||
new_shape["radius"] = shape["radius"] * scale
|
||||
options = shape.get("options")
|
||||
if isinstance(options, dict):
|
||||
new_options = dict(options)
|
||||
new_options["fontSize"] = options.get("fontSize", 4.0) * scale
|
||||
new_shape["options"] = new_options
|
||||
out["shapeData"] = new_shape
|
||||
children = entity.get("children")
|
||||
if isinstance(children, list):
|
||||
out["children"] = [
|
||||
_transform_entity(child, f"{seed}:{index}", scale, dx, dy)
|
||||
for index, child in enumerate(children)
|
||||
]
|
||||
return out
|
||||
|
||||
|
||||
def frame_entities(
|
||||
drawing_id: str,
|
||||
content_bbox: tuple[float, float, float, float],
|
||||
template_name: str = A1_TEMPLATE,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""콘텐츠 bbox를 감싸는 도각 프레임 엔티티 목록(잠금 레이어). 템플릿 없으면 빈 목록."""
|
||||
template = _load_template(template_name)
|
||||
if not template:
|
||||
return []
|
||||
min_x, min_y, max_x, max_y = content_bbox
|
||||
content_w = max(max_x - min_x, 1e-6)
|
||||
content_h = max(max_y - min_y, 1e-6)
|
||||
|
||||
ix0, iy0, ix1, iy1 = _A1_INNER
|
||||
usable_w = (ix1 - ix0) * (1.0 - 2.0 * _CONTENT_MARGIN)
|
||||
usable_h = (iy1 - iy0) * (1.0 - 2.0 * _CONTENT_MARGIN)
|
||||
scale = max(content_w / usable_w, content_h / usable_h)
|
||||
|
||||
# 콘텐츠 중심 = 내부 작도 영역 중심이 되도록 이동량 산출.
|
||||
dx = (min_x + max_x) / 2.0 - (ix0 + ix1) / 2.0 * scale
|
||||
dy = (min_y + max_y) / 2.0 - (iy0 + iy1) / 2.0 * scale
|
||||
|
||||
return [
|
||||
_transform_entity(entity, f"{drawing_id}:frame:{index}", scale, dx, dy)
|
||||
for index, entity in enumerate(template.get("entities", []))
|
||||
]
|
||||
Reference in New Issue
Block a user