AutoCAD VBAを掌握する極限の知見:図面からの数量算出し、設計値を制圧する
多くのプログラマやCADオペレーターが、AutoCAD VBAの初歩的なチュートリアルを卒業した後に直面する壁がある。それは、「図面から正確な幾何情報をプログラムで引き出し、それを実務の耐えうる高速かつ堅牢な処理へと昇華させる方法」だ。
本稿では、`AcadDocument`が内包するオブジェクトモデルの深層、幾何学計算の効率化、そしてメモリ管理の極意に焦点を当て、単なる「動くコード」の先にあるエンジニアリングの真髄を解説する。
—
1. オブジェクトモデルの解剖学:`AcadDocument` と選択セットのライフサイクル
AutoCAD VBAにおいて、すべての起点は `AcadApplication` と `AcadDocument` にある。特に `AcadDocument.ModelSpace` からエンティティをいかに効率よく抽出するかは、パフォーマンスを大きく左右する。
多くの初心者は、`For Each` ループをモデルスペース全体の全エンティティに対して回し、その中で `TypeOf` 判定を行う。
これは大規模図面において致命的なアンチパターンだ。
数万の図形が存在するレイアウトにおいて、VBAとCOMの境界(Interop Boundary)を無駄にまたぐループ処理は、ガベージコレクションとCOMラッパーの生成コストにより、処理を数分単位で遅延させる。
ここで使うべきは、明示的に管理された `AcadSelectionSet`(選択セット) と、AutoCAD内部の高速インデックス機構を叩く `SelectByPolygon` やフィルタ機構(FilterType / FilterData) である。
—
2. 実装:高速かつ堅牢な数量算出エンジン
以下に、指定されたレイヤまたはすべての線分(Line/LWPolyline)の「長さ」、および閉じたポリラインの「面積」を極限まで最適化されたロジックで一括算出し、イミディエイトウィンドウに出力する実用コードを示す。
このコードは、オブジェクトの明示的な解放(メモリリークの根絶)と、COM例外に対する防御的プログラミングを完全に実装している。
Option Explicit
‘ ==============================================================================
‘ 局所的なCOMラッパー解放と高速数量算出演習
‘ Author: Chief Architect (Automation Division)
‘ ==============================================================================
Public Sub ExtractGeometryMetrics()
Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Dim ssets As AcadSelectionSets
Dim targetSSet As AcadSelectionSet
‘ フィルタ用配列
Dim filterType(0) As Integer
Dim filterData(0) As Variant
On Error GoTo ErrorHandler
‘ 1. Application取得の堅牢化 (早期バインディング前提)
Set acadApp = ThisDrawing.Application ‘ または GetObject(, “AutoCAD.Application”)
Set acadDoc = acadApp.ActiveDocument
‘ 2. 既存の同名選択セットの残骸をパージ (COMリーク防止の鉄則)
Set ssets = acadDoc.SelectionSets
On Error Resume Next
ssets.Item(“QTO_HighPerf_Set”).Delete
On Error GoTo ErrorHandler
‘ 3. 新規選択セットの作成
Set targetSSet = ssets.Add(“QTO_HighPerf_Set”)
‘ 4. フィルタの設定: LINE または LWPOLYLINE のみを一括抽出
‘ DXFグループコード 0 はエンティティタイプを表す
filterType(0) = 0
filterData(0) = “LINE,LWPOLYLINE”
‘ モデルスペースから高速一括選択 (COMの往復を最小化)
targetSSet.Select acSelectionSetAll, , , filterType, filterData
If targetSSet.Count = 0 Then
MsgBox “対象となる幾何オブジェクトが見つかりませんでした。”, vbExclamation, “QTO Engine”
GoTo CleanUp
End If
‘ 5. 集計変数の初期化
Dim totalLineLength As Double
Dim totalPolyLength As Double
Dim totalArea As Double
totalLineLength = 0#
totalPolyLength = 0#
totalArea = 0#
Dim ent As AcadEntity
Dim polyObj As AcadLWPolyline
Dim lineObj As AcadLine
‘ 6. ループ処理: オブジェクト型の判定と算術演算
Dim i As Long
For i = 0 To targetSSet.Count – 1
Set ent = targetSSet.Item(i)
If TypeOf ent is AcadLine Then
Set lineObj = ent
totalLineLength = totalLineLength + lineObj.Length
ElseIf TypeOf ent is AcadLWPolyline Then
Set polyObj = ent
totalPolyLength = totalPolyLength + polyObj.Length
‘ 閉じた領域(面積を持つポリライン)の判定
‘ .Closed プロパティが True かつ 頂点数が3以上、またはAreaが有効な場合
If polyObj.Closed Then
‘ AutoCADのLWPolyline.Areaは内部で計算済みの値を返すため極めて高速
totalArea = totalArea + polyObj.Area
End If
End If
‘ ループ内でのローカル変数オブジェクトの参照を解放
Set ent = Nothing
Set lineObj = Nothing
Set polyObj = Nothing
Next i
‘ 7. 結果の出力 (システム間連携やCSV出力のフックポイント)
Debug.Print “=== AutoCAD Geometry QTO Report ===”
Debug.Print “対象図面: ” & acadDoc.Name
Debug.Print “検証対象総数: ” & targetSSet.Count & ” エンティティ”
Debug.Print “———————————–”
Debug.Print “線分(LINE) 総延長: ” & Format(totalLineLength, “#,
0.00″) & ” mm”
Debug.Print “ポリライン 総延長: ” & Format(totalPolyLength, “#,
0.00″) & ” mm”
Debug.Print “閉じた領域 総面積: ” & Format(totalArea, “#,
0.00″) & ” sq.mm (” & Format(totalArea / 1000000#, “#,##0.04″) & ” sq.m)”
Debug.Print “===================================”
CleanUp:
‘ 8. 厳格なメモリ解放 (COMオブジェクトのゾンビ化を防ぐ)
If Not targetSSet Is Nothing Then
targetSSet.Delete
Set targetSSet = Nothing
End If
Set ssets = Nothing
Set acadDoc = Nothing
Set acadApp = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “Critical Error”
Resume CleanUp
End Sub
—
3. シニアエンジニアが知るべき「裏側の真実」とパフォーマンスチューニング
上記のコードを実務の巨大図面(数メガバイト〜数十メガバイトのDWG、数万のプリミティブ)に適用する際、以下のアーキテクチャ上の制約を理解しているかどうかが、プロとアマの分かれ目となる。
A. COMインターフェースの参照解放(Reference Counting)
VBAのランタイムは優秀だが、AutoCADのCOMオブジェクト(C++で書かれたARX/ObjectARXのラッパー)は、VBA側で明示的に `Set variable = Nothing` を行わない限り、AutoCADプロセスのメモリ空間内に参照が残り続ける。
特にループ内で生成・破棄されるオブジェクトの参照が残ると、数回の実行でメモリ使用量が跳ね上がり、最悪の場合はAutoCAD自体がクラッシュする(メモリリーク)。
B. `Area` プロパティのレイテンシ
`AcadLWPolyline.Area` は非常に便利なプロパティだが、CAD内部でジオメトリが非同期に更新されている状態(未保存の変更や、複雑な自己交差ポリライン)で呼び出すと、予期せぬCOMエラー(Error 5: プロシージャの呼び出しまたは引数が不正です)を吐くことがある。
実運用では、`On Error Resume Next` を局所的に挟むか、事前にジオメトリの整合性を担保するサニタイズ処理を入れるのが、堅牢なシステム管理者のアプローチだ。
C. レガシー環境と.NET (ObjectARX / Managed .NET API) への移行パス
VBAは手軽である一方、AutoCADのバージョンアップ(特にマルチスレッド処理や最新のグラフィックスエンジン)において、COMラッパーの限界に突き当たる。
もしあなたが全社的な数量算出システム(QTOシステム)の基盤構築を任されているなら、VBAでロジックの概念実証(PoC)を行ったのち、速やかに C# (.NET API) の `Editor.Select()` や `Curve.GetDistanceAtParameter()` へ移行する設計図を描いておくべきだ。
C#であれば、LINQを活用したクエリベースでの幾何演算が可能になり、VBAの10倍以上のパフォーマンスを叩き出すことができる。
—
結言
AutoCAD VBAにおける幾何情報の抽出は、単にメソッドを呼び出す作業ではない。CADのメモリ構造、COMのライフサイクル、そして図面データという「生きた数学的モデル」に対する深い敬意と理解があって初めて、破綻のない自動化システムが構築できる。
ここに示した知見とコードをあなたの開発環境に組み込み、レガシーの呪縛を断ち切る強靭な自動化基盤を完成させてもらいたい。
