AutoCAD VBAの深淵:矩形選択領域(Window)内のエンティティを「外科手術」する極意
AutoCAD VBAにおいて、全図面を対象としたイテレーションは、もはや「素人の所業」だ。数万のオブジェクトを走査し、条件分岐で間引く……そんなコードが低速なのは、AutoCADのオブジェクトモデルとメモリ管理の深層を理解していないからに他ならない。
真に効率的なシステムを構築するエンジニアは、「最初から必要なオブジェクトだけを拾い上げる」。今回は、`GetWindowSelection`を用いた空間的フィルタリングを軸に、シニアエンジニアが押さえておくべきメモリ管理と設計思想を伝授する。
1. なぜ「空間フィルタリング」が必要なのか
`ThisDrawing.ModelSpace`を`For Each`で回すのは簡単だ。だが、図面が肥大化した瞬間に処理は停止する。なぜか?
VBAのラッパーを通じたCOMの呼び出しコストは極めて重い。不必要なオブジェクトをメモリ空間にロードし、解放するプロセス自体がシステムリソースを食いつぶす。
今回解説する「Window選択」は、AutoCADの強力な選択セット(SelectionSet)のエンジンを直接叩く手法だ。これにより、CPU負荷を最小限に抑えつつ、必要なオブジェクトのみをメモリ上にマッピングできる。
2. 空間選択エンジンの実装コード
以下のコードは、単なる選択ではない。`AcadSelectionSets`の重複エラーを回避し、メモリリークを防ぐための「防弾仕様」だ。
‘ ———————————————————
‘ 矩形範囲(Window)内のエンティティのみを抽出・処理するメソッド
‘ ———————————————————
Public Sub ProcessEntitiesInWindow(pt1 As Variant, pt2 As Variant)
Dim ssets As AcadSelectionSets
Dim sset As AcadSelectionSet
Dim ent As AcadEntity
‘ 1. セレクションセットのクリーンアップ(極めて重要)
Set ssets = ThisDrawing.SelectionSets
On Error Resume Next
ssets.Item(“TargetRangeSet”).Delete
On Error GoTo 0
Set sset = ssets.Add(“TargetRangeSet”)
‘ 2. Windowモードでの選択実行 (acSelectionSetWindow)
‘ 内部エンジンが空間インデックスを走査し、瞬時に結果を返す
sset.Select acSelectionSetWindow, pt1, pt2
‘ 3. 処理対象の走査
‘ ここで初めてメモリ上にオブジェクトのポインタが保持される
For Each ent In sset
‘ ここに外科手術(プロパティ変更・移動など)を記述
‘ 例: ent.Color = acRed
Next ent
‘ 4. 明示的なメモリ解放
‘ VBAはGCが弱いため、巨大なコレクションを操作した際は即座に解放する
sset.Delete
Set sset = Nothing
Set ssets = Nothing
End Sub
3. シニアエンジニアが看過してはならない「メモリ最適化」の真実
上記のコードには、単なるスクリプト以上の意図が隠されている。
- SelectionSetの即時廃棄: `SelectionSet`は一度作成すると、明示的に`Delete`しない限り`AcadSelectionSets`コレクション内に残留する。これはVBAプログラムのセッションが終了するまでメモリを占有し続け、いわゆる「メモリの腐敗」を招く。`Delete`を忘れるエンジニアは、現場を去るべきだ。
- On Error Resume Nextの意図: ここでのエラー処理は、既に存在する同名のセレクションセットを削除するための「おまじない」ではない。AutoCADのプロセスが予期せぬ終了をした後の、残存オブジェクトを安全にハンドリングするための防衛策である。
4. レガシー環境との共存:WinAPIでの補強
もし、極限のパフォーマンスを求めるならば、`GetWindowSelection`の限界を超えて、Windows APIを介して図面座標とスクリーン座標の変換を直接制御する必要がある。
特に、`ActiveViewport`の傾きやUCS(ユーザー座標系)が複雑な場合、単純な`Select`メソッドでは選択精度が落ちることがある。そんな時は、`acedTrans`関数を駆使して、デバイス座標(スクリーン上の矩形)をWCSに正確にマッピングしろ。
‘ 必要なAPI定義(必要に応じてUser32.dllを叩く)
‘ シニアであれば、GetCursorPos等で動的に矩形を生成するUIを構築せよ
5. 伝説のアーキテクトからの提言
AutoCAD VBAはレガシーだと揶揄されるが、それは「設計思想の古さ」を指しているに過ぎない。オブジェクトモデルの真髄を理解していれば、現在の.NET環境へ移行した際も、そのロジックは寸分違わず再現できる。
- イテレーションを減らせ:全走査は敗北である。
- メモリの所有権を意識せよ:COMオブジェクトを生成したら、必ず自身で責任を持って破棄する。
- 境界を定義せよ:座標計算の精度を軽視するな。
このコードをコピー&ペーストするだけでなく、なぜこの順序で実装されているのかを自問自答してほしい。それが、君が「コードを書く人」から「システムを設計する人」へ進化する境界線だ。
諸君の現場で、この知見が「処理落ち」という名の敗北を覆す武器になることを期待する。
