AutoCAD VBAを掌握する:図面比較自動化の極意――「差分」を制する者は設計品質を制する
設計変更の嵐の中で、手作業の図面比較に命を削っていないだろうか?「A図面とB図面、どこが変わったのか?」という問いに対し、目視で追うのはエンジニアの仕事ではない。それはAutoCADという強力なエンジンに任せるべきタスクだ。
今回は、AutoCAD VBAを用いた「差分検出」のアーキテクチャを解説する。単にオブジェクトをなめるだけのスクリプトではない。大規模図面でも破綻せず、かつ実務で耐えうる「堅牢な比較ロジック」の神髄を伝授する。
—
1. なぜ「力技の比較」は失敗するのか
多くの初心者が陥る罠は、「すべてのオブジェクトを力技でループして比較する」という設計だ。
- 非効率な設計の末路: オブジェクト数万個をメモリにロードし、総当たりで比較すれば、AutoCADは確実にハングアップする。
- IDの罠: `Handle` はコピーやブロック化で変化する可能性がある。これを唯一の頼りにするのは脆弱だ。
プロフェッショナルがとるべき戦略
1. ハッシュベースの比較: オブジェクトの主要プロパティ(挿入点、半径、画層、色等)を文字列化し、ハッシュ値(またはそれに準ずるキー)を生成する。
2. 空間インデックスの活用: 全領域を走査するのではなく、バウンディングボックスの範囲で絞り込む。
3. 辞書オブジェクトの利用: VBAの `Scripting.Dictionary` を使い、O(1)の計算量で検索を行う。
—
2. 実装:差分検出エンジン(プロダクションコード)
以下のコードは、2つの図面を開いた状態で、「モデル空間内の円(Circle)」の差分を検出するプロトタイプだ。実務ではこれをポリラインやブロックに拡張してほしい。
‘ 参照設定: Microsoft Scripting Runtime を追加すること
Option Explicit
Public Sub CompareDrawings()
Dim docOld As AcadDocument, docNew As AcadDocument
Dim dictOld As New Scripting.Dictionary
Dim ent As AcadEntity
Dim key As String
‘ 図面が2つ開かれている前提
Set docOld = Application.Documents.Item(0)
Set docNew = Application.Documents.Item(1)
‘ 1. 旧図面の円を辞書に登録 (Key: 中心点と半径の文字列)
For Each ent In docOld.ModelSpace
If TypeOf ent Is AcadCircle Then
key = GetCircleKey(ent)
If Not dictOld.Exists(key) Then dictOld.Add key, True
End If
Next
‘ 2. 新図面を走査し、旧図面に存在しないものをハイライト
For Each ent In docNew.ModelSpace
If TypeOf ent Is AcadCircle Then
key = GetCircleKey(ent)
If Not dictOld.Exists(key) Then
‘ 差分発見!赤色に変更して目立たせる
ent.Color = acRed
ent.Update
End If
End If
Next
MsgBox “比較完了:変更・追加箇所を赤色でマークしました。”
End Sub
‘ ハッシュ用キー生成関数(浮動小数点の誤差を考慮し丸める)
Private Function GetCircleKey(cir As AcadCircle) As String
GetCircleKey = Format(cir.Center(0), “0.000”) & “|” & _
Format(cir.Center(1), “0.000”) & “|” & _
Format(cir.Radius, “0.000”)
End Function
—
3. 実務で「壊れない」ための3つの鉄則
① 浮動小数点の誤差を殺せ
`Double` 型の比較は `If a = b Then` では絶対に機能しない。`Format` 関数で文字列に落とし込むか、許容誤差(Epsilon)を用いた比較関数を自作すること。上記のコードでは `Format` を用いて簡易的な正規化を行っている。
② データベース/ログ出力の連携
比較結果を単に色を変えるだけで終わらせてはいけない。
- ログ出力: 差分をCSVに書き出し、Excelで「設計変更履歴一覧」として自動生成する。
- レイヤー管理: 差分オブジェクトを自動的に「DIFF_CHECK」という専用レイヤーに移動させると、設計者が後で一括管理しやすくなる。
③ COMオブジェクトのライフサイクル管理
`For Each` ループ内でオブジェクトを削除したり移動したりすると、イテレータが崩壊する可能性がある。
- 削除・修正はスタックする: ループ内では「対象リスト(コレクション)」を作成するだけに留め、ループ終了後に一括処理する設計が、予期せぬクラッシュを防ぐ唯一の道だ。
—
結論:自動化は「思考」を省略することではない
AutoCAD VBAで比較ツールを作る目的は、単に「楽をする」ことではない。「人間が判断すべきクリティカルな変更点」を浮き彫りにし、設計者が本来集中すべき「設計品質」に時間を割かせることにある。
まずはこのコードをベースに、自社の標準画層やブロック属性に対応させてみてほしい。それが、君のエンジニアとしての価値を一段引き上げるはずだ。
コードは嘘をつかない。だが、設計思想が甘ければコードは裏切る。常に「もし数万オブジェクトあったらどうなるか?」という視点を忘れずに開発を続けてくれ。検討を祈る。
