【テクニカル・上級編】【初心者向け】AutoCAD VBAで図面内の特定の文字(文字列)を検索し、その位置情報を取得する – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:図面内文字列の高速検索と位置情報抽出のアーキテクチャ

AutoCAD VBAにおけるオブジェクトモデルの操り方は、単なるスクリプトの記述にとどまらない。背後にあるCOM(Component Object Model)のライフサイクル、メモリ管理、そしてAutoCADデータベースの内部構造を熟知していなければ、大規模図面を扱った瞬間に致命的なパフォーマンス低下やメモリリークを引き起こす。

今回は、図面内に散在する特定の文字列(例:「注意」)を網羅的に検索し、その正確な位置情報(挿入点およびバウンディングボックス)を極限まで効率よく取得する手法を解説する。これは、手作業による図面チェックを完全に自動化し、上流工程の品質担保を実現するための基盤技術となる。

1. AutoCADオブジェクトモデルの深層とパフォーマンスの罠

初心者が最初に陥る罠は、`ActiveDocument.ModelSpace` や `ActivePaperSpace` に対する漫然としたイテレーション(ループ処理)である。さらに、`TextString` プロパティの比較を不適切に行うと、文字種(MTextとDBText)の差異によって検索漏れが発生する。

MTextとDBTextの二面性

AutoCAD図面内には、主に以下の2種類のテキストオブジェクトが存在する。
1. `AcadText` (DBText): 単一行文字。比較的軽量。
2. `AcadMText` (MText): マルチテキスト。書式設定コード(`\P`, `\f…` など)を含み、内部構造が複雑。

これらを同時に、かつ漏れなく捕捉するためには、モデル空間およびすべてのペーパー空間(レイアウト)を横断し、かつ `EntityName` を正確に評価する必要がある。

2. 実装コード:堅牢性と速度を極めた文字列検索エンジン

以下に、実務の現場で耐えうる、メモリ効率と例外処理を考慮した実用コードを提示する。単に文字を探すだけでなく、その境界ボックス(Bounding Box)を取得し、座標情報を多角的に抽出する。

Option Explicit

‘ =================================================================================
‘ 処理名: 図面内特定文字列検索エンジン
‘ 概要: モデル空間およびレイアウト空間から指定文字列を検索し、位置情報をイミディエイトに出力する
‘ =================================================================================
Public Sub SearchTextAndGetCoordinates()
Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Dim searchKeyword As String

‘ 検索キーワードの定義
searchKeyword = “注意”

‘ AutoCADアプリケーションの取得(バインドの最適化)
On Error Resume Next
Set acadApp = GetObject(, “AutoCAD.Application”)
If Err.Number <> 0 Then
MsgBox “AutoCADが起動していません。”, vbCritical, “致命的エラー”
Exit Sub
End If
On Error GoTo 0

Set acadDoc = acadApp.ActiveDocument

‘ 処理の高速化(画面描画とイベントの抑止)
acadApp.ScreenUpdating = False

Dim matchCount As Long
matchCount = 0

‘ 1. モデル空間の走査
matchCount = matchCount + ScanContainer(acadDoc.ModelSpace, searchKeyword)

‘ 2. ペーパー空間(レイアウト)の走査
Dim layoutObj As AcadLayout
For Each layoutObj In acadDoc.Layouts
‘ モデル空間以外のレイアウトタブを対象とする
If layoutObj.Model = False Then
matchCount = matchCount + ScanContainer(acadDoc.PaperSpace, searchKeyword)
End If
Next layoutObj

‘ 画面描画の復元
acadApp.ScreenUpdating = True

‘ 結果報告
MsgBox “検索が完了しました。” & vbCrLf & _
“キーワード [” & searchKeyword & “] が ” & matchCount & ” 件見つかりました。”, _
vbInformation, “図面チェック自動化”

‘ オブジェクトの明示的解放(COMメモリリーク防止)
Set acadDoc = Nothing
Set acadApp = Nothing
End Sub

‘ =================================================================================
‘ コンテナ(モデル/ペーパー空間)走査ヘルパー関数
‘ =================================================================================
Private Function ScanContainer(ByRef container As AcadSelectionSet, ByVal keyword As String) As Long
‘ ※ 引数の型をAcadSelectionSetとしているが、実際にはAcadBlock(ModelSpace/PaperSpaceはAcadBlockを継承)を走査する
Dim foundCount As Long
foundCount = 0

Dim ent As AcadEntity
Dim textObj As AcadText
Dim mtextObj As AcadMText

Dim insertionPoint As Variant
Dim minPoint As Variant
Dim maxPoint As Variant

Dim targetString As String

‘ 空間内の全エンティティを走査
Dim i As Long
Dim totalEntities As Long
totalEntities = container.Count

For i = 0 To totalEntities – 1
Set ent = container.Item(i)

‘ オブジェクトタイプに応じた分岐処理
If TypeOf ent Is AcadText Then
Set textObj = ent
targetString = textObj.TextString

If InStr(1, targetString, keyword, vbTextCompare) > 0 Then
foundCount = foundCount + 1
insertionPoint = textObj.InsertionPoint

