AutoCAD VBAの深淵:連番管理を「堅牢な資産」に変える設計術
AutoCADで「連番を振る」というタスクは、一見すると単純なループ処理に見える。しかし、実務レベルで数千・数万のオブジェクトを扱う際、その「単純さ」は脆弱性の温床となる。
多くの開発者が陥る罠は、「SelectionSetの管理放棄」と「XData/Propertyの不整合」だ。今回は、ただ動くコードではなく、プロジェクトの保守性を担保し、後から「誰が触っても壊れない」極限の設計を授ける。
—
1. なぜ「単純な連番」が破綻するのか
プロトタイプ段階では、`For Each`文で全オブジェクトを回すコードを書くだろう。だが、現実の図面は汚い。
- 不意のUndo(元に戻す): ユーザーが途中で操作をキャンセルすれば、連番の整合性は崩壊する。
- 非決定的な順序: AutoCADのDB格納順序は、作成・修正履歴に依存する。見た目通りに連番が振られない事態は、エンジニアとして許容してはならない。
解法: オブジェクトのX/Y座標によるソートを確定させ、`SelectionSet`を明示的に解放する。これがプロの流儀だ。
—
2. 実装の核心:連番付与ソリューション
以下のコードは、図面上の特定のブロックに対し、カスタムプロパティ(XRecord)としてユニークなIDを書き込むものだ。
プロダクションコード:`SequenceManager.bas`
Option Explicit
‘ ———————————————————
‘ 目的: 指定ブロックに連番を付与し、XRecordとして永続化する
‘ 設計指針: SelectionSetの再利用禁止、エラーハンドリングの徹底
‘ ———————————————————
Public Sub AssignSequenceToBlocks()
Dim ss As AcadSelectionSet
Dim ent As AcadEntity
Dim blockRef As AcadBlockReference
Dim i As Long
Dim seqName As String: seqName = “MY_ASSET_ID”
‘ 1. SelectionSetのクリーンアップ(重要:既存があれば必ず破棄)
On Error Resume Next
ThisDrawing.SelectionSets.Item(“BlockSelection”).Delete
On Error GoTo 0
Set ss = ThisDrawing.SelectionSets.Add(“BlockSelection”)
‘ 2. フィルタリング(ブロック名指定推奨)
Dim filterType(0) As Integer
Dim filterData(0) As Variant
filterType(0) = 0: filterData(0) = “INSERT”
ss.Select acSelectionSetAll, , , filterType, filterData
‘ 3. 座標による並び替え(簡易版:実際の現場では座標計算のソート関数を別途作成すること)
‘ ここでは簡略化のため順次処理とするが、実務では配列へ格納しソートを推奨
For i = 0 To ss.Count – 1
Set ent = ss.Item(i)
If TypeOf ent Is AcadBlockReference Then
Set blockRef = ent
‘ カスタムプロパティへの書き込み(XRecord使用)
Call WriteXRecord(blockRef, seqName, “ID-” & Format(i + 1, “0000”))
End If
Next i
‘ 4. 後処理
ss.Delete
MsgBox “連番の付与が完了しました。”, vbInformation
End Sub
‘ XRecordによる永続化(プロパティ管理の要)
Private Sub WriteXRecord(obj As AcadObject, key As String, val As String)
Dim xrec As AcadXRecord
Dim data(0) As Variant
Dim types(0) As Integer
‘ XRecordの作成・更新処理
‘ ※実運用では既存XRecordの有無を確認し、更新/作成を分岐させること
Set xrec = ThisDrawing.Dictionaries.Add(“MY_PROJECT_DATA”).AddXRecord(key)
data(0) = val: types(0) = 1
xrec.SetXRecordData types, data
End Sub
—
3. 「堅牢性」を極めるための3つの掟
① SelectionSetの「呪縛」を解く
VBAの`SelectionSet`はメモリを喰う。`ss.Delete`を忘れると、次回の実行時に「そんな名前は既に存在する」というエラーで沈黙する。必ず`On Error Resume Next`で既存の同名セットを削除してから生成するルーチンをテンプレート化せよ。
② カスタムプロパティの保存先
`Attribute(属性)`を使うのは避けろ。属性はユーザーがGUIで簡単に編集できてしまうため、管理データとしては脆い。`XRecord`(拡張レコード)を使用せよ。これは図面DBに深く潜り込み、不用意な変更を許さない。
③ トランザクション思考
数千のオブジェクトを処理する際、途中でクラッシュすると「連番が途中まで振られた死体」が残る。
- 対策: 処理前に`ThisDrawing.StartUndoMark`を呼び出し、処理完了後に`EndUndoMark`を呼ぶ。これにより、万が一の際も「Undo 1回」で全ロールバックが可能になる。
—
4. 最後に:エンジニアとしての矜持
このコードは「動く」だけのものだ。実際の現場では、これに「CSVへのエクスポート機能」や「重複チェック機能」を付与することになるだろう。
しかし、最も重要なのは「コードの可読性と保守性」だ。
VBAは古い言語だが、正しく書けばAutoCADのエンジンを最も直接的に制御できる。小手先のテクニックで誤魔化さず、オブジェクトのライフサイクルを制御下に置く設計こそが、我々エンジニアの生存戦略である。
もし君がこのコードをベースに拡張するなら、まずは`Dictionary`オブジェクトを活用して、座標の重複チェックを実装してみろ。それが、中級者から「真のアーキテクト」へ至る階段だ。
