【実務・中級編】【上級】AcadDocument.Databaseオブジェクト深掘り:Undo/Redoスタックを考慮したトランザクション的な処理の実装 – AutoCAD VBA解析バイブル

スポンサーリンク

【上級】AcadDocument.Databaseオブジェクト深掘り:Undo/Redoスタックを考慮したトランザクション的な処理の実装

こんにちは。大規模なプラント設計からインフラ、BIM/CIMデータに至るまで、AutoCADの限界領域をVBAとCOMインターフェースでねじ伏せてきたチーフアーキテクトの私だ。

日々の業務自動化(RPA)において、数千・数万の図形を一括生成・改修するマクロを書いた経験はあるだろうか?
その際、処理が終わった後に図面を見て「あ、やっぱりこれ全部なかったことにしたい(Ctrl + Z)」と思ったユーザーが、「元に戻す」を200回連打しなければならなかった……なんていう惨事を引き起こしたことはないか?

プロとして現場にツールを納品するなら、このような「ユーザー体験の破壊」と「メモリの無駄遣い」は絶対に許されない。
今回は、AutoCADの裏側に鎮座する `Database` オブジェクトと、Undo/Redoスタックを完全に掌握するための極限の知見を授けよう。

1. なぜ「個別の図形操作」をそのままループさせてはいけないのか

多くの初学者は、次のようなコードを書く。

‘ 【アンチパターン】絶対にやってはいけない実装
Dim i As Long
For i = 1 to 10000
‘ ループの回数分、Undoスタックにトランザクションが個別蓄積される
Dim ent As AcadEntity
Set ent = ThisDrawing.ModelSpace.AddLine(…)
Next i

このコードの問題点はお分かりだろうか。
AutoCADは、図形を追加・変更するたびに、内部の `Database` が持つUndo/Redoスタックへ「1操作」としての履歴をガンガン積み上げていく。

結果として何が起きるか?
1. パフォーマンスの著しい低下:履歴の生成とメモリ管理のオーバーヘッドで、ループ処理が異様に遅くなる。
2. Undo/Redoの崩壊:ユーザーが「Ctrl + Z」を1回押しても、1万本引いた線のうち「たった1本」しか消えない。全キャンセルには1万回の「Ctrl + Z」が必要になり、最悪の場合はAutoCADがメモリ不足でクラッシュする。

これを防ぐ唯一の解法が、「Undoマーク(Undo Mark)」の戦略的配置である。

2. 戦略的アプローチ:`StartUndoMark` と `EndUndoMark`

AutoCAD VBAでは、`AcadDocument`(あるいは `AcadDatabase`)に対して「ここからここまでを1つの不可分なトランザクション(不可逆な一塊の処理)として扱え」と明示的に指示することができる。

それが以下の2つのメソッドだ。

  • `ThisDrawing.StartUndoMark()` : 仮想的なトランザクションの開始
  • `ThisDrawing.EndUndoMark()` : 仮想的なトランザクションの終了

この間に実行された数万回のオブジェクト生成・削除は、AutoCADのUndoスタック上では「たった1つのアクション」としてまとめられる。
ユーザーが「元に戻す」を1回実行すれば、マクロが実行した全変更が一瞬でロールバックされるのだ。データベースの整合性を担保する上でも、これは業務アプリ開発の必須要件である。

3. 【プロダクションコード】堅牢な一括処理テンプレート

ここからは、実務の現場でそのままコピー&ペーストして使える、堅牢性と保守性を極限まで高めたコードを提示する。

エラーハンドリング(`On Error Goto`)をサボるプログラマは、私のチームにはいらない。トランザクション中に予期せぬエラーでマクロが落ちた場合、Undoマークが閉じられずにAutoCADのセッション全体が不安定になる(あるいはコマンドがロックされる)という恐怖の仕様があるからだ。

必ず、異常終了時(Error Handler)にも `EndUndoMark` が正しく評価される、あるいは安全に復旧する構造を作らなければならない。

Option Explicit

”’

”’ 大量の図形生成を1つのUndoトランザクションとして安全に処理するテンプレート
”’

Public Sub ExecuteBatchOperationSafely()
Dim doc As AcadDocument
Set doc = ThisDrawing

