凡人の「差分比較」を卒業せよ:DWG Compareを自動化するアーキテクチャ設計論
「新旧の図面を比較して、変更箇所を特定し、結果を保存する」
実務において、このタスクを依頼されることは多い。しかし、多くの開発者が陥る致命的なミスがある。それは、「VBAで全てのエンティティをループで回し、座標やレイヤーを一つずつ比較しようとする」ことだ。
もし君がそんなコードを書こうとしているなら、今すぐその手を止めろ。それは、砂漠で一粒ずつ砂を数えるような、無意味で、極めてパフォーマンスの低い、そして脆弱な設計だ。
AutoCADには、強力な比較エンジンである`DWGCOMPARE`コマンドが既に存在する。我々エンジニアの仕事は、そのエンジンを「どう制御し、どう結果を業務プロセスに組み込むか」というオーケストレーション(指揮)にある。
本稿では、単なるコードの書き方ではなく、業務で耐えうる「堅牢な自動比較システム」の設計思想を伝授する。
1. なぜ「エンティティ比較ループ」はゴミなのか
まず、設計の前提となる「失敗のパターン」を叩き込んでおく。
多くの初級者は、`For Each obj In ModelSpace` を使い、新旧図面のオブジェクトを比較しようとする。しかし、このアプローチには以下の致命的な欠陥がある。
1. IDの不一致: 図面を一度でも保存し直したり、別のソフトを経由したりすると、オブジェクトのハンドル(Handle)やIDは変わる。
2. 計算量の爆発: 数万個のオブジェクトを持つ図面で、二重ループ(O(n²))を回せば、AutoCADはフリーズしたように沈黙する。
3. 比較精度の限界: 線分(Line)がポリライン(Polyline)に変換されていた場合、属性比較だけでは「変更」を正しく検知できない。
プロフェッショナルの解:
AutoCADのネイティブコマンドである`DWGCOMPARE`を`SendCommand`経由で叩く。これにより、AutoCAD内部の高度な幾何学解析エンジンをそのまま利用し、計算負荷と精度問題を同時に解決する。
2. 堅牢な設計:3つのレイヤー
実務ツールを作るなら、コードを「ファイル操作」「コマンド実行」「エラーハンドリング」の3層に分離して設計すべきだ。
① ファイル管理層 (File Management Layer)
パスの妥当性、ファイルの存在確認、書き込み権限のチェックを行う。ファイルが存在しない、あるいは他のユーザーがロックしている状態でコマンドを投げれば、即座にシステムはクラッシュする。
② コマンド制御層 (Command Control Layer)
`SendCommand`は強力だが、非同期的に動作する。コマンドが完了する前に次の処理へ進むと、予期せぬ挙動を引き起こす。コマンドの実行タイミングと、図面状態の同期を制御する必要がある。
③ ライフサイクル管理層 (Lifecycle Management Layer)
比較が終わった後、比較結果を表示したままにするのか、それとも特定の名前で「差分図面」として保存するのか。図面のOpen/Closeのライフサイクルを厳格に管理し、メモリリークやゾンビプロセスを防ぐ。
3. 実装:プロダクション・クオリティの比較エンジン
以下に、実務でそのまま使えるレベルのコード構造を示す。これは、単なる比較ではなく、「新旧図面を比較し、結果を特定の名前で保存する」というワークフローを完結させるための設計だ。
'**
' Module: AutomationEngine
' Description: 高度なDWG比較および結果保存プロセス
' Author: Chief Architect
'**
Option Explicit
' ファイル操作のための参照設定: Microsoft Scripting Runtime
' (ツール -> 参照設定 から追加すること)
Public Sub ExecuteAutomatedComparison()
Dim fso As New FileSystemObject
Dim oldDocPath As String
Dim newDocPath As String
Dim resultDocPath As String
Dim targetFolder As String
' --- 1. 設定セクション (本来はExcelやDBから取得すべき) ---
oldDocPath = "C:\Project\Drawing_V1.dwg"
newDocPath = "C:\Project\Drawing_V2.dwg"
targetFolder = "C:\Project\Comparison_Results\"
' 結果の保存先パスを生成 (例: Drawing_V1_vs_V2_Diff.dwg)
resultDocPath = targetFolder & "Diff_" & _
fso.GetBaseName(oldDocPath) & "_vs_" & _
fso.GetBaseName(newDocPath) & ".dwg"
' --- 2. 事前バリデーション (ガード句) ---
On Error GoTo ErrorHandler
If Not fso.FileExists(oldDocPath) Then Err.Raise 53, , "旧図面が見つかりません: " & oldDocPath
If Not fso.FileExists(newDocPath) Then Err.Raise 53, , "新図面が見つかりません: " & newDocPath
If Not fso.FolderExists(targetFolder) Then fso.CreateFolder (targetFolder)
' --- 3. 比較プロセスの実行 ---
Debug.Print "Comparison Started: " & Now
' AutoCADのメインプロセスへ制御を移す
PerformCompare oldDocPath, newDocPath
' ※注意: DWGCOMPAREコマンド自体は「現在の図面」に「別の図面」を重ねる挙動をする。
' 比較結果を「ファイル」として残すには、比較モードの後に
' 変更箇所を抽出する、あるいは比較状態の図面をSaveAsする戦略をとる。
' ここでは、比較を実行した後の図面を「差分結果」として保存するフローを想定
ThisDrawing.SaveAs resultDocPath
MsgBox "比較プロセスが正常に完了しました。" & vbCrLf & "保存先: " & resultDocPath, vbInformation
ExitSub:
Set fso = Nothing
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました。" & vbCrLf & _
"Error No: " & Err.Number & vbCrLf & _
"Description: " & Err.Description, vbCritical
Resume ExitSub
End Sub
''' <summary>
''' AutoCADのネイティブコマンドを使用して比較を実行する
''' </summary>
Private Sub PerformCompare(ByVal oldPath As String, ByVal newPath As String)
' DWGCOMPAREコマンドは、現在開いている図面に対して、
' 比較対象のパスを引数として渡すことで動作する。
' 1. まず、比較のベースとなる「旧図面」を開く
Dim docOld As AcadDocument
Set docOld = Documents.Open(oldPath)
' 2. 比較コマンドの実行
' SendCommandは文字列をコマンドラインに直接打ち込む。
' 引数として比較対象(newPath)を渡す。
' 文末のスペースはEnterキーの代わり。
docOld.SendCommand "DWGCOMPARE " & Chr(34) & newPath & Chr(34) & " "
' 3. コマンドが完了するまで待機するロジックが必要な場合があるが、
' DWGCOMPAREはUI制御が強いため、基本的にはコマンド実行後に
' 図面が「比較モード」に移行した状態になる。
' 注意: VBAからDWGCOMPAREの「結果オブジェクト」に直接触るAPIは公開されていない。
' そのため、UI上の比較結果を維持したままSaveAsを行うのが最も現実的な自動化である。
End Sub
4. 実務における「落とし穴」と回避策
このコードをプロダクション環境に投入する際、以下の3点に留意せよ。
A. `Chr(34)`(ダブルクォーテーション)の徹底
パスにスペースが含まれている場合(例: `C:\My Project\Drawing.dwg`)、`SendCommand`に渡すパスを `”` で囲まなければ、コマンドはパスの途中で途切れてエラーになる。`Chr(34)` を使うのは、プロの作法だ。
B. ファイルロックのハンドリング
比較対象の図面が他のユーザーによって開かれている場合、`Documents.Open` は失敗する。実務ツールでは、`On Error` で捕捉し、「ファイルが使用中です。担当者に確認してください」といった人間が次に何をすべきかを示すメッセージを返すように設計しろ。
C. 比較結果の「保存」に関する思想
`DWGCOMPARE` は、現在の図面の表示状態(View)を変化させるものだ。
もし君のクライアントが「変更されたオブジェクトだけを抜き出した新しい図面が欲しい」と言ってきた場合、`DWGCOMPARE` だけでは不十分だ。その場合は、比較コマンド実行後に、「比較結果のレイヤー(DWGCOMPARE_…)」に属するオブジェクトのみを抽出し、新しい図面にコピーするという追加ロジックが必要になる。
5. 結論:エンジニアとしての矜持
自動化とは、単に作業を速くすることではない。「人間がミスをする余地を、設計によって排除すること」だ。
エンティティを一つずつ比較するコードを書くのは、エンジニアの仕事ではない。それは単なる「作業のコード化」だ。AutoCADが持つ最強のエンジンを理解し、それをいかに安全に、いかに確実に制御するか。それこそが、アーキテクトに求められる資質である。
この設計思想を胸に、次なる自動化プロジェクトに挑んでほしい。
