- 데모 v2 이후 개발 PC의 변경을 옮김 (이 저장소의 이름 변경·README 정리는 유지) - 서버 기본 DEM, DEM 등고선, 속성 테이블 범위 선택, WNTR 교차 검증 시험 포함 - 새 라이브러리: ezdxf(Python), maplibre-contour(npm) - 변경 내역: docs/SPipe_패치내역_도면출력_2026-11-06.txt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
57 lines
2.7 KiB
Python
57 lines
2.7 KiB
Python
"""Drawing sheet -> DXF R2018 (ezdxf): Unicode text, layers, lineweights, hatches."""
|
|
import io
|
|
import os
|
|
import tempfile
|
|
|
|
import ezdxf
|
|
import pyogrio
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from backend.batch import BatchError
|
|
from backend.drawing_dxf import drawing_to_dxf
|
|
from backend.main import app
|
|
|
|
DRAWING = {
|
|
"width": 420, "height": 297, "title": "t",
|
|
"items": [
|
|
{"kind": "line", "layer": "FRAME", "pts": [[0, 0], [420, 0], [420, 297], [0, 297]], "closed": True, "width": 0.7},
|
|
{"kind": "line", "layer": "HGL_1", "pts": [[50, 200], [300, 150]], "width": 0.45, "color": "#1d4ed8", "dash": "dashed"},
|
|
{"kind": "fill", "layer": "LEGEND", "pts": [[10, 10], [30, 10], [30, 20], [10, 20]], "fill": "#ffffff", "opacity": 0.9},
|
|
{"kind": "circle", "layer": "NODE", "x": 100, "y": 100, "r": 1.2, "fill": "#dc2626", "color": "#dc2626"},
|
|
{"kind": "text", "layer": "TITLE", "x": 210, "y": 280, "text": "송수관로 수리 종단면도 ○ ‰ m³", "size": 7, "anchor": "middle", "vAnchor": "middle", "bold": True},
|
|
{"kind": "text", "layer": "TABLE", "x": 60, "y": 60, "text": "J-101", "size": 2, "rotate": 90, "anchor": "middle", "vAnchor": "middle"},
|
|
],
|
|
}
|
|
|
|
|
|
def test_r2018_with_unicode_layers_and_styles():
|
|
data = drawing_to_dxf(DRAWING)
|
|
doc = ezdxf.read(io.StringIO(data.decode("utf-8")))
|
|
assert doc.dxfversion == "AC1032" and doc.units == ezdxf.units.MM
|
|
msp = doc.modelspace()
|
|
texts = [e.dxf.text for e in msp.query("TEXT")]
|
|
assert "송수관로 수리 종단면도 ○ ‰ m³" in texts
|
|
hgl = msp.query('LWPOLYLINE[layer=="HGL_1"]')[0]
|
|
assert hgl.dxf.linetype == "DASHED" and hgl.dxf.lineweight == 40 and hgl.rgb == (29, 78, 216)
|
|
assert len(msp.query("HATCH")) == 1 and len(msp.query("CIRCLE")) == 1 # white mask box dropped
|
|
assert {"FRAME", "HGL_1", "NODE", "TITLE", "TABLE"} <= {l.dxf.name for l in doc.layers}
|
|
rotated = [e for e in msp.query("TEXT") if e.dxf.text == "J-101"][0]
|
|
assert rotated.dxf.rotation == 90
|
|
# GDAL (what GIS tools use) reads the Korean text back too.
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
p = os.path.join(tmp, "d.dxf")
|
|
open(p, "wb").write(data)
|
|
meta, _, _, fields = pyogrio.raw.read(p)
|
|
gtexts = [t for t in fields[list(meta["fields"]).index("Text")] if t]
|
|
assert any("송수관로" in t for t in gtexts)
|
|
|
|
|
|
def test_errors_and_endpoint():
|
|
with pytest.raises(BatchError):
|
|
drawing_to_dxf({"items": []})
|
|
with TestClient(app) as c:
|
|
r = c.post("/api/drawing/dxf", json={"drawing": DRAWING, "name": "종단면도"})
|
|
assert r.status_code == 200 and b"AC1032" in r.content
|
|
assert "송수관로".encode("utf-8") in r.content
|