- Frame_Export: Table 갈래 table_parts(경계선 · 글 자리) · 정렬 MIDDLE_LEFT · CENTER · RIGHT · 높이 = 칸 → 표 글자 크기 · 전에는 Table 이 조용히 빠짐 - 짝 = openwebcad table-geometry.ts(두 파일 머리) · 거울 시험 test_b07_frame_export_table.py + helper_b07_table_geometry.cjs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
120 lines
4.4 KiB
Python
120 lines
4.4 KiB
Python
"""DXF 내보내기 표 = 선 + 글(PLAN 41-2) — `B07_DesignDetail_Engine_Frame_Export`.
|
|
|
|
- 거울: `table_parts` 경계선 · 글 자리 = openwebcad `table-geometry.ts`(Node 헬퍼) —
|
|
병합 · 정렬 · 여백
|
|
- DXF: M02 면적산출 표 · B07 수량표(`table_entity`) 모두 LINE · TEXT 로 나옴(전에는 조용히 빠짐) ·
|
|
글 정렬(MIDDLE_LEFT · CENTER · RIGHT) · 높이 = 칸 글자 크기 → 표 글자 크기
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
import ezdxf
|
|
import pytest
|
|
|
|
from B07_DesignDetail import B07_DesignDetail_Engine_Frame_Export as export
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad import table_entity
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
AREA_TABLE = {
|
|
"origin": {"x": 10, "y": 50},
|
|
"columnWidths": [30, 15, 15],
|
|
"rowHeights": [5, 5, 5],
|
|
"cells": [
|
|
[{"text": "항목", "colSpan": 3}, None, None],
|
|
[
|
|
{"text": "면적", "rowSpan": 2, "align": "left"},
|
|
{"text": "12.5", "align": "right"},
|
|
{"text": "㎡"},
|
|
],
|
|
[None, {"text": "1,250", "align": "right", "fontSize": 3}, {"text": ""}],
|
|
],
|
|
"style": {"fontSize": 2.5, "padding": 1, "연결": "T1"},
|
|
}
|
|
PLAIN = {
|
|
"origin": {"x": 0, "y": 0},
|
|
"columnWidths": [10, 10],
|
|
"rowHeights": [4],
|
|
"cells": [[{"text": "a"}, {"text": "b", "align": "left"}]],
|
|
"style": {"padding": 0},
|
|
}
|
|
|
|
|
|
def _mirror(shapes: list[dict]) -> list[dict]:
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_b07_table_geometry.cjs")],
|
|
input=json.dumps(shapes, ensure_ascii=False),
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_거울_경계선_글_자리가_TS_와_같음():
|
|
shapes = [AREA_TABLE, PLAIN]
|
|
for shape, ts in zip(shapes, _mirror(shapes)):
|
|
lines, texts = export.table_parts(shape)
|
|
flat = [value for line in lines for value in line]
|
|
assert flat == pytest.approx([value for line in ts["lines"] for value in line])
|
|
assert len(lines) == len(ts["lines"])
|
|
assert [(t["text"], t["x"], t["y"], t["align"]) for t in texts] == [
|
|
(t["text"], pytest.approx(t["x"]), pytest.approx(t["y"]), t["align"])
|
|
for t in ts["texts"]
|
|
]
|
|
|
|
|
|
def test_병합_자리는_선을_끊음():
|
|
lines, _ = export.table_parts(AREA_TABLE)
|
|
# 바깥 4 · 안쪽 세로 4(1행 병합 자리 끊김) · 가로 5(「면적」 세로 병합 자리 끊김)
|
|
vertical = [line for line in lines[4:] if line[0] == line[2]]
|
|
horizontal = [line for line in lines[4:] if line[1] == line[3]]
|
|
assert len(vertical) == 4 and len(horizontal) == 5
|
|
|
|
|
|
def _dxf(entities: list[dict], tmp_path) -> ezdxf.document.Drawing:
|
|
raw, skipped = export.drawing_to_dxf({"entities": entities, "layers": []})
|
|
assert skipped == {}
|
|
path = tmp_path / "out.dxf"
|
|
path.write_bytes(raw)
|
|
return ezdxf.readfile(path)
|
|
|
|
|
|
def test_면적산출_표가_LINE_TEXT_로_나옴(tmp_path):
|
|
doc = _dxf([{"type": "Table", "layerId": "기본", "shapeData": AREA_TABLE}], tmp_path)
|
|
lines, texts = export.table_parts(AREA_TABLE)
|
|
space = doc.modelspace()
|
|
assert len(space.query("LINE")) == len(lines) == 13
|
|
found = {t.dxf.text: t for t in space.query("TEXT")}
|
|
assert set(found) == {"항목", "면적", "12.5", "㎡", "1,250"} and len(texts) == 5
|
|
assert found["면적"].get_placement()[0] == ezdxf.enums.TextEntityAlignment.MIDDLE_LEFT
|
|
assert found["12.5"].get_placement()[0] == ezdxf.enums.TextEntityAlignment.MIDDLE_RIGHT
|
|
assert found["항목"].get_placement()[0] == ezdxf.enums.TextEntityAlignment.MIDDLE_CENTER
|
|
assert found["1,250"].dxf.height == 3 and found["항목"].dxf.height == 2.5
|
|
|
|
|
|
def test_B07_수량표도_같이_나옴(tmp_path):
|
|
qtable = table_entity(
|
|
"t:qtable",
|
|
(0, 0),
|
|
[20, 20],
|
|
[5, 5],
|
|
[
|
|
[{"text": "토공", "colSpan": 2}, None],
|
|
[{"text": "절토"}, {"text": "12.30", "align": "right"}],
|
|
],
|
|
"b08-cross-table",
|
|
"#ffffff",
|
|
2.0,
|
|
"#ffffff",
|
|
)
|
|
space = _dxf([qtable], tmp_path).modelspace()
|
|
assert len(space.query("LINE")) == 7 # 바깥 4 · 세로 1(1행 병합 자리 끊김) · 가로 2
|
|
assert sorted(t.dxf.text for t in space.query("TEXT")) == ["12.30", "절토", "토공"]
|