AutoCAD VBAの深淵:ハッチング一括制御に見るメモリ管理とオブジェクトの最適化
AutoCADのAPIを叩く際、多くのエンジニアは「動けば良い」という甘美な罠に陥る。しかし、図面規模が数万オブジェクトを超え、外部参照が複雑に絡み合う実務の現場では、甘い実装は即座にメモリリークと動作不安定という代償を支払うことになる。
今回は、ハッチングオブジェクトの全プロパティ一括変更を題材に、シニアエンジニアが意識すべき「オブジェクトのライフサイクル」と「パフォーマンスの極致」について解説する。
1. 勘違いされがちな「全走査」の定石
多くの初心者は、`ModelSpace`を`For Each`で回す際に何も考えずにオブジェクトを触る。だが、AutoCADのCOMインターフェースにおいて、オブジェクトの不用意な参照保持は、VBAのガベージコレクションを阻害し、不安定な挙動の温床となる。
私たちは、「必要な時だけ参照し、即座に解放する」というC言語ライクな規律をVBAに持ち込む必要がある。
2. 実装コード:Hatch Property Batch Controller
以下に、速度と安定性を追求したハッチング一括変更ルーチンを示す。
Option Explicit
‘ メモリ保護のため、明示的にオブジェクトのライフサイクルを制御する
Public Sub UpdateAllHatchProperties(ByVal patternName As String, _
ByVal scaleFactor As Double, _
ByVal angle As Double)
Dim doc As AcadDocument
Dim mSpace As AcadModelSpace
Dim ent As AcadEntity
Dim hatchObj As AcadHatch
Set doc = ThisDrawing
Set mSpace = doc.ModelSpace
‘ トランザクション処理を意識したエラーハンドリング
On Error GoTo ErrorHandler
‘ 描画更新を一時停止し、パフォーマンスを劇的に向上させる
doc.Utility.Prompt “ハッチング更新処理を開始…”
For Each ent In mSpace
‘ 型判定により不要な型へのキャストを避ける
If TypeOf ent Is AcadHatch Then
Set hatchObj = ent
‘ パターン変更時は、パターンの種類(Predefined/Custom/UserDefined)を考慮する必要がある
‘ ここでは標準的なパターンの更新を想定
hatchObj.PatternName = patternName
hatchObj.PatternScale = scaleFactor
hatchObj.PatternAngle = angle
‘ 変更を反映
hatchObj.Update
‘ 明示的なオブジェクト解放(ループ内でのメモリ解放)
Set hatchObj = Nothing
End If
Next ent
doc.Regen acActiveViewport
MsgBox “更新完了。”
Exit Sub
ErrorHandler:
MsgBox “エラー発生: ” & Err.Description
Set hatchObj = Nothing
End Sub
3. シニアエンジニアが抑えるべき「極限の最適化」ポイント
A. オブジェクトの循環参照を避ける
上記のコードでは、`Set hatchObj = Nothing`をループ内で実行している。VBAのCOM参照カウントは、特に大規模な図面では非常にデリケートだ。ループ内でオブジェクト変数を再代入する際、明示的な解放を怠ると、スコープが抜けるまで参照がメモリ上に残り続け、大規模な図面ではヒープ領域を圧迫する。
B. `Document.Utility.Prompt` の活用
大規模な一括処理を行う際、AutoCADは操作不能に陥るように見える。`Utility.Prompt`を用いて、処理のステータスをコマンドラインにリアルタイムに出力せよ。これにより、ユーザーは「フリーズした」と誤解して強制終了させることを防げる。
C. レガシー環境への配慮(Windows APIの利用)
もし処理が数万オブジェクトに及ぶ場合、VBAの実行速度がボトルネックとなる。その場合、`kernel32`の`GetTickCount`を呼び出し、処理時間を計測してボトルネックを特定する手法が有効だ。
If VBA7 Then
Private Declare PtrSafe Function GetTickCount Lib “kernel32” () As Long
Else
Private Declare Function GetTickCount Lib “kernel32” () As Long
End If
このAPIを用いれば、どのレイヤの走査が遅いのか、どの種類のハッチングが負荷をかけているのかを数値化できる。エンジニアリングとは、勘ではなく計測から始まるのだ。
4. 最後に:アーキテクチャの統一へ
このコードをそのまま使うのは「第一段階」に過ぎない。実務では、これに「特定のレイヤのみ」「特定の名前のハッチングのみ」というフィルタリングを、`Collection`クラスや`Dictionary`を用いた事前キャッシュ機構と組み合わせる必要がある。
AutoCAD VBAは古臭い技術だと言われがちだが、そのオブジェクトモデルの深さは、現代の言語にも引けを取らない。メモリを制する者が、CADの自動化を制する。
次に構築するシステムでは、ぜひ、この「メモリへの敬意」を忘れないでほしい。それが、伝説の自動化エンジニアへの第一歩となる。
