From 008558d4ee25827fc2e14c8194e26ea9c732553d Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 8 Oct 2026 15:16:40 +0900 Subject: [PATCH] =?UTF-8?q?fix(B07):=20DXF=C2=B7DWG=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20=EC=9E=91=EC=9D=80=20=EC=9B=90=C2=B7?= =?UTF-8?q?=ED=98=B8=20=EB=AD=89=EA=B0=9C=EC=A7=90=20=EA=B3=A0=EC=B9=A8=20?= =?UTF-8?q?=E2=80=94=20=EA=B3=A1=EC=84=A0=20=ED=86=A0=EB=A7=89=EB=A7=88?= =?UTF-8?q?=EB=8B=A4=208=EB=A7=88=EB=94=94=20=EC=9D=B4=EC=83=81=20=C2=B7?= =?UTF-8?q?=20=EB=B6=80=EB=B6=84=20=ED=83=80=EC=9B=90=20=EB=8B=AB=EB=8A=94?= =?UTF-8?q?=20=EC=A4=84=20=EC=97=86=EC=95=B0(99-3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 원인: 펴기 허용오차 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 Claude-Session: https://claude.ai/code/session_015KYZ2HWWdUwZWYnn3tQz7X --- .../B07_DesignDetail_Engine_Frame_Import.py | 25 +++++++++++++------ .../tester/test_b07_frame_import_shapes.py | 21 ++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/B07_DesignDetail/B07_DesignDetail_Engine_Frame_Import.py b/B07_DesignDetail/B07_DesignDetail_Engine_Frame_Import.py index 673df9a21..ae6ce9982 100644 --- a/B07_DesignDetail/B07_DesignDetail_Engine_Frame_Import.py +++ b/B07_DesignDetail/B07_DesignDetail_Engine_Frame_Import.py @@ -39,6 +39,8 @@ _IMPORT_NS = uuid5(NAMESPACE_URL, "aislo/b07/frame-import") _DEFAULT_COLOR = "#f5f7fa" # 곡선을 선분으로 풀 때 허용 오차(mm) — 도각 크기(840x594mm)에서 눈에 띄지 않는다. _FLATTEN_MM = 0.2 +# 곡선 한 토막(90° 이하)을 적어도 이만큼 나눔 — 단위가 m 인 도면의 작은 원 · 호가 점 · 삼각형 · 직선으로 뭉개지지 않게. +_CURVE_SEGMENTS = 8 _MAX_ENTITIES = 20000 # 블록 속 블록을 풀 깊이 — 자기를 품는 깨진 블록에서 끝없이 돌지 않게. _MAX_BLOCK_DEPTH = 16 @@ -149,10 +151,19 @@ def _text( } -def _flatten(entity: Any) -> list[Any] | None: - """원·호·타원·스플라인을 선분 점열로 편다. 못 펴면 None.""" +def _path_points(entity: Any) -> list[Any]: + """도형 → WCS 경로 점열 — 곡선 토막마다 `_CURVE_SEGMENTS` 이상으로 나눔.""" + return list(ezdxf_path.make_path(entity).flattening(_FLATTEN_MM, segments=_CURVE_SEGMENTS)) + + +def _flatten(entity: Any) -> tuple[list[Any], bool] | None: + """원·호·타원·스플라인 → (선분 점열, 닫힘). 경로는 닫는 마디까지 넣음 · 못 펴면 None.""" try: - return list(entity.flattening(_FLATTEN_MM)) + return _path_points(entity), False + except Exception: + pass + try: + return list(entity.flattening(_FLATTEN_MM)), entity.dxftype() == "CIRCLE" except Exception: return None @@ -164,7 +175,7 @@ def _polyline_points(entity: Any) -> tuple[list[Any], bool]: 면 · 메시 POLYLINE 처럼 경로로 못 바꾸면 꼭짓점을 그대로 잇는다. """ try: - return list(ezdxf_path.make_path(entity).flattening(_FLATTEN_MM)), False + return _path_points(entity), False except Exception: if entity.dxftype() == "LWPOLYLINE": return list(entity.get_points("xy")), bool(entity.closed) @@ -203,10 +214,10 @@ def _convert_entity(index: int, entity: Any) -> list[dict[str, Any]]: shape = _polyline(index, entity, points, closed) return [shape] if shape else [] if kind in ("CIRCLE", "ARC", "ELLIPSE", "SPLINE"): - points = _flatten(entity) - if not points: + flat = _flatten(entity) + if not flat: return [] - shape = _polyline(index, entity, points, kind in ("CIRCLE", "ELLIPSE")) + shape = _polyline(index, entity, *flat) return [shape] if shape else [] if kind == "POINT": location = entity.dxf.location diff --git a/resources/tester/test_b07_frame_import_shapes.py b/resources/tester/test_b07_frame_import_shapes.py index a93942d27..5038d2363 100644 --- a/resources/tester/test_b07_frame_import_shapes.py +++ b/resources/tester/test_b07_frame_import_shapes.py @@ -133,3 +133,24 @@ def test_내보내기_시계방향_작은_호(tmp_path): (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