AutoCAD VBAを掌握する極限の知見
第1回:図面内の全ハッチング境界を再定義!AcadHatchオブジェクトのAppendLoopメソッドによる形状追従の自動化
こんにちは。開発プロジェクトの現場で幾多のレガシーマクロと戦ってきたチーフアーキテクトの私だ。
AutoCAD VBAの実務において、単なる「図形描画の自動化」から抜け出せないうちは、まだ初級者の域を出ない。真の自動化エンジニアが直面するのは、「設計変更に追従する既存図面の動的メンテナンス」という泥臭く、かつ絶対に避けて通れない壁だ。
今回は、実務で最もフラストレーションが溜まるポイントの一つ――「境界が変更されたのに、ハッチングが追従せず破綻する問題」を、`AcadHatch` オブジェクトと `AppendLoop` メソッドを駆使して完全に制圧するテクニックを伝授する。
—
1. なぜ「ハッチングの再定義」で多くのエンジニアが散るのか?
設計変更によって境界線(ポリラインなど)がストレッチされたり、移動したりした時、素人が書いたVBAコードは決まってこうなる。
- 「とりあえず既存のハッチングを削除して、同じ位置で新しくハッチングを作り直せばいいや」
これは最悪のアンチパターンだ。
なぜか?
ハッチングオブジェクトが保持していた「画層」「色」「パターン名」「尺度」「角度」、そして何より外部データベースや他の図面要素との関連付け(Handle値)がすべて吹き飛ぶからだ。実務の図面において、オブジェクトのHandleが変わることは、下流の管理システムや集計スクリプトにとって致命傷になり得る。
我々が目指すべきは、「既存の `AcadHatch` インスタンスを生存させたまま、その境界ループ(Loop)だけを外科手術のように正確に再定義し、アソシエイティブ(関連付け)を維持する」ことだ。
—
2. AcadHatch と AppendLoop の核心構造
`AcadHatch` オブジェクトの内部は、実は幾何学的な「ループ(境界の輪郭)」のコレクションで構成されている。1つのハッチングが複数の外周や島(内側の抜き穴)を持つのは、そのためだ。
境界を再定義する正確な手順は以下の通りである。
1. 対象の `AcadHatch` オブジェクトを特定する。
2. 既存の境界ループをすべて削除する(`Hatch.DeleteLoop`)。
3. 新しい境界となるエンティティ(`AcadEntity`の配列)を定義する。
4. `AppendLoop` メソッドを叩いて新しいループを追加する。
5. `Evaluate` メソッドを強制実行し、ジオメトリを再計算させる。
ここで、AutoCAD VBA特有の「重い罠」に触れておこう。
`AppendLoop` に渡す配列は、必ず VARIANT型の1次元配列(かつ `AcadEntity` のオブジェクト参照の詰まったもの) である必要がある。ここを型ミスマッチでミスると、容赦なくエラー 438 や 13 が飛んでくる。
—
3. 【プロダクションコード】堅牢なハッチング境界再定義モジュール
実務の現場でそのまま組み込める、エラーハンドリング完備のプロフェッショナルコードを公開しよう。このコードは、選択された(あるいはモデル空間全体の)アソシエイティブ・ハッチングに対し、紐付いているはずの境界オブジェクトの最新形状をスキャンし、ループを再構築する。
Option Explicit
‘ =================================================================00
‘ モジュール名: ModHatchReconstructor
‘ 概要: 既存のAcadHatchの境界ループを動的に再構築し、プロパティを維持したまま形状追従させる
‘ =================================================================00
Public Sub RebuildAllAssociatedHatches()
Dim acadDoc As AcadDocument
Set acadDoc = ThisDrawing
‘ パフォーマンスと画面描画のロック(実務の基本:画面描画を止めて爆速化する)
acadDoc.Utility.Prompt “ハッチング境界の再定義処理を開始します…” & vbCrLf
Dim hatchCount As Long: hatchCount = 0
Dim errCount As Long: errCount = 0
On Error GoTo ErrorHandler
Dim ent As AcadEntity
For Each ent In acadDoc.ModelSpace
If TypeOf ent is AcadHatch Then
Dim oHatch As AcadHatch
Set oHatch = ent
‘ アソシエイティブ(関連付け)されているハッチングのみを対象とする
If oHatch.AssociativeHatch = True Then
If UpdateHatchLoop(oHatch) Then
hatchCount = hatchCount + 1
Else
errCount = errCount + 1
End If
End If
End If
Next ent
acadDoc.Utility.Prompt “処理完了: 成功=” & hatchCount & “件, 失敗=” & errCount & “件” & vbCrLf
Exit Sub
ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “自動化エンジニアリング”
End Sub
‘ =================================================================00
‘ 関数名: UpdateHatchLoop
‘ 概要: 単一のAcadHatchオブジェクトの境界ループをクリアし、再アタッチする
‘ =================================================================00
Private Function UpdateHatchLoop(ByRef targetHatch As AcadHatch) As Boolean
On Error GoTo LocalError
‘ 1. ハッチングに現在関連付けられているソース境界エンティティを取得
Dim boundEntities() As AcadEntity
boundEntities = targetHatch.GetAssociateEntities()
‘ 境界エンティティが取得できない場合はスキップ
If UBound(boundEntities) < 0 Then
UpdateHatchLoop = False
Exit Function
End If
' 2. 既存のすべての境界ループをインデックスの逆順から削除
' ※コレクション操作の鉄則:削除は必ず後ろのインデックスから行うこと
Dim i As Long
Dim loopCount As Long
loopCount = targetHatch.NumberOfLoops
For i = loopCount - 1 To 0 Step -1
targetHatch.DeleteLoop i
Next i
' 3. 取得した境界エンティティを新しいループとして再追加
' ここでAppendLoopに渡す配列の型と次元に細心の注意を払う
Dim loopType As Long
loopType = acHatchLoopTypeDefault ' 通常の外部境界ループ
targetHatch.AppendLoop loopType, boundEntities
' 4. ジオメトリの再評価(Evaluateを実行しないと画面上は古い形状のまま残る)
targetHatch.Evaluate
UpdateHatchLoop = True
Exit Function
LocalError:
' 個別ハッチングのエラーで全体を止めないためのフェイルセーフ
UpdateHatchLoop = False
End Function
---
4. チーフアーキテクトが教える、現場で活きる実装の急所
上記のコードを実務展開するにあたり、プロとして押さえておくべき設計思想を解説する。
① `GetAssociateEntities` の挙動を理解せよ
AutoCADの仕様上、ハッチングが「アソシエイティブ」として生成されている場合、そのハッチングは元となった境界オブジェクト(LWPolylineやLineなど)の参照を内部保持している。`GetAssociateEntities` メソッドは、この関連付けられたオブジェクトの配列を返す。
設計変更によって境界の頂点座標が移動していれば、このメソッドで取得できるオブジェクト自体がすでに「新しい形状」を保持しているため、そのまま `AppendLoop` に投げ返すだけで、自動的に変形後の形状でハッチングが再計算されるという寸法だ。
② 削除処理(`DeleteLoop`)の落とし穴
ループの削除を前から(インデックス 0, 1, 2… と)実行すると、要素が削除されるたびに後続のインデックスが繰り上がってしまい、必ず `Index Out of Range` の例外が起きる。
「コレクションの削除は後ろから逆順(Step -1)で回せ」。これはGUIプログラミングやCAD自動化における普遍的な鉄則だ。
③ 描画のブラックボックス:`Evaluate` の強制
VBAで `AppendLoop` を実行した直後、AutoCADの画面上ではハッチングが消えたように見えたり、古い領域のままフリーズしているように見えることがある。これは画面の再描画(Display)と内部データ(Database)の同期が遅延しているためだ。
コード内で明示的に `targetHatch.Evaluate` を呼び出し、その直後に `ThisDrawing.Regen acActiveViewport` を挟むのも手だが、パフォーマンスを考慮するなら `Evaluate` のみでバックグラウンド計算を完結させ、最後に図面全体をリフレッシュするのが最もエレガントである。
—
5. おわりに
今回紹介した `AppendLoop` によるハッチング再定義のテクニックは、一見地味に見えるかもしれない。しかし、数千個の区画を持つ建築図面やプラント配管図の改修において、この自動化スクリプトがどれほどのヒューマンエラーと工数を削減するか、想像に難くないはずだ。
「図形が変わったら、ハッチングも自動で追従する」――この当たり前のようで誰もが面倒くさがる領域をコードで完全調教することこそ、真の業務自動化エンジニアの仕事である。
妥協のないコードで、あなたの開発現場を圧倒的な効率化へと導いてほしい。健闘を祈る。
