【実務・中級編】【実務中級】図面内の「グループ(Group)」オブジェクト操作:関連する図形を一括でまとめ、効率的に編集・移動するVBAコード – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:図面内「グループ(Group)」オブジェクトの完全制覇

こんにちは。チーフアーキテクトの私だ。
これまで数々の大規模プラント図面や建築図面の自動化プロジェクトを統括してきたが、現場からもっとも多く寄せられる嘆きの一つがこうだ。

「選択セット(SelectionSet)で一時的にまとめて処理したはいいが、図面を閉じたら消えてしまう」
「ブロック化するほどでもないが、関連する複数の図形を『ひと固まり』として永続的に管理し、ユーザーに一括選択・編集させたい」

君たちは、一時的な選択セットと、図面データベースに永続化される「グループ(AcadGroup)」の本質的な違いを理解しているか?

今回は、SelectionSetの限界を超え、図面内にグループを生成・管理し、実務の現場でバグを踏まないための堅牢なVBAコードと設計思想を伝授しよう。退屈なリファレンスの引き写しではない。プロダクション環境でそのまま動く「プロのコード」を叩き込む。

1. なぜ「グループ」なのか?:SelectionSetとの決定的違い

実務において、図形をまとめる手段としては主に「ブロック(Block)」か「選択セット(SelectionSet)」が使われる。しかし、これらには明確なジレンマがある。

1. ブロック (`AcadBlock`):

  • メリット: 永続的であり、挿入単位で一括管理できる。
  • デメリット: 内部の個別図形を編集するには「ブロックエディタ」を開くか、分解(Explode)する手間がかかる。その場でのラフな形状変更には向かない。

2. 選択セット (`AcadSelectionSet`):

  • メリット: 瞬時に任意の図形を集められる。
  • デメリット: 非永続的である。図面を閉じれば消滅し、さらに同名のセットが存在する場合のエラーハンドリングなど、メモリ管理が極めて煩雑だ。

ここで登場するのが `AcadGroups` コレクション だ。
グループは図面ファイル(DWG)内に永続的に保存され、ユーザーは通常の選択モードでグループの境界をクリックするだけで、構成要素を一網打尽に選択・変形できる。しかも、ブロックのようにわざわざ定義を編集する手間がなく、個々のエンティティのアイデンティティが保たれる。

実務で「一時的すぎず、ブロックほど硬直的でない」関連付けが必要な場合、グループ一択なのだ。

2. 【設計の急所】グループ操作における3大罠

AutoCAD VBAでグループを扱う際、素人が必ずハマる罠がある。ここを理解していないと、現場で「突然VBAが暴走する」「図面が破損する」といった致命傷を負う。

罠1:同名グループの重複作成によるクラッシュ

`Groups.Add(“MyGroup”)` は、すでに同名のグループが存在する場合、容赦なく実行時エラー(エラー番号:-2145386478 など)を吐いて沈没する。
プロダクションコードでは、必ず既存グループの有無を走査して削除するか、名前を一意(ユニーク)にするガードロジックが必須だ。

罠2:オブジェクト配列(Variant)の次元と型の厳密性

`Group.AppendItems` メソッドに渡す引数は、「AcadEntityオブジェクトを格納した1次元のVariant配列」でなければならない。
単一のオブジェクトをそのまま渡したり、型が不整合だったりすると、容赦なく「型が一致しません」エラーが発生する。

罠3:図面クローズ時のメモリリークと参照切れ

オブジェクト変数を取得したはいいが、適切に解放(Nothing代入)しなかったり、存在しないインデックスにアクセスしたりすると、AutoCAD自体のプロセスが不安定になる。

3. 【実装コード】堅牢なグループ管理・一括変形モジュール

それでは、実務でそのまま使えるプロダクションコードを公開する。
このコードは、指定したレイヤの図形を自動でかき集め、永続グループを生成し、一括で移動(シフト)させる一連の処理を、鉄壁の錯誤処理(Error Handling)とともに実装したものだ。

Option Explicit

” ==============================================================================
” モジュール名: modGroupManager
” 概要: AutoCAD図面内での「グループ」の生成、要素追加、および一括変形を制御する
” 開発者: チーフアーキテクト
” ==============================================================================

Public Sub ExecuteRobustGroupOperation()
On Error GoTo ErrorHandler

Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Set acadApp = ThisDrawing.Application
Set acadDoc = ThisDrawing

‘ 1. グループ名の定義
Const TARGET_GROUP_NAME As String = “PRD_PROD_ASSEMBLY_01”

‘ 2. 既存グループのクリーンアップ(同名存在時の安全対策)
Call RemoveGroupIfExists(acadDoc, TARGET_GROUP_NAME)

‘ 3. 新規グループの作成
Dim targetGroup As AcadGroup
Set targetGroup = acadDoc.Groups.Add(TARGET_GROUP_NAME)

