Files
Aislo/resources/tester/test_b07_frame_import_shapes.py
T
eomsangdonandClaude Opus 5.5 008558d4ee fix(B07): DXF·DWG 불러오기 작은 원·호 뭉개짐 고침 — 곡선 토막마다 8마디 이상 · 부분 타원 닫는 줄 없앰(99-3)
- 원인: 펴기 허용오차 0.2 고정 — m 단위 도면(중력식 사방댐 시트 폭 약 80)에서 반지름 0.071 원이 길이 0 선 1개 · 0.15~0.2 원이 삼각형 · 0.36~0.46 호가 직선 한 마디
- 고침: 원·호·타원·스플라인·bulge 폴리선 모두 ezdxf 경로로 펴고 90° 이하 토막마다 8마디 이상
- 원본 DWG 대조: 원 42 · 호 16 오차 반지름의 0.5% 이하 · 호 16 모두 원래 각 범위 안(큰 호로 뒤집힘 0) · 불러오기 1.45 s · 도형 1,959
- 시험: test_b07_frame_import_shapes 작은 원·호 시험 하나 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KYZ2HWWdUwZWYnn3tQz7X
2026-10-08 15:16:40 +09:00

157 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""B07 도면 불러오기 — 호 · bulge 폴리선 · 거울 블록 · 겹 블록 견본 DXF(84-2) · 내보내기 시계방향 호(84-3).
견본은 ezdxf 로 그 자리에서 만들어 끌어다 놓기 길(`drawing_file_to_entities`)로 읽는다.
"""
from __future__ import annotations
import io
import math
import ezdxf
from ezdxf.enums import TextEntityAlignment
from B07_DesignDetail import B07_DesignDetail_Engine_Frame_Export as export
from B07_DesignDetail.B07_DesignDetail_Engine_Frame_Import import drawing_file_to_entities
def _read(doc: ezdxf.document.Drawing) -> list[dict]:
stream = io.StringIO()
doc.write(stream)
entities, _layers = drawing_file_to_entities("견본.dxf", stream.getvalue().encode("utf-8"))
return entities
def _points(polyline: dict) -> list[tuple[float, float]]:
children = polyline["children"]
points = [
(c["shapeData"]["startPoint"]["x"], c["shapeData"]["startPoint"]["y"]) for c in children
]
last = children[-1]["shapeData"]["endPoint"]
return [*points, (last["x"], last["y"])]
def _on_circle(points, cx: float, cy: float, r: float) -> bool:
return all(abs(math.hypot(x - cx, y - cy) - r) < 0.21 for x, y in points)
def test_호는_1사분면_작은_호():
doc = ezdxf.new()
doc.modelspace().add_arc((0, 0), 10, 0, 90)
(arc,) = _read(doc)
points = _points(arc)
assert _on_circle(points, 0, 0, 10)
assert points[0] == (10.0, 0.0) and math.isclose(points[-1][0], 0, abs_tol=1e-9)
assert all(x >= -1e-9 and y >= -1e-9 for x, y in points) # 큰 호(270°)로 뒤집히지 않음
def test_bulge_폴리선은_호로_펴짐():
doc = ezdxf.new()
space = doc.modelspace()
# 반원(bulge 1 · 반시계 → 아래로) · 작은 호(bulge −0.2 · 시계 → 위로 1)
space.add_lwpolyline([(0, 0, 0, 0, 1), (10, 0)], format="xyseb")
space.add_lwpolyline([(0, 20, 0, 0, -0.2), (10, 20)], format="xyseb")
half, small = _read(doc)
half_points = _points(half)
assert len(half_points) > 3 and _on_circle(half_points, 5, 0, 5)
assert min(y for _x, y in half_points) < -4.9
small_points = _points(small)
assert len(small_points) > 3
assert math.isclose(max(y for _x, y in small_points), 21.0, abs_tol=0.01) # 처짐 = 0.2 × 10 / 2
assert min(y for _x, y in small_points) >= 20 - 1e-9
def test_거울_블록은_WCS_자리():
doc = ezdxf.new()
block = doc.blocks.new("거울")
block.add_lwpolyline([(0, 0, 0, 0, -0.2), (10, 0)], format="xyseb")
block.add_arc((20, 0), 2, 0, 90)
block.add_text("가", dxfattribs={"height": 2.5}).set_placement((2, 3))
doc.modelspace().add_blockref("거울", (100, 0), dxfattribs={"xscale": -1})
by_type: dict[str, list[dict]] = {}
for entity in _read(doc):
by_type.setdefault(entity["type"], []).append(entity)
bulge, arc = by_type["PolyLine"]
bulge_points = _points(bulge)
assert (
min(x for x, _y in bulge_points) >= 90 - 1e-9
and max(x for x, _y in bulge_points) <= 100 + 1e-9
)
assert math.isclose(max(y for _x, y in bulge_points), 1.0, abs_tol=0.01) # 위로 그대로
arc_points = _points(arc)
assert _on_circle(arc_points, 80, 0, 2)
assert all(x <= 80 + 1e-9 and y >= -1e-9 for x, y in arc_points) # 2사분면으로 대칭
(text,) = by_type["Text"]
assert text["shapeData"]["basePoint"] == {"x": 98.0, "y": 3.0}
def test_겹_블록도_풀림():
doc = ezdxf.new()
doc.blocks.new("속").add_line((0, 0), (1, 0))
doc.blocks.new("겉").add_blockref("속", (5, 0))
doc.modelspace().add_blockref("겉", (10, 0))
(line,) = _read(doc)
assert line["type"] == "Line"
assert line["shapeData"] == {
"startPoint": {"x": 15.0, "y": 0.0},
"endPoint": {"x": 16.0, "y": 0.0},
}
def test_TEXT_정렬점_자리():
doc = ezdxf.new()
space = doc.modelspace()
space.add_text("가운데", dxfattribs={"height": 2}).set_placement(
(50, 5), align=TextEntityAlignment.MIDDLE_CENTER
)
space.add_text("오른", dxfattribs={"height": 2}).set_placement(
(80, 5), align=TextEntityAlignment.BOTTOM_RIGHT
)
center, right = _read(doc)
assert center["shapeData"]["basePoint"] == {"x": 50.0, "y": 5.0}
assert center["shapeData"]["options"]["textAlign"] == "center"
assert right["shapeData"]["basePoint"] == {"x": 80.0, "y": 5.0}
assert right["shapeData"]["options"]["textAlign"] == "right"
def test_내보내기_시계방향_작은_호(tmp_path):
arc = {
"type": "Arc",
"layerId": "기본",
"shapeData": {
"center": {"x": 0, "y": 0},
"radius": 1,
"startAngle": math.pi / 2,
"endAngle": 0,
"counterClockwise": False,
},
}
raw, skipped = export.drawing_to_dxf({"entities": [arc], "layers": []})
assert skipped == {}
path = tmp_path / "out.dxf"
path.write_bytes(raw)
(out,) = ezdxf.readfile(path).modelspace().query("ARC")
span = (out.dxf.end_angle - out.dxf.start_angle) % 360
assert math.isclose(span, 90) and math.isclose(out.dxf.start_angle % 360, 0, abs_tol=1e-9)
def test_작은_원_호는_뭉개지지_않음():
"""m 단위 도면(99-3 중력식사방댐) — 반지름 0.071 원 · 0.36 호 · bulge 0.4 폭 반원이 점 · 직선이 되지 않음."""
doc = ezdxf.new()
space = doc.modelspace()
space.add_circle((0, 0), 0.071)
space.add_arc((5, 0), 0.361, 10, 96)
space.add_lwpolyline([(10, 0, 0, 0, 1), (10.4, 0)], format="xyseb")
circle, arc, half = _read(doc)
circle_points = _points(circle)
assert len(circle_points) >= 33 and circle_points[0] == circle_points[-1]
assert _on_circle(circle_points, 0, 0, 0.071)
assert max(x for x, _y in circle_points) > 0.07 and min(x for x, _y in circle_points) < -0.07
arc_points = _points(arc)
assert len(arc_points) >= 9
for x, y in arc_points: # 10°~96° 안 · 큰 호로 뒤집히지 않음
assert abs(math.hypot(x - 5, y) - 0.361) < 0.003
assert 10 - 0.01 <= math.degrees(math.atan2(y, x - 5)) <= 96 + 0.01
half_points = _points(half)
assert len(half_points) >= 9 and min(y for _x, y in half_points) < -0.19