【実務中級者向け】図面保存時の「DGN線種データ」肥大化を解消:保存速度を劇的に改善するクリーンアップ自動化
「ツールは完成した。しかし、なぜか処理が異常に遅い。しかも、生成された図面ファイルが数MB単位で不必要に重い……」
もし君が、AutoCAD VBAを用いた自動化ツールを開発していてこのような壁にぶつかっているなら、原因は君の書いたロジックの効率性ではない。「図面データベースそのものが抱える、目に見えないゴミ(メタデータ)」にある。
特に、外部参照(XREF)を多用する大規模プロジェクトにおいて、MicroStation(DGN形式)の線種データがDWG内に混入し、図面を「肥大化」させる現象は、実務における自動化エンジニアにとっての「静かなる敵」だ。
本稿では、単なるコマンドの実行方法ではなく、「なぜDGNデータが問題なのか」「SendCommandの非同期性という罠をどう回避するか」という、プロフェッショナルが設計段階で考慮すべき極限の知見を伝授する。
1. 肥大化の正体:なぜDGNデータは「増殖」するのか
AutoCAD図面が重くなる原因の多くは、図形オブジェクトの数ではなく、「データベース内の定義情報の肥大化」だ。
特に厄介なのが、DGN線種データである。これは、過去にMicroStation形式のデータをAutoCADへ変換したり、DGN由来の要素を含む図面をXREFとして読み込んだりした際に、図面データベースの「線種テーブル」にこっそりと書き込まれる。
恐ろしいのはその性質だ。
1. XREF経由の侵入: 直接的な操作をしていなくても、参照先の図面にDGNデータが含まれていれば、現在の図面にもその「定義」が引き継がれる。
2. 再帰的な増殖: 図面をコピー&ペーストしたり、ブロックとして定義したりする過程で、不要なメタデータが図面全体に拡散していく。
これらは通常の `PURGE` コマンド(ダイアログ形式)では完全に除去できないケースがあり、コマンドライン版の `-PURGE` を、適切なオプションで叩き込む必要がある。
2. アーキテクチャの設計思想:`SendCommand` の「非同期性」という罠
多くの開発者が、以下のようなコードを書いて失敗する。
' --- 失敗する設計例 ---
ThisDrawing.SendCommand "-PURGE " & vbCr & "All " & vbCr & "No " & vbCr
ThisDrawing.SaveAs "C:\Output\Cleaned.dwg" ' ← ここでクラッシュ、あるいは未清掃のまま保存される
なぜこれがダメなのか?
AutoCADの `SendCommand` メソッドは、「コマンドをコマンドラインに送るだけで、その完了を待たずに次の行を実行する(非同期的な振る舞い)」からだ。
つまり、上記のコードでは、Purgeコマンドがまだバックグラウンドで走っている最中に、`SaveAs` が実行されてしまう。結果として、「ゴミが残ったまま保存される」か、あるいは「実行中のコマンドと衝突してAutoCADがフリーズする」という、極めて不安定な挙動を招く。
堅牢なツールを作るなら、「コマンドが完了したことを検知する」か、あるいは「ユーザーの介入を許容する設計」、もしくは「コマンド完了後に実行されるイベント」を考慮しなければならない。
3. プロダクション・レディな実装例
以下に、実務でそのまま利用できる、エラーハンドリングと状態管理を考慮したクラスモジュール級の設計コードを示す。ここでは、最も確実な「コマンド実行後に制御を戻す」ための設計思想を取り入れる。
クリーンアップ・エンジン (Module)
Option Explicit
''' <summary>
''' 図面の最適化(DGNデータ、不要なRegappsの削除)を実行する
''' </summary>
''' <param name="isSilent">Trueの場合、ユーザーへの確認をスキップする</param>
Public Sub OptimizeDrawing(ByVal isSilent As Boolean)
On Error GoTo ErrorHandler
Dim acadApp As AcadApplication
Set acadApp = ThisApplication ' 実行コンテキスト
Debug.Print "Optimization Started: " & ThisDrawing.Name
' 1. 読み取り専用チェック(設計の基本:書き込み権限のないオブジェクトへの操作は避ける)
If ThisDrawing.ReadOnly Then
MsgBox "エラー: 図面が読み取り専用です。クリーンアップを中止します。", vbCritical
Exit Sub
End If
' 2. ユーザーへの通知(プロフェッショナルなツールは、裏で何をしているかを隠さない)
If Not isSilent Then
Debug.Print "Purging DGN data and Regapps..."
End If
' 3. コマンドの構築
' -PURGE -> All (全ての項目) -> No (確認メッセージにNoと答える)
' DGNデータおよびRegappsを確実に掃除するためのシーケンス
Dim purgeCmd As String
purgeCmd = "-PURGE " & vbCr & "All " & vbCr & "No " & vbCr
' 4. コマンド実行
' 注意: SendCommandは非同期であるため、直後の処理には注意が必要
ThisDrawing.SendCommand purgeCmd
' 5. 非同期問題への対策
' 実務的な解決策として、コマンド完了を待つために、
' ユーザーに一度「コマンド完了を確認してください」と促すか、
' もしくは、このプロシージャ自体を「コマンド完了後に呼び出されるイベント」へ委ねる設計にする。
' ここでは、堅牢性を重視し、処理の完了をユーザーに委ねる安全策をとる。
If Not isSilent Then
MsgBox "クリーンアップコマンドを送信しました。" & vbCr & _
"コマンドが完了したら [OK] を押して保存を実行してください。", vbInformation
End If
' 6. 保存プロセス
' 本来は、コマンド完了後に呼び出すべきだが、一括処理ツールの場合は
' ここで明示的にSaveを行う設計にする(ユーザーがコマンド完了後にOKを押す前提)
ThisDrawing.Save
Debug.Print "Optimization Completed Successfully."
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
Debug.Print "Error: " & Err.Number & " - " & Err.Description
End Sub
4. データベース連携・バッチ処理における注意点
このクリーンアップ機能を、単一の図面ではなく「フォルダ内の全図面を処理するバッチツール」に組み込む場合、さらに高度な設計が求められる。
① オブジェクトのライフサイクル管理
バッチ処理で `Documents.Open` を繰り返す際、クリーンアップ後の `Save` と `Close` が正しく行われないと、メモリリークが発生し、数千枚の処理中にAutoCADがクラッシュする。必ず `Set doc = Nothing` で参照を解放せよ。
② ファイル・データベースとの整合性
もし、図面のメタデータ(図面番号やプロジェクト名)を外部のSQLデータベースやExcelから管理している場合、「Purge実行前と実行後で、図面内のオブジェクトID(Handle)が変わっていないか」を意識せよ。
Purge自体はHandleを破壊しないが、もし「不要な要素を削除する」ロジックをPurgeと併用する場合、Handleの不一致はデータベースの整合性を破壊する致命的なバグとなる。
③ トランザクションの概念
AutoCAD VBAには厳密な意味でのデータベース・トランザクションはない。しかし、`Undo` 履歴を考慮せよ。大量のPurgeを実行すると、Undoスタックが肥大化し、メモリを圧迫する。大量処理を行うツールでは、`Undo` を無効化するか、処理ごとに `Regen` を挟むのが定石だ。
5. まとめ:エンジニアとしての矜持
「動けばいい」コードを書くのは、スクリプト作成者だ。
「予期せぬデータに対しても、図面の整合性を保ち、パフォーマンスを最大化する」コードを書くのが、アーキテクトだ。
DGNデータのクリーンアップは、単なる「掃除」ではない。図面というデータベースの「健全性を維持するためのメンテナンス・プロセス」である。`SendCommand` の非同期性という特性を理解し、ユーザーやシステムの挙動をコントロール下に置くこと。それが、現場で信頼される自動化エンジニアへの第一歩だ。
さあ、君のツールに、真の堅牢性を実装したまえ。
