- 【極限の設計】AutoCADを「開かずに」変換せよ:ODA File ConverterとPythonによる非同期変換パイプラインの構築
- ==============================================================================
- Module: ConversionOrchestrator
- Description: 高速変換パイプラインの全体制御
- ==============================================================================
- ログ設定:エンジニアリングにおける「可視化」は必須要件である
【極限の設計】AutoCADを「開かずに」変換せよ:ODA File ConverterとPythonによる非同期変換パイプラインの構築
CADデータの運用において、我々シニアエンジニアが直面する最も忌むべき課題の一つは、「バージョンの断絶」である。
数千、数万という図面資産が、2000年代のレガシーな形式から最新のDWG形式まで混在している環境において、AutoCADの `Documents.Open` メソッドを用いて一つずつファイルを開き、`SaveAs` を実行する――。このような「素人臭い」アプローチは、即座に放棄すべきだ。それはメモリリークの温床であり、プロセスがデッドロックに陥るリスクを孕んだ、極めて不安定な設計である。
本稿では、AutoCAD本体のGUIプロセスを介さず、ODA (Open Design Alliance) File Converter を外部エンジンとして利用し、PythonによるオーケストレーションとVBAによる低レイヤー制御を組み合わせた、超高速・高信頼の「バージョン変換パイプライン」の構築手法を詳解する。
1. CADエンジニアリングにおける「重厚長大」という罠
AutoCADは、設計のための「重厚長大」なアプリケーションである。図面を一つ開くたびに、メモリ上には膨大なグラフィックス・エンジン、ジオメトリ・エンジン、そして複雑なレジストリ・ハンドリングが展開される。
大量のファイル変換をAutoCADのプロセス内で行うと、以下の問題が不可避的に発生する:
- メモリの断片化と蓄積: `SaveAs` を繰り返しても、AutoCADのメモリ空間は解放されず、次第にスワップ領域へ食い込み、パフォーマンスが指数関数的に低下する。
- UIスレッドのブロッキング: AutoCADのメインスレッドが変換処理に拘束され、システム全体の応答性が失われる。
- エラーの連鎖: 一つの破損したDWGファイルが `Open` に失敗した瞬間、VBAのランタイムエラーが走り、パイプライン全体が崩壊する。
我々が目指すべきは、「変換処理(Conversion)」と「設計環境(CAD Engine)」の完全なるデカップリング(分離)である。
2. アーキテクチャの転換:ODA File Converterの採用
変換の心臓部には、AutoCADのエンジンとは独立して動作する ODA File Converter を採用する。これはコマンドラインから制御可能なスタンドアロン・コンバーターであり、AutoCADのGUIプロセスを一切介さずに、DWG/DXFのバージョン変換を完結できる。
このアーキテクチャの要諦は以下の通りである:
1. Orchestrator (Python): ディレクトリ走査、ファイルリストの管理、並列実行の制御、ログ出力。
2. Worker (VBA/Shell): Windows OSへの命令発行、外部プロセスのライフサイクル管理。
3. Engine (ODA File Converter): 実際のバイナリ変換処理。
3. 実装フェーズ I:VBAによる低レイヤー制御
まず、VBA側では、単なる `Shell` 関数ではなく、プロセスの終了を確実に待ち、戻り値(Exit Code)を厳密に評価するための制御ロジックが必要となる。ここでは `WScript.Shell` を用い、同期実行(WaitOnReturn)を実現する。
' ==============================================================================
' Module: ConversionController
' Description: ODA File Converterを呼び出し、変換プロセスを同期的に制御する
' ==============================================================================
Option Explicit
' Windows APIの宣言(高度なプロセス制御が必要な場合に使用)
' 今回はWScript.Shellによる抽象化された制御を用いるが、
' 異常終了時のプロセス強制終了が必要な場合はTerminateProcess等の検討が必要。
Public Function ExecuteODAMachine(ByVal odaPath As String, _
ByVal inputDir As String, _
ByVal outputDir As String, _
ByVal version As String, _
ByVal fileType As String) As Boolean
Dim shell As Object
Dim command As String
Dim exitCode As Long
Dim wsh As Object
On Error GoTo ErrorHandler
' WScript.Shellオブジェクトの生成
Set shell = CreateObject("WScript.Shell")
' ODA File Converterのコマンドライン引数構築
' 引数構成: [InputFolder] [OutputFolder] [InputVersion] [OutputVersion] [Filter] [Recursive]
' 例: "C:\ODA\ODAFileConverter.exe" "C:\In" "C:\Out" "ACAD2018" "ACAD2013" "DWG" "0"
command = """" & odaPath & """ " & _
"""" & inputDir & """ " & _
"""" & outputDir & """ " & _
"""" & version & """ " & _
"""" & version & """ " & _
"""" & fileType & """ " & _
"0" ' Recursive flag (0: No, 1: Yes)
Debug.Print "Executing Command: " & command
' Runメソッドの第3引数をTrueにすることで、プロセス終了まで待機(Synchronous)
' 第4引数はウィンドウの表示状態(0: 非表示)
exitCode = shell.Run(command, 0, True)
' ODAの戻り値を確認(通常、成功時は0)
If exitCode = 0 Then
ExecuteODAMachine = True
Else
Debug.Print "Error: ODA Converter exited with code " & exitCode
ExecuteODAMachine = False
End If
Set shell = Nothing
Exit Function
ErrorHandler:
Debug.Print "Critical Error in VBA Execution: " & Err.Description
ExecuteODAMachine = False
Set shell = Nothing
End Function
4. 実装フェーズ II:Pythonによるオーケストレーション
VBA単体では、ディレクトリの再帰的な走査や、エラー発生時のリトライ、詳細なJSONログ出力といった「システム管理」の領域において限界がある。ここでPythonを導入し、パイプラインの司令塔(Orchestrator)としての役割を担わせる。
Pythonは、`subprocess` モジュールを用いて、VBAを介さず直接ODAを叩くことも可能だが、既存のVBA資産(AutoCAD内部の特殊な属性チェックなど)を活かす場合は、PythonからExcel/AutoCADを介してVBAを呼び出す構成が合理的である。
import subprocess
import os
import logging
from pathlib import Path
==============================================================================
Module: ConversionOrchestrator
Description: 高速変換パイプラインの全体制御
==============================================================================
ログ設定:エンジニアリングにおける「可視化」は必須要件である
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
handlers=[logging.FileHandler("conversion.log"), logging.StreamHandler()]
)
class ConversionPipeline:
def __init__(self, oda_exe, target_version="ACAD2013", file_type="DWG"):
self.oda_exe = oda_exe
self.target_version = target_version
self.file_type = file_type
def run_batch_conversion(self, input_root, output_root):
"""
ディレクトリ構造を維持したまま、一括変換を実行する
"""
input_path = Path(input_root)
output_path = Path(output_root)
if not input_path.exists():
logging.error(f"Input path does not exist: {input_root}")
return
# 変換対象のディレクトリを走査
# ここでは単純化のため、ディレクトリ単位でODAを呼び出す
# ODAはディレクトリ単位での変換に最適化されているため
for folder in input_path.iterdir():
if folder.is_dir():
rel_path = folder.relative_to(input_path)
dest_dir = output_path / rel_path
dest_dir.mkdir(parents=True, exist_ok=True)
logging.info(f"Processing directory: {rel_path}")
try:
# ODA File Converterの直接呼び出し
# subprocess.run を用いて、非同期ではなく同期的に実行し、完了を待つ
cmd = [
self.oda_exe,
str(folder),
str(dest_dir),
"ACAD2018", # Input Version (例)
self.target_version, # Output Version
self.file_type,
"0" # Recursive
]
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
logging.info(f"Successfully converted: {rel_path}")
except subprocess.CalledProcessError as e:
logging.error(f"Conversion failed for {rel_path}: {e.stderr}")
except Exception as e:
logging.critical(f"Unexpected error: {str(e)}")
if __name__ == "__main__":
# パス設定(環境に応じて厳密に定義すること)
ODA_PATH = r"C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe"
INPUT_DIR = r"C:\CAD_Data\Legacy_Project"
OUTPUT_DIR = r"C:\CAD_Data\Converted_Project"
pipeline = ConversionPipeline(ODA_PATH, target_version="ACAD2013")
pipeline.run_batch_conversion(INPUT_DIR, OUTPUT_DIR)
5. メモリとプロセスの完全なる統治:アーキテクトの心得
このシステムを実戦投入するにあたり、以下の「極限の知見」を忘れてはならない。
オブジェクトのライフサイクル管理
VBAにおいて `Set obj = Nothing` は基本中の基本だが、外部プロセスを制御する場合、真の敵は「ゾンビプロセス」である。`WScript.Shell` が異常終了した場合、ODAのプロセスがバックグラウンドで残り続け、ファイルロックを引き起こす。
実運用環境では、Pythonの `psutil` ライブラリ等を用いて、変換開始前に既存の `ODAFileConverter.exe` プロセスをスキャンし、異常な残留プロセスを強制終了(`terminate()`)する処理を組み込むべきだ。
I/Oボトルネックの回避
大量のDWG変換において、CPUよりも先にボトルネックとなるのはディスクI/Oである。
- RAID構成/NVMe SSD: 変換パイプラインを走らせるワークステーションには、高速なNVMeストレージが必須である。
- ネットワークドライブの回避: 変換処理中にネットワーク越しにファイルを読み書きすることは、破損リスクと極端な遅延を招く。必ず「ローカルへのコピー → 変換 → 転送」の3ステップを徹底せよ。
冪等性(Idempotency)の確保
パイプラインが途中でクラッシュした場合、再実行した際に「既に変換済みのファイル」を二重に処理しない設計にすること。Python側で出力ディレクトリの存在確認や、ファイルタイムスタンプの比較を行うことで、システムの堅牢性は飛躍的に高まる。
結論
AutoCAD VBAを「単なるマクロ」として使うのか、それとも「巨大なシステムの一部」として設計するのか。その差は、オブジェクトのライフサイクル、プロセスの分離、そして外部エンジンの戦略的活用にある。
ODA File ConverterとPythonを組み合わせたこのアーキテクチャは、CAD運用における「バージョンの呪縛」を解き放つ、極めて強力な武器となるだろう。