‘ 4. グループに追加する図形を収集(例として、特定のレイヤに属する全図形を収集)
Dim ent As AcadEntity
Dim entCount As Long
entCount = 0

‘ 事前に要素数をカウントして動的配列のサイズを決定する
For Each ent in acadDoc.ModelSpace
‘ 例: “Mechanical” レイヤの図形をグループ化の対象とする
If UCase(ent.Layer) = “MECHANICAL” Then
entCount = entCount + 1
End If
Next ent

If entCount = 0 Then
MsgBox “対象となるレイヤ ‘Mechanical’ の図形が見つかりませんでした。”, vbExclamation, “処理中断”
Exit Sub
End If

‘ 5. AcadEntityを格納する1次元配列の生成
Dim entities() As AcadEntity
ReDim entities(0 To entCount – 1)

Dim i As Long
i = 0
For Each ent in acadDoc.ModelSpace
If UCase(ent.Layer) = “MECHANICAL” Then
Set entities(i) = ent
i = i + 1
End If
Next ent

‘ 6. グループへ図形群を追加(永続化)
targetGroup.AppendItems entities

‘ デバッグ出力: 登録確認
Debug.Print “グループ [” & TARGET_GROUP_NAME & “] に ” & targetGroup.Count & ” 個の図形を登録しました。”

‘ 7. グループ単位での一括変形テスト(全要素を一括でX方向に +50.0mm 移動)
Dim displacement(0 To 2) As Double
displacement(0) = 50.0 ‘ X方向移動量
displacement(1) = 0.0 ‘ Y方向移動量
displacement(2) = 0.0 ‘ Z方向移動量

‘ グループ内の全エンティティに対して一括でMoveメソッドを適用
‘ ※AcadGroup自体にはMoveメソッドがないため、要素をループして一括操作する、
‘ または選択セット経由で操作するのが実務上の定石。
Dim memberEnt As AcadEntity
For i = 0 To targetGroup.Count – 1
Set memberEnt = targetGroup.Item(i)
memberEnt.Move displacement(0), displacement(1), displacement(2)
Next i

acadDoc.Regen acActiveViewport
MsgBox “グループの作成と、グループ図形の一括移動が完了しました。”, vbInformation, “成功”

‘ クリーンアップ
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “致命的エラー”

‘ オブジェクトの解放
Set targetGroup = Nothing
Set acadDoc = Nothing
Set acadApp = Nothing
End Sub

” ==============================================================================
” 補助プロシージャ: 同名グループが存在する場合は安全に削除する
” ==============================================================================
Private Sub RemoveGroupIfExists(doc As AcadDocument, groupName As String)
On Error GoTo CheckError

Dim grp As AcadGroup
‘ 存在しない場合はエラーになるため、エラーハンドラで捕捉する
Set grp = doc.Groups.Item(groupName)

If Not grp Is Nothing Then
‘ グループ定義(オブジェクト自体の削除ではなく、グループという「枠」の削除)
grp.Delete
Debug.Print “既存の同名グループ [” & groupName & “] を削除しました。”
End If
Exit Sub

CheckError:
‘ グループが見つからないエラー(-2145386478等)は無視して続行
Err.Clear
End Sub

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

このコードをそのまま社内展開するにあたり、以下のアーキテクチャ上のポイントを覚えておいてほしい。

1. 「グループの削除」と「図形の削除」を混同するな
`grp.Delete` を実行しても、グループに含まれていた図形(AcadEntity)自体はモデル空間に残る。消えるのは「グループというコレクションの枠組み」だけだ。図形そのものを消去したい場合は、個別に `ent.Delete` を呼ぶ必要がある。この仕様の勘違いによるバグが非常に多い。
2. パフォーマンスの意識
数千・数万の図形を一度に `AppendItems` する場合、AutoCADの画面描画(グラフィック・パイプライン)が毎回追従すると激しく処理が重くなる。大規模データを扱う際は、一時的に `acadDoc.ActiveViewport.GridOn` などをオフにするか、処理の前後で画面更新を抑止する工夫を入れるとプロっぽい仕上がりになる。
3. 他者との共同作業(データベース連携)における注意
グループ名は図面ごとにユニークである必要がある。外部からマージ(挿入)された図面とグループ名が競合する場合があるため、自動生成ツールを作る際はプレフィックス(例: `PRJ_` + タイムスタンプ等)を付与して名前空間の衝突を防ぐのが、プロフェッショナルな設計というものだ。

SelectionSetのその先へ――。「永続するグループ」を自在に操ることで、君のAutoCAD自動化スクリプトは、単なる「作業の代行」から「高度なデータ管理システム」へと昇華する。

現場の生産性を限界まで引き上げてくれ。健闘を祈る。

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