境界を切り出す:AutoCAD VBAにおける「Export」メソッドの極致とメモリ管理の鉄則
大規模なプラント設計や建築プロジェクトにおいて、数GBに及ぶ巨大なDWGファイルから、特定の部品や加工用データとして「特定の範囲だけ」をDXFとして切り出す作業は、日常的に発生する。
しかし、多くのエンジニアが書くコードは脆弱だ。`SelectionSets` の適切な破棄を怠り、ループ処理の中でメモリリークを引き起こし、数千ファイル規模のバッチ処理において、ある日突然AutoCADが「沈黙(クラッシュ)」する。
本稿では、単なる「書き出し方の説明」はしない。オブジェクトのライフサイクル、座標系の厳密な制御、そして商用システムに耐えうる堅牢なアーキテクチャを構築するための、実務中級者以上が知るべき「極限の知見」を伝授する。
1. `Document.Export` メソッドの本質的な挙動
AutoCAD VBAにおける `Document.Export` メソッドは、一見すると単純なファイル保存関数に見える。しかし、その真の挙動は「現在の選択セット(SelectionSet)」、あるいは「ユーザーによる選択」に強く依存している。
図面全体を保存する `SaveAs` と決定的に異なるのは、「何が選択されているか」というコンテキストが、出力されるDXFの内容を決定づけるという点だ。
陥りやすい罠:SelectionSetsの衝突
VBAでプログラムから選択セットを作成する場合、既存の選択セット名と衝突するとランタイムエラーが発生する。また、作成した選択セットを `Delete` せずに放置すると、AutoCADのメモリ空間にオブジェクト参照が残り続け、メモリリークの直接的な原因となる。
2. 堅牢な切り出しロジックの設計思想
特定の座標範囲(Bounding Box)をDXFとして切り出す場合、以下の3つのフェーズを「アトミック(不可分)」に実行する必要がある。
1. 座標系の正規化: ユーザーのUCS(ユーザー座標系)ではなく、必ずWCS(世界座標系)で範囲を定義すること。
2. 選択セットの厳密な管理: 既存のセットを排除し、エラーハンドリング内で確実に解放すること。
3. メモリの明示的解放: `Set obj = Nothing` は、単なる作法ではなく、COMオブジェクトの参照カウントを制御するための必須命令である。
3. 実装例:高信頼性・範囲指定DXFエクスポート・エンジン
以下に、実務でそのまま利用可能なレベルの、エラーハンドリングとメモリ管理を組み込んだコードを示す。
Option Explicit
''' <summary>
''' 指定したWCS座標範囲内のオブジェクトをDXFとして書き出す。
''' </summary>
''' <param name="targetDoc">対象のAutoCADドキュメント</param>
''' <param name="exportPath">保存先のフルパス(拡張子は.dxf)</param>
''' <param name="minPt">範囲の最小座標 (Array of Double: x, y, z)</param>
''' <param name="maxPt">範囲の最大座標 (Array of Double: x, y, z)</param>
Public Sub ExportRangeToDXF(ByRef targetDoc As AcadDocument, _
ByVal exportPath As String, _
ByVal minPt As Variant, _
ByVal maxPt As Variant)
Dim ssObj As AcadSelectionSet
Dim ssName As String
Dim errorOccurred As Boolean
' 1. 選択セット名の定義(一意性を確保)
ssName = "TEMP_EXPORT_SS_" & Format(Now, "yyyymmddhhmmss")
errorOccurred = False
On Error GoTo ErrorHandler
' 2. 選択セットの作成
' 既存の同名セットがないことを前提とするが、念のためエラーハンドリングを行う
Set ssObj = targetDoc.SelectionSets.Add(ssName)
' 3. 範囲選択 (Crossing Window を使用)
' Window選択(Select)は範囲内のもののみだが、Crossing(CrossingWindow)は境界に触れたものも含む。
' 加工データ等の切り出しでは、境界欠落を防ぐため Crossing が推奨される。
ssObj.Select acSelectionSetCrossing, minPt, maxPt
' 4. エクスポートの実行
' Exportメソッドは、選択セットが空の場合、エラーを投げる可能性があるため注意。
If ssObj.Count > 0 Then
targetDoc.Export exportPath, ssObj
Else
Err.Raise vbObjectError + 513, "ExportRangeToDXF", "指定された範囲内にオブジェクトが存在しません。"
End If
Debug.Print "Successfully exported: " & exportPath
CleanUp:
' 5. メモリ解放の儀式(最重要)
' 選択セットを削除しない限り、メモリ上に残り続ける。
On Error Resume Next
If Not ssObj Is Nothing Then
ssObj.Delete
Set ssObj = Nothing
End If
Exit Sub
ErrorHandler:
errorOccurred = True
MsgBox "Critical Error during Export: " & Err.Description, vbCritical
Resume CleanUp
End Sub
''' <summary>
''' 実行用テストルーチン
''' </summary>
Public Sub TestExport()
Dim doc As AcadDocument
Set doc = ThisDrawing
' WCS座標での範囲指定 (例: 0,0,0 から 100,100,0)
Dim minP(0 To 2) As Double: minP(0) = 0#: minP(1) = 0#: minP(2) = 0#
Dim maxP(0 To 2) As Double: maxP(0) = 100#: maxP(1) = 100#: maxP(2) = 0#
Dim savePath As String
savePath = "C:\Temp\Part_Export_" & Format(Now, "hhmmss") & ".dxf"
Call ExportRangeToDXF(doc, savePath, minP, maxP)
End Sub
4. アーキテクトの視点:さらなる高みへ
上記のコードは「動く」が、エンタープライズ・レベルのシステムにおいては、以下の観点がさらに求められる。
A. Windows API によるファイルロックの検証
`Export` メソッドが実行される際、出力先のファイルが他のプロセス(例えば、プレビュー表示中のエクスプローラーや別のCADプロセス)によってロックされていると、AutoCADは無慈悲に停止する。
本格的なシステムでは、`CreateFile` API を用いて、書き込み前にファイルが排他的に取得可能かどうかをチェックするレイヤーを設けるべきだ。
B. DXFバージョンの互換性問題
`Export` メソッドは、現在のドキュメントのバージョンに基づいたDXFを出力する。もし、レガシーなCAM装置(古いCNCマシンなど)へデータを送る場合、AutoCAD 2024の図面から書き出されたDXFは、構文エラーを引き起こす可能性がある。
この場合、VBA単体での制御には限界があるため、「一旦、古いバージョンのDWG形式で保存し直してからエクスポートする」という、極めて泥臭いが確実なワークフローを自動化に組み込む判断が必要だ。
C. 座標系の罠(WCS vs UCS)
`minPt` と `maxPt` を渡す際、ユーザーが画面上でクリックした座標(UCS)をそのまま渡すと、図面が傾いている場合に全く異なる範囲が切り出される。
必ず `Utility.GetPoint` 等で取得した座標に対し、`ActiveUCS` から `World` への変換行列を適用するか、あるいは `GetBoundingBox` メソッドを用いて、オブジェクトから直接WCSの座標を抽出するロジックを実装せよ。
結論
AutoCAD VBAにおける「切り出し」は、単なる関数の呼び出しではない。それは、オブジェクトの生存期間を管理し、座標系という数学的真理を制御し、不確実なファイルシステムと対峙するプロセスである。
「動けばいい」というコードは、大規模な自動化の現場では「時限爆弾」でしかない。常にメモリの底を見つめ、例外処理の網を張り、堅牢なアーキテクチャを構築せよ。それが、伝説的なエンジニアへの唯一の道である。