Dim undoMarkActive As Boolean
undoMarkActive = False

‘ 堅牢なエラーハンドリングの要
On Error GoTo ErrorHandler

‘ —————————————————-
‘ 1. Undoマークの開始
‘ —————————————————-
doc.StartUndoMark
undoMarkActive = True

‘ 画面描画を停止し、パフォーマンスを限界まで引き上げる
doc.Application.ScreenUpdating = False

‘ —————————————————-
‘ 2. メインの爆速バッチ処理(例:1000本の線を引く)
‘ —————————————————-
Dim i As Long
Dim startPoint(2) As Double
Dim endPoint(2) As Double
Dim lineObj As AcadLine

For i = 0 To 999
startPoint(0) = i 10: startPoint(1) = 0: startPoint(2) = 0
endPoint(0) = i 10: endPoint(1) = 100: endPoint(2) = 0

‘ ModelSpaceへの追加
Set lineObj = doc.ModelSpace.AddLine(startPoint, endPoint)

‘ 必要であれば拡張データ(XData)やカスタムプロパティをここで付与
Next i

‘ —————————————————-
‘ 3. 正常終了時のUndoマークの閉じ込み
‘ —————————————————-
doc.EndUndoMark
undoMarkActive = False

‘ 画面描画の復帰
doc.Application.ScreenUpdating = True

MsgBox “1000本の線分生成が正常に完了しました。\n(Ctrl + Z 1回で全キャンセル可能です)”, vbInformation, “処理成功”
Exit Sub

ErrorHandler:
‘ —————————————————-
‘ 4. 異常終了時のフェイルセーフ
‘ —————————————————-
‘ 画面描画の強制復帰
doc.Application.ScreenUpdating = True

‘ StartUndoMarkに対応するEndUndoMarkが呼ばれていない状態で放置すると
‘ AutoCADのUndoスタックが破損するため、強制的に閉じる
If undoMarkActive Then
On Error Resume Next ‘ 連続エラー回避
doc.EndUndoMark
On Error GoTo 0
End If

‘ ユーザーへエラーを通知
MsgBox “致命的なエラーが発生しました。処理を中断し、変更をロールバックします。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “致命的エラー”

End Sub

4. チーフアーキテクトからの実践的アドバイス

上記のコードを見れば、単にメソッドを呼び出すだけではなく、「なぜそこまで記述しなければならないのか」の意図が伝わるはずだ。実務で組み込む際は、以下のポイントも意識してほしい。

① `ScreenUpdating = False` との合わせ技

大量のエンティティを生成する際、AutoCADはデフォルトで「1つ図形が増えるたびに画面を再描画(ビューの更新)」しようとする。これがパフォーマンス低下の最大のガンだ。
`StartUndoMark` とセットで `Application.ScreenUpdating = False` を挟むことで、描画処理を完全にバイパスし、処理速度を最大10倍以上に跳ね上げることができる。(※処理終了時には必ず `True` に戻すこと。戻し忘れると画面がフリーズしたように見えるので注意せよ)

② ネスト(入れ子)のUndoマークに注意せよ

VBAから別の汎用関数を呼び出す際、その汎用関数内でも `StartUndoMark` を呼んでいると、Undoマークがネスト(多重化)する。
AutoCAD VBAにおいて、Undoマークの開始と終了は厳密にペア(1:1)でなければならない。複雑なアーキテクチャを設計する場合は、「Undoマークの管理は最上位のコントローラー層(エントリーポイント)でのみ行う」という設計規約をチーム内で徹底してほしい。

総括

AutoCAD VBAは、単に「図形を自動で描くおもちゃのスクリプト言語」ではない。裏側では強固なオブジェクトデータベース(`Database`)と、複雑なトランザクション管理機構が稼働している。

今回解説した `StartUndoMark` / `EndUndoMark` の制御をマスターすれば、数万オブジェクトを扱う巨大図面であっても、ユーザーをイライラさせないプロフェッショナルなツールを構築できる。

現場のエンジニア諸君、場当たり的なコードを書くのは今日で終わりにしよう。構造化され、堅牢で、ユーザーフレンドリーな自動化アーキテクチャを君の手で実装してくれ。健闘を祈る。

タイトルとURLをコピーしました