feat(B07): LibreDWG 변환기 동봉 및 자동 탐색
- 저장소에 LibreDWG 0.14.8594 Windows 실행 파일 동봉 (dwg2dxf/dxf2dwg + 필요한 DLL 4개, 약 33MB) 실제 파일은 메인 워크트리 B07_DesignDetail/openwebcad/tools/libredwg 에 두고 보조 워크트리는 junction 으로 연결 - 파이썬 바인딩 미포함 (import 시 GPL 이 본 프로그램까지 확산) — 별도 프로세스 호출 방식 유지 - GPL v3 전문(COPYING)과 원본 출처·구성·교체 방법 README 동봉 - 변환기 탐색 순서: .env 경로 → 동봉본 → PATH - 옛 DXF 의 유니코드 escape 를 복원해 DWG 왕복 시 한글 깨짐 해결, DWG 출력용 DXF 는 R2004 로 생성 - DWG 왕복 검증 테스트 추가 (tmp/tests, git 추적 제외) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ from uuid import NAMESPACE_URL, uuid5
|
||||
|
||||
import ezdxf
|
||||
from ezdxf import colors as ezdxf_colors
|
||||
from ezdxf.lldxf.encoding import decode_dxf_unicode, has_dxf_unicode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -38,6 +39,17 @@ _FLATTEN_MM = 0.2
|
||||
_MAX_ENTITIES = 20000
|
||||
|
||||
|
||||
# 프로그램에 함께 담은 LibreDWG 자리 — `B07_DesignDetail/openwebcad/tools/libredwg/`.
|
||||
# 별도 실행 파일로만 부른다(라이브러리로 품지 않는다) — 자세한 것은 그 폴더의 README.
|
||||
_BUNDLED_DIR = Path(__file__).resolve().parent / "openwebcad" / "tools" / "libredwg"
|
||||
|
||||
|
||||
def bundled_tool(name: str) -> str | None:
|
||||
"""동봉한 변환기 경로. 없으면 None."""
|
||||
path = _BUNDLED_DIR / name
|
||||
return str(path) if path.is_file() else None
|
||||
|
||||
|
||||
def _entity_id(index: int) -> str:
|
||||
return str(uuid5(_IMPORT_NS, str(index)))
|
||||
|
||||
@@ -99,12 +111,17 @@ def _polyline(index: int, entity: Any, points: list[Any], closed: bool) -> dict[
|
||||
return {**_base(index, entity, "PolyLine"), "shapeData": None, "children": children}
|
||||
|
||||
|
||||
def _plain(label: str) -> str:
|
||||
"""옛 DXF 는 한글을 유니코드 escape 로 적는다 — 글자로 되돌린다."""
|
||||
return decode_dxf_unicode(label) if has_dxf_unicode(label) else label
|
||||
|
||||
|
||||
def _text(index: int, entity: Any, label: str, insert: Any, height: float) -> dict[str, Any]:
|
||||
rotation = float(getattr(entity.dxf, "rotation", 0.0) or 0.0)
|
||||
return {
|
||||
**_base(index, entity, "Text"),
|
||||
"shapeData": {
|
||||
"label": label,
|
||||
"label": _plain(label),
|
||||
"basePoint": _point(insert[0], insert[1]),
|
||||
"options": {
|
||||
"textDirection": _point(cos(radians(rotation)), sin(radians(rotation))),
|
||||
@@ -215,11 +232,11 @@ def dwg_version(data: bytes) -> str | None:
|
||||
|
||||
|
||||
def _dwg2dxf_path() -> str | None:
|
||||
"""LibreDWG 변환기(dwg2dxf) 자리. `.env` 값이 먼저고, 없으면 PATH 에서 찾는다."""
|
||||
"""LibreDWG 변환기(dwg2dxf) 자리 — `.env` 값 → 동봉본 → PATH 순으로 찾는다."""
|
||||
configured = os.getenv("LIBREDWG_DWG2DXF_PATH", "").strip()
|
||||
if configured:
|
||||
return configured if Path(configured).is_file() else None
|
||||
return shutil.which("dwg2dxf")
|
||||
return bundled_tool("dwg2dxf.exe") or shutil.which("dwg2dxf")
|
||||
|
||||
|
||||
def _dwg_to_dxf(source: Path, work_dir: Path) -> Path:
|
||||
|
||||
Reference in New Issue
Block a user