【AutoCAD VBAを掌握する極限の知見】図面整理を極限まで加速する!条件フィルタリングと画層一括移行のアーキテクチャ
業務自動化エンジニアの皆さん、日々の図面整理に消耗していないか?
「特定の画層にある、特定の色の線分だけを別の画層に一括で移したい」「膨大な図面オブジェクトから条件に合うものだけを秒速で抽出したい」――こうした要求に対し、手動で選択セットを作ったり、プロパティパレットを行ったり来たりしているようでは、プロのエンジニアとは言えない。
AutoCAD VBAにおいて、オブジェクトの走査と一括操作は「APIの重み」と「オブジェクトのライフサイクル」を正しく理解しているかどうかで、パフォーマンスと安定性が天と地ほど変わる。
今回は、実務の現場でそのまま稼働する、堅牢かつ洗練されたフィルタリング&画層移行スクリプトの全貌を授けよう。
—
1. なぜ素朴な `For Each` ループは実務で破綻するのか?
初学者や素人がやりがちなのが、`ActiveDocument.ModelSpace` を `For Each` で総なめし、条件分岐で `Layer` プロパティを書き換えるコードだ。
‘ 【アンチパターン】絶対に真似してはならないコード
Dim ent As AcadEntity
For Each ent In ThisDrawing.ModelSpace
If ent.Layer = “OLD_LAYER” And ent.Color = acRed Then
ent.Layer = “NEW_LAYER”
End If
Next ent
このコードの何が問題か?
1. COMのオーバーヘッドの嵐: AutoCADのCOMインターフェース経由で1つずつオブジェクトにアクセスするため、オブジェクト数が数万を超えると、ループのたびにCOM境界を跨ぐコストが発生し、画面がフリーズしたような重さに陥る。
2. トランザクションと図面更新の非効率: プロパティを変更するたびにグラフィックスの再描画やインデックスの更新が発生し得る。
プロが選ぶべきアプローチ:SelectionSetのネイティブフィルタ
AutoCADには、C++のCore層で高速に動作するSelectionSet(選択セット)のフィルター機能が備わっている。VBAからもこの機能(`Select`メソッドの引数)を呼び出すことが可能だ。
これを使えば、VBA側でループを回して条件判定するまでもなく、AutoCADのエンジン側が一瞬で条件に合致するオブジェクト群を抽出してくれる。
—
2. 堅牢な設計:存在しない画層のハンドリングとエラー対策
実務で動かすツールにおいて最も重要なのは、「想定外の入力」に対する耐性だ。
移動先の画層(ターゲット画層)が図面に存在しない場合、そのままプロパティを書き換えようとすればRuntimeエラー(実行時エラー)でマクロがクラッシュする。
したがって、以下の要件を満たす設計にする必要がある。
- ターゲット画層が存在しない場合は、自動的に新規作成する。
- 処理対象の画層や色、線種などの条件を柔軟に変更できるように定数・変数化する。
- 画面更新(`ScreenUpdating` 相当の制御)を一時停止し、処理速度を限界まで引き上げる。
—
3. 【プロダクションコード】条件フィルタリング&画層一括移行マクロ
以下のコードは、実務の現場で即座にコピー&ペーストして利用できる、極限まで最適化されたプロダクションコードだ。
Option Explicit
‘ ==============================================================================
‘ 処理名: 指定条件オブジェクトの画層一括移行プロシージャ
‘ 概要: モデル空間から指定された画層・色の条件に合致するエンティティを抽出し、
‘ 指定した新しい画層へ一括移動する。
‘ ==============================================================================
Public Sub FilterAndMoveToLayer()
‘ — 1. 条件設定(必要に応じてここを変更してください) —
Const TARGET_SOURCE_LAYER As String = “0” ‘ 検索対象の画層名 (空文字列””の場合は全画層対象)
Const TARGET_COLOR As Integer = 1 ‘ 検索対象の色番号 (1 = 赤)
Const DEST_LAYER As String = “M-MOVE-TO-HERE” ‘ 移動先の画層名
Dim doc As AcadDocument
Set doc = ThisDrawing
‘ 画面描画をロックしてパフォーマンスを最大化
doc.Application.Update
On Error GoTo ErrorHandler
‘ — 2. 移動先画層の存在確認と自動生成 —
Dim targetLayer As AcadLayer
On Error Resume Next
Set targetLayer = doc.Layers.Item(DEST_LAYER)
On Error GoTo ErrorHandler
If targetLayer Is Nothing Then
‘ 画層が存在しない場合は新規作成
Set targetLayer = doc.Layers.Add(DEST_LAYER)
‘ 必要に応じて色の初期設定などを行う (例: 緑色に設定)
targetLayer.Color = acGreen
MsgBox “移動先画層 ‘” & DEST_LAYER & “‘ が存在しなかったため、新規作成しました。”, vbInformation, “画層作成”
End If
‘ — 3. 選択セットの安全な生成と破棄 —
Dim ssName As String
ssName = “FilterMoveSet_” & Format(Now, “hhmmss”)
Dim sset As AcadSelectionSet
Set sset = CreateSafeSelectionSet(doc, ssName)
‘ — 4. フィルター条件の構築 (DXFグループコードを使用) —
Dim groupCode(1) As Integer
Dim dataValue(1) As Variant
Dim filterCount As Integer
filterCount = 0
‘ 条件1: 色コードの指定
groupCode(filterCount) = 62 ‘ DXF: カラー
dataValue(filterCount) = TARGET_COLOR
filterCount = filterCount + 1
‘ 条件2: 元画層の指定(必要に応じて追加)
If TARGET_SOURCE_LAYER <> “” Then
‘ 配列のサイズを動的に拡張
ReDim Preserve groupCode(filterCount)
ReDim Preserve dataValue(filterCount)
groupCode(filterCount) = 8 ‘ DXF: 画層名
dataValue(filterCount) = TARGET_SOURCE_LAYER
filterCount = filterCount + 1
End If
‘ — 5. 高速フィルタリング実行 —
‘ モデル空間全体から条件に合うものを一撃で抽出
sset.Select acSelectionSetAll, , , groupCode, dataValue
If sset.Count = 0 Then
MsgBox “条件に合致するオブジェクトは見つかりませんでした。”, vbExclamation, “処理終了”
GoTo CleanUp
End If
‘ — 6. 一括画層プロパティの書き換え —
Dim ent As AcadEntity
Dim movedCount As Long
movedCount = 0
‘ ここではCOMのオーバーヘッドを最小限にするため、一括ループでレイヤーを変更
For Each ent in sset
‘ ロックされている画層のオブジェクトは変更不可のためスキップ等のガードを入れるとさらに堅牢
If Not IsLayerLocked(doc, ent.Layer) Then
ent.Layer = DEST_LAYER
movedCount = movedCount + 1
End If
Next ent
‘ — 7. 完了通知 —
MsgBox “処理が完了しました。” & vbCrLf & _
“移動対象: ” & sset.Count & ” 件” & vbCrLf & _
“実際に移動した件数: ” & movedCount & ” 件” & vbCrLf & _
“移行先画層: ” & DEST_LAYER, vbInformation, “完了”
CleanUp:
‘ 選択セットの確実なクリーンアップ(メモリリーク防止)
Call ReleaseSelectionSet(doc, ssName)
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume CleanUp
End Sub
‘ ==============================================================================
‘ 補助関数: 既存の同名選択セットを確実に破棄して新規作成する
‘ ==============================================================================
Private Function CreateSafeSelectionSet(doc As AcadDocument, setName As String) As AcadSelectionSet
Dim sset As AcadSelectionSet
On Error Resume Next
‘ 既に存在する場合は取得して削除
Set sset = doc.SelectionSets.Item(setName)
If Not sset Is Nothing Then
doc.SelectionSets.Item(setName).Delete
End If
On Error GoTo 0
Set sset = doc.SelectionSets.Add(setName)
Set CreateSafeSelectionSet = sset
End Function
‘ ==============================================================================
‘ 補助関数: 選択セットを安全に削除する
‘ ==============================================================================
Private Sub ReleaseSelectionSet(doc As AcadDocument, setName As String)
On Error Resume Next
doc.SelectionSets.Item(setName).Delete
On Error GoTo 0
End Sub
‘ ==============================================================================
‘ 補助関数: 指定画層がロックされているか判定する
‘ ==============================================================================
Private Function IsLayerLocked(doc As AcadDocument, layerName As String) As Boolean
Dim lyr As AcadLayer
On Error Resume Next
Set lyr = doc.Layers.Item(layerName)
If Not lyr Is Nothing Then
IsLayerLocked = lyr.Lock
Else
IsLayerLocked = False
End If
On Error GoTo 0
End Function
—
4. コードの深掘り:エンジニアが押さえておくべきポイント
① DXFグループコードによる絞り込みの力
`groupCode(0) = 62` と `groupCode(1) = 8` という記述に注目してほしい。これはAutoCADの内部データベース(DXFフォーマット)で使われているグループコードを直接指定している。
VBA側でオブジェクトを一つずつ舐めてプロパティを評価するのではなく、AutoCADのコアエンジンにダイレクトに条件を投げるため、図面規模が大きくなればなるほど、このアプローチの圧倒的な速度優位性が体感できるはずだ。
② 選択セットのライフサイクル管理(重要)
AutoCAD VBAにおいて、`SelectionSets` コレクションは明示的に削除(`.Delete`)しない限り、図面ファイル内に残存し続ける。
これを怠ると、二回目以降のマクロ実行時に「既に同じ名前の選択セットが存在します」という致命的なエラーを引き起こす。
上記のコードでは、関数 `CreateSafeSelectionSet` および `ReleaseSelectionSet` を用意し、確実に作成と破棄を行うライフサイクル管理を徹底している。これがプロダクションクオリティだ。
③ 画層ロックへの配慮
実務図面では、誤操作を防ぐために特定の画層が「ロック」されていることがある。ロックされた画層にあるオブジェクトのプロパティを無理やり書き換えようとするとエラーになるか、意図しない挙動を引き起こす。
`IsLayerLocked` 関数を挟み込むことで、こうした実務特有のトラブルを未然に防ぐ堅牢性を担保している。
—
5. まとめ
AutoCAD VBAによる自動化は、単に「コードが動けばいい」というフェーズを脱し、「パフォーマンス」「メモリ管理(オブジェクトのライフサイクル)」「例外耐性」の3つを網羅したアーキテクチャで構築して初めて価値を持つ。
今回紹介したフィルタリング&一括移行テクニックは、図面整理だけでなく、検図スクリプトやBIM/CIMデータのクレンジングなど、あらゆる自動化の基盤となる強力なパターンだ。
自身の開発環境に組み込み、日々の業務効率を劇的に引き上げてほしい。さらなる極限の知見が必要なときは、またこの場を訪れるといい。