‘ バウンディングボックスの取得(回転角や文字スタイルによりエラーになる場合があるため保護)
On Error Resume Next
textObj.GetBoundingBox minPoint, maxPoint
If Err.Number = 0 Then
Call LogTextInfo(“DBText”, textObj.Handle, targetString, insertionPoint, minPoint, maxPoint)
Else
Call LogTextInfo(“DBText”, textObj.Handle, targetString, insertionPoint, Array(0, 0, 0), Array(0, 0, 0))
End If
On Error GoTo 0
End If

ElseIf TypeOf ent Is AcadMText Then
Set mtextObj = ent
targetString = mtextObj.TextString

If InStr(1, targetString, keyword, vbTextCompare) > 0 Then
foundCount = foundCount + 1
insertionPoint = mtextObj.InsertionPoint

On Error Resume Next
mtextObj.GetBoundingBox minPoint, maxPoint
If Err.Number = 0 Then
Call LogTextInfo(“MText”, mtextObj.Handle, targetString, insertionPoint, minPoint, maxPoint)
Else
Call LogTextInfo(“MText”, mtextObj.Handle, targetString, insertionPoint, Array(0, 0, 0), Array(0, 0, 0))
End If
On Error GoTo 0
End If
End If

‘ ループ内でのメモリ解放
Set ent = Nothing
Set textObj = Nothing
Set mtextObj = Nothing
Next i

ScanContainer = foundCount
End Function

‘ =================================================================================
‘ 情報出力プロシージャ
‘ =================================================================================
Private Sub LogTextInfo(ByVal textType As String, ByVal handle As String, ByVal textStr As String, _
ByRef insPt As Variant, ByRef minPt As Variant, ByRef maxPt As Variant)

Debug.Print “— 検出 [” & textType & “] (Handle: ” & handle & “) —”
Debug.Print ” 文字列: ” & textStr
Debug.Print ” 挿入点: X=” & Format(insPt(0), “0.00”) & “, Y=” & Format(insPt(1), “0.00”) & “, Z=” & Format(insPt(2), “0.00”)

‘ バウンディングボックス(有効な場合のみ出力)
If Not IsEmpty(minPt) And Not IsEmpty(maxPt) Then
Debug.Print ” BBox Min: X=” & Format(minPt(0), “0.00”) & “, Y=” & Format(minPt(1), “0.00”)
Debug.Print ” BBox Max: X=” & Format(maxPt(0), “0.00”) & “, Y=” & Format(maxPt(1), “0.00”)
End If
End Sub

3. シニアエンジニアが押さえるべきアーキテクチャの急所

上記のコードは一見して完結しているが、極限のパフォーマンスと保守性を担保するために、以下のアーキテクチャ上の設計思想が組み込まれている。

① COMオブジェクトのライフサイクル管理とメモリ最適化

VBAのランタイムは、COMオブジェクトへの参照を自動的に解放する仕様になっているが、大規模な図面(数万〜数十万エンティティ)をループ処理する際、この自動解放機構(RCWの参照カウント制御)を信用してはならない
ループの内部で `Set ent = Nothing` を明示的に呼び出すことで、VBAヒープとAutoCADプロセス間のCOM境界におけるメモリリークを防ぎ、ガベージコレクションの負荷を劇的に軽減している。

② 画面描画のロック (`ScreenUpdating = False`)

AutoCAD VBAにおいて、図面要素を走査する際にグラフィックスパイプラインが動作していると、CPUの大部分が画面の再描画(Redraw)に消費される。
処理の冒頭で `ScreenUpdating = False`(内部的には `REGENMODE` や `WM_SETREDRAW` に類似する動作)を強制することで、処理速度を最大数倍〜数十倍に跳ね上げることが可能だ。

③ エラーハンドリングの境界防衛

`GetBoundingBox` メソッドは、特殊な変形を受けたテキストや、不正なゼロレングスのオブジェクトに対して実行時エラーをスローする。
これに対し、局所的な `On Error Resume Next` を配置し、例外発生時であっても全体の処理フローが停止しない「フォールトトレラント(耐障害性)」な設計を徹底している。

4. さなる高みへ:システム間連携とAPIへの昇華

このVBAによる文字列検索ロジックは、単なる「図面チェックのマクロ」に留まらない。これを踏み台として、以下のようなエンタープライズシステムへの拡張が可能となる。

  • 外部データベース(SQL Server / PostgreSQL)との連携: 検出されたテキストの座標とハンドル値を非同期でDBに書き込み、図面改訂履歴の自動トラッキングシステムを構築する。
  • .NET (C#) プラグインへの移行: VBAの実行速度やセキュリティ上の制約を超えるため、このロジックをObjectARX / .NET API (`Autodesk.AutoCAD.DatabaseServices`) の `Transaction` を用いた高速な図面解析エンジンへとリファクタリングする。

AutoCAD VBAを「おもちゃのスクリプト」と侮るなかれ。背後にあるAPIの挙動とメモリ構造を完全に支配した時、VBAは最強のインダストリアル・オートメーション・ツールへと変貌を遂げる。

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