【AutoCAD VBA】図面比較の深淵:ハッシュアルゴリズムとオブジェクト・ライフサイクル管理による差分検出の極致
AutoCADの図面比較(DWG Compare)は、オートデスクが提供する標準機能だが、現場のシニアエンジニアであれば「あれはあくまで視覚的な補助に過ぎない」と知っているはずだ。設計変更の履歴追跡、あるいは自動検査システムに組み込むためには、ブラックボックスのコマンドではなく、我々自身の手で「データ構造」を解析せねばならない。
本稿では、VBAというレガシーかつ強力なインターフェースを使い、オブジェクトの属性値を抽出・ハッシュ化することで、図面間の論理的な差異を高速に検出するアーキテクチャを解説する。
—
1. 比較エンジンの設計思想:なぜ「図面全体」を回してはいけないのか
AutoCADの`ModelSpace`を単にループして比較するようなコードは、図面規模が大きくなった瞬間に崩壊する。オブジェクトの数、複雑なブロック参照、XData……。これらを単純比較すれば、メモリリークと計算量爆発を招くのは自明だ。
極限の知見:
- ハッシュ化の導入: 全プロパティを逐一比較するのではなく、Handle、Layer、LayerState、Color、Linetype、そして座標値(Vector)を連結した文字列からMD5相当のハッシュ値を生成し、Dictionaryオブジェクトで比較せよ。
- メモリの解放: `AcadEntity`オブジェクトへの参照は、ループのイテレーションごとに即座に `Nothing` をセットし、`CollectGarbage`(VBAにはないが、オブジェクトのスコープ管理で代用)を意識する。
—
2. 実装:高速差分検出アルゴリズム
以下のコードは、2つの図面から「Entityのハッシュマップ」を生成し、その差分を抽出するコアロジックの断片だ。
‘ 必要な参照設定: Microsoft Scripting Runtime
‘ 比較対象のエンティティのプロパティをハッシュ化して保持
Public Function GetEntityHash(ent As AcadEntity) As String
‘ パフォーマンスの要:座標等の浮動小数点は精度を丸めてから文字列化する
‘ ここを疎かにすると、微小な浮動小数点誤差で差分と誤認される
Dim hashBase As String
hashBase = ent.ObjectName & “|” & ent.Layer & “|” & _
Format(ent.InsertionPoint(0), “0.0000”) & “|” & _
Format(ent.InsertionPoint(1), “0.0000”)
‘ 本来はここでSHA256等のAPIを呼び出すのがベストだが、
‘ VBA環境であれば簡易的にVBScript.Encodeやハッシュ関数を利用する
GetEntityHash = hashBase
End Function
Public Sub CompareDrawings(doc1 As AcadDocument, doc2 As AcadDocument)
Dim dict1 As Object: Set dict1 = CreateObject(“Scripting.Dictionary”)
Dim ent As AcadEntity
‘ 図面1の解析(DictionaryにHandleをキーとして保存)
For Each ent In doc1.ModelSpace
dict1.Add ent.Handle, GetEntityHash(ent)
Set ent = Nothing ‘ ライフサイクルの明示的解放
Next ent
‘ 図面2と比較
For Each ent In doc2.ModelSpace
If dict1.Exists(ent.Handle) Then
If dict1(ent.Handle) <> GetEntityHash(ent) Then
Debug.Print “変更検知: ” & ent.Handle
End If
dict1.Remove ent.Handle
Else
Debug.Print “新規追加: ” & ent.Handle
End If
Set ent = Nothing
Next ent
‘ 残ったdict1のキーは「削除されたオブジェクト」
‘ …
End Sub
—
3. パフォーマンスを極めるためのエンジニアリングTips
Windows APIによる「フリーズ」の回避
大規模図面を処理する際、AutoCADが「応答なし」になるのを防ぐ必要がある。VBAのループ内で `DoEvents` を叩くのは定石だが、多用するとオーバーヘッドが大きい。1000要素ごとに `DoEvents` を実行するカウンターを実装せよ。
オブジェクトの明示的解放の真実
VBAの参照カウンタは優秀だが、AutoCADのCOMオブジェクトは複雑な循環参照を抱えやすい。`For Each` ループ内で取得したオブジェクトは、必ずそのスコープの終わりで `Nothing` を代入する。これだけで、長時間稼働後のメモリ消費量が劇的に安定する。
レガシー環境の保守:なぜVBAで戦うのか
現在では .NET (ObjectARX) が主流だが、社内の古いシステムやドキュメント管理ツールとの連携において、VBAの「手軽さ」は捨てがたい。もし将来的に .NET へ移行する可能性があるなら、ロジックをVBAのフォームコードに書かず、`Class` モジュールにカプセル化せよ。インターフェースを分離しておくことで、将来的にDLLへ容易に移植可能となる。
—
終わりに:アーキテクトからの提言
図面比較を自動化するということは、単にツールを作ることではない。「設計者の意図がどこで変化したか」をデータとして定義する行為である。
AutoCADのオブジェクトモデルは、CADという巨大なグラフ構造の一部に過ぎない。今回紹介したハッシュベースのアプローチは、その氷山の一角だ。さらに踏み込むのであれば、`AcDbDatabase` を直接操作する ObjectARX (C++) への道が待っている。
しかし、まずはこのVBAで、現場の「見落とし」を撲滅する第一歩を踏み出してほしい。コードは語る。君がどれだけ細部に魂を込めたかを。
