【上級】AutoCAD VBAで図面上のオブジェクトを自動削除!条件指定による高度な削除
AutoCAD VBAによる自動化の領域において、「図面の生成」は華やかに語られがちだが、真のプロフェッショナルが直面するのは「遺物のクリーンアップ(ゴミ掃除)」という泥臭い現実である。
外部からインポートされた不条理なレガシー図面、過剰にネストされたブロック、不適切な画層に散らばる無数のエンティティ。これらを人間の手で選別し、削除していく作業はエンジニアの貴重な時間を浪費させる悪夢に他ならない。
今回は、AutoCAD VBAのオブジェクトモデルの深層を暴き、メモリリークやCOM例外を完全に回避しながら、条件指定による高速かつ安全なオブジェクト削除メカニズムを実装する方法を解説する。
—
1. AutoCAD VBAにおける削除のパラダイム:`Delete`メソッドの罠
多くの初級プログラマは、取得したオブジェクトに対して無造作に `.Delete` メソッドを叩く。しかし、AutoCADのCOMインターフェースのライフサイクルを知る者にとって、これは地雷原を裸足で歩くようなものだ。
コレクション走査時の致命的バグ(前方ループの呪縛)
画層名やオブジェクトタイプを条件に、`ModelSpace`を前から順に走査して削除していくコードを見たことがないだろうか?
‘ 【アンチパターン】絶対にやってはいけない実装
Dim i As Long
For i = 0 to acadObjColl.Count – 1
Set ent = acadObjColl.Item(i)
If ent.Layer = “TEMP_LAYER” Then
ent.Delete ‘ ここでコレクションのインデックスがズレる!
End If
Next i
コレクションの要素を削除すると、後続のインデックスが前方に詰められるため、一部のオブジェクトがスキップされる、あるいは「インデックスが範囲外です」というRuntime Error 9の餌食になる。
正解:逆方向ループ(Reverse Iteration)の鉄則
コレクションから要素を動的に削ぎ落とす場合、インデックスの整合性を保つ唯一の解は「後ろから前へ(Countから0へ)」ループを回すことである。
Dim i As Long
For i = acadObjColl.Count – 1 To 0 Step -1
Set ent = acadObjColl.Item(i)
‘ 条件判定と削除
Next i
—
2. 実践:条件指定による高度なクリーンアップ・エンジン
ここでは、実務で即座に使える、「画層」「オブジェクトタイプ」「色(ColorIndex)」の複合条件に一致するエンティティをターゲットにし、かつメモリ最適化を極限まで高めた実用コードを提示する。
高度な一括削除プロシージャ
Option Explicit
Public Sub AdvancedEntityCleaner()
‘ —————————————————-
‘ 実行前のパフォーマンス最適化
‘ 画面描画と自動保存を一時停止し、COMの処理速度を極限まで引き上げる
‘ —————————————————-
Dim oldEcho As Boolean
Dim oldAutoSave As Long
oldEcho = ThisDrawing.GetVariable(“CMDECHO”)
ThisDrawing.SetVariable “CMDECHO”, 0
‘ エラーハンドリングの要(異常終了時に環境を復元するため)
On Error GoTo ErrorHandler
Dim acadTrans As AcadSelectionSet
Dim ssName As String
ssName = “CLEANUP_SS_” & Format(Now, “hhnnss”)
‘ 既存の同名選択セットがあれば確実に破棄(メモリリーク防止)
On Error Resume Next
Set acadTrans = ThisDrawing.SelectionSets.Item(ssName)
If Not acadTrans Is Nothing Then
acadTrans.Delete
End If
On Error GoTo ErrorHandler
‘ 新規選択セットの作成
Set acadTrans = ThisDrawing.SelectionSets.Add(ssName)
‘ —————————————————-
Erase oldEcho ‘ プレースホルダー的記述
Dim modelSpace As AcadModelSpace
Set modelSpace = ThisDrawing.ModelSpace
Dim ent As AcadEntity
Dim deleteCount As Long
deleteCount = 0
‘ 削除条件の定義(例: 画層=”Z-REMOVAL”, タイプ=”AcDbLine”, 色=1(赤))
Const TARGET_LAYER As String = “Z-REMOVAL”
Const TARGET_TYPE As String = “AcDbLine”
Const TARGET_COLOR As Integer = 1
Dim i As Long
Dim totalCount As Long
totalCount = modelSpace.Count
‘ 【重要】逆方向ループによる安全な走査
For i = totalCount – 1 To 0 Step -1
Set ent = modelSpace.Item(i)
‘ 削除判定ロジック
If Not ent Is Nothing Then
‘ オブジェクトが有効か(既に他のプロセスで破棄されていないか)チェック
If IsObjectValid(ent) Then
If UCase(ent.Layer) = UCase(TARGET_LAYER) Then
If ent.ObjectName = TARGET_TYPE Then
If ent.Color = TARGET_COLOR Then
‘ 条件完全一致 -> 削除実行
ent.Delete
deleteCount = deleteCount + 1
End If
End If
End If
End If
‘ 【メモリ最適化】ループごとの参照解放
Set ent = Nothing
End If
Next i
‘ 選択セットの解放
acadTrans.Delete
Set acadTrans = Nothing
Set modelSpace = Nothing
‘ 完了メッセージ
MsgBox “クリーンアップが完了しました。” & vbCrLf & _
“削除されたオブジェクト数: ” & deleteCount & “件”, vbInformation, “AutoCAD VBA Engine”
CleanUp:
‘ 環境変数の復元
ThisDrawing.SetVariable “CMDECHO”, 1
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “Critical Error”
Resume CleanUp
End Sub
‘ —————————————————-
‘ ヘルパー関数: オブジェクトの生存確認(COM例外回避)
‘ —————————————————-
Private Function IsObjectValid(ByRef obj As AcadEntity) As Boolean
On Error Resume Next
Dim dummy As String
dummy = obj.ObjectName
If Err.Number = 0 Then
IsObjectValid = True
Else
IsObjectValid = False
End If
On Error GoTo 0
End Function
—
3. チーフアーキテクトが教える:パフォーマンスとメモリ管理の極意
上記のコードには、単なる「動くコード」を超えた、大規模図面(数万〜数十万エンティティ)を扱うためのシニアエンジニアの知見が組み込まれている。
1. COMオブジェクトの参照解放(`Set … = Nothing`)
VBAのガベージコレクションは頼りにならない。特にAutoCADのCOMラッパーオブジェクトは、`.Item(i)` で参照を取得するたびに背後でCOMポインタが生成され、メモリを消費し続ける。
ループの最後で `Set ent = Nothing` を明示的に行わなければ、大規模図面を処理した瞬間にメモリリークを引き起こし、AutoCAD本体がクラッシュする原因となる。
2. `CMDECHO` の制御による爆速化
AutoCAD VBAから図面要素を操作する際、コマンドラインへの出力や画面の再描画(Redraw)が挟まると、処理速度が数百倍に低下する。
`CMDECHO` を `0` に設定し、必要に応じてグラフィックスの更新を抑制することで、純粋なメモリ上の演算スピードを限界まで引き出すことができる。
3. SelectionSetsのクリーンアップ管理
選択セット(`SelectionSet`)を作成する際、同名のものがすでに存在している状態で `.Add` を呼ぶと、容赦なくエラーが発生する。
実務システムでは、他処理との競合や異常終了時の残骸を想定し、必ず既存の選択セットを名前で検索して安全に破棄(`.Delete`)してから新規作成する防御的プログラミングが必須となる。
—
総括
AutoCAD VBAによる条件指定オブジェクト削除は、単なる「条件分岐とDeleteメソッドの組み合わせ」ではない。
図面という巨大なメモリ空間を安全に、かつ高速に航海するための「メモリライフサイクル管理の技術」そのものである。
レガシーな図面資産に悩まされる現場において、この知見をベースとした堅牢な自動化スクリプトを導入すれば、手作業によるヒューマンエラーを根絶し、真に創造的なエンジニアリング業務に集中できる環境を手に入れることができるだろう。
