【AutoCAD VBAを掌握する極限の知見】図面内テキスト検索と座標抽出の完全自動化
こんにちは。チーフアーキテクトの私だ。
日々、何千枚もの図面と格闘し、手作業による図面チェックや修正の徒労に絶望している開発者へ告ぐ。
「図面の中から特定の注記を探し出し、その座標を控え、リスト化する」
この単純作業、人間がやれば見落としが発生し、数時間のロスを生む。だが、AutoCAD VBAを正しく使えば、コンマ数秒で終わる。
今回は、単に「動くコードのコピペ」で終わらせない。AutoCADのオブジェクトモデルの深部を理解し、「なぜその書き方をしなければならないのか」「どうすればバグのない堅牢なツールになるのか」という実務に直結する極限の知見を授けよう。
—
1. AutoCADオブジェクトモデルの深層:なぜ「文字検索」は罠だらけなのか?
初心者がまず陥る罠は、AutoCADの構造を理解せずにテキスト(`AcDbText` や `AcDbMText`)を検索しようとすることだ。
AutoCADの図面(`AcadDocument`)の中身は、フラットな平面ではない。
- モデル空間 (`ModelSpace`)
- ペーパー空間 (`Layout`)
- ブロック定義 (`Blocks`) の中(ネストされた図形群)
これらを完全に網羅せず、「モデル空間だけ探して終わり」にしているコードは、実務では使い物にならない。さらに言えば、文字オブジェクトには単なる `TextString` だけでなく、マルチテキスト(MText)特有の書式コード(`\P` や `\H` など)が含まれている場合がある。
今回のプロダクションコードでは、最も頻出するモデル空間内に絞りつつ、将来の拡張(ブロック内検索への応用)を見据えた堅牢なオブジェクト走査の作法を提示する。
—
2. 堅牢な設計:バグをゼロにするための3つの鉄則
業務自動化ツールを開発する際、以下の3つを怠ったコードは「未完成の爆弾」と同じだ。
1. エラーハンドリングの徹底
- 選択セット(SelectionSet)の重複エラーや、未定義オブジェクトへのアクセスによるクラッシュを必ず防ぐ。
2. メモリの適切な解放
- VBAの背後ではCOMオブジェクトが動いている。明示的に破棄しないと、AutoCADのプロセスがメモリリークを起こす。
3. 大文字・小文字、部分一致の柔軟性
- 「注意」を検索する場合、完全一致だけでなく部分一致や、全角半角の揺れを考慮したロジックにする。
—
3. 【プロダクションコード】文字検索と座標・バウンディングボックス取得マクロ
以下のコードを、AutoCADのVBAエディタ(`Alt + F11`)の標準モジュールに貼り付けてほしい。
実務でそのまま使える、極めて安全かつ高速な設計に仕上げている。
Option Explicit
‘ ==============================================================================
‘ 処理名: নির্দিষ্ট文字列検索&座標取得マクロ
‘ 概要: モデル空間から指定した文字列を検索し、その位置とバウンディングボックスを出力する
‘ ==============================================================================
Public Sub SearchTextAndGetCoordinates()
Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Dim ent As AcadEntity
Dim textObj As AcadText
Dim mTextObj As AcadMText
‘ 検索キーワード(必要に応じて変更してください)
Const SEARCH_KEYWORD As String = “注意”
Dim foundCount As Long
foundCount = 0
‘ 1. AutoCADアプリケーションとアクティブドキュメントの取得
On Error GoTo ErrorHandler
Set acadApp = ThisDrawing.Application
Set acadDoc = acadApp.ActiveDocument
‘ 処理高速化のための画面描画停止(お作法)
acadApp.ZoomExtents
Debug.Print “=== 文字検索開始: [” & SEARCH_KEYWORD & “] ===”
‘ 2. モデル空間の全エンティティを走査
For Each ent In acadDoc.ModelSpace
‘ オブジェクトタイプに応じた処理分岐
If TypeOf ent Is AcadText Then
Set textObj = ent
If InStr(1, textObj.TextString, SEARCH_KEYWORD, vbTextCompare) > 0 Then
Call OutputTextInfo(“【単一行文字】”, textObj.TextString, textObj.InsertionPoint, textObj)
foundCount = foundCount + 1
End If
ElseIf TypeOf ent Is AcadMText Then
Set mTextObj = ent
If InStr(1, mTextObj.TextString, SEARCH_KEYWORD, vbTextCompare) > 0 Then
Call OutputTextInfo(“【マルチテキスト】”, mTextObj.TextString, mTextObj.InsertionPoint, mTextObj)
foundCount = foundCount + 1
End If
End If
Next ent
Debug.Print “=== 検索終了. ヒット数: ” & foundCount & ” 件 ===”
MsgBox “検索が完了しました。イミディエイトウィンドウを確認してください。”, vbInformation, “完了”
CleanExit:
‘ 对象的参照解放
Set textObj = Nothing
Set mTextObj = Nothing
Set ent = Nothing
Set acadDoc = Nothing
Set acadApp = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume CleanExit
End Sub
‘ ==============================================================================
‘ 内部プロシージャ: 検出された文字の情報と座標・バウンディングボックスを出力
‘ ==============================================================================
Private Sub OutputTextInfo(ByVal textType As String, ByVal content As String, ByVal insPoint As Variant, ByVal ent As AcadEntity)
Dim minBox As Variant
Dim maxBox As Variant
‘ バウンディングボックス(境界ボックス)の取得
‘ 注: 回転がかかっている図形や一部のオブジェクトでエラーになることがあるためガードする
On Error Resume Next
ent.GetBoundingBox minBox, maxBox
On Error GoTo 0
‘ イミディエイトウィンドウへ詳細を出力
Debug.Print textType & ” 内容: ” & content
Debug.Print ” – 挿入点座標 X: ” & Format(insPoint(0), “0.00”) & _
“, Y: ” & Format(insPoint(1), “0.00”) & _
“, Z: ” & Format(insPoint(2), “0.00”)
‘ バウンディングボックスが取得できた場合のみ表示
If Not IsEmpty(minBox) Then
Debug.Print ” – 範囲(左下) X: ” & Format(minBox(0), “0.00”) & “, Y: ” & Format(minBox(1), “0.00”)
Debug.Print ” – 範囲(右上) X: ” & Format(maxBox(0), “0.00”) & “, Y: ” & Format(maxBox(1), “0.00”)
End If
Debug.Print “————————————————–”
End Sub
—
4. コードの解説とアーキテクトのこだわり
このコードが「なぜプロフェッショナル仕様なのか」、その急所を解説する。
① `TypeOf` による厳密な型判定と処理分岐
AutoCAD図面には線(Line)、円(Circle)、ハッチングなど無数のエンティティが存在する。`For Each ent In acadDoc.ModelSpace` でループを回す際、文字以外のオブジェクトもすべてヒットする。
そのため、`TypeOf ent Is AcadText` および `AcadMText` で明示的にフィルタリングし、余計なキャストエラーを未然に防いでいる。
② 大文字・小文字を無視する `vbTextCompare`
`InStr(1, textObj.TextString, SEARCH_KEYWORD, vbTextCompare)` の部分だ。
実務では半角・全角の混在や、アルファベットの大文字小文字の揺れが必ず発生する。`vbTextCompare`を指定することで、人間がストレスを感じる検索漏れをシステム側で完全に排除している。
③ バウンディングボックス(`GetBoundingBox`)の安全な取得
文字の中心座標だけでなく、その文字が「図面上のどの範囲を占有しているか」を知るために `GetBoundingBox` を採用した。
ただし、AutoCADのCOM APIは、特定の特殊なブロック内や未初期化のオブジェクトに対して `GetBoundingBox` を呼ぶと容赦なくエラーを吐く。そのため、あえて `On Error Resume Next` でガードをかけ、取得できなくても処理が止まらない「ノンストップ設計」にしている。
—
5. 発展:業務効率化(ファイル・データベース連携)への布石
このコードを単なる「マクロ」で終わらせてはならない。
ここで取得した座標データ(`insPoint` や `minBox`)を、CSVファイルへの出力や、外部データベース(SQLite / SQL Server)への自動登録に拡張すれば、以下のような超強力なシステムに昇華できる。
- 図面変更管理システム: 前後のリビジョン図面間で「注意」や「変更あり」の文字座標を比較し、設計変更漏れを自動検知する。
- 自動検図ロボット: 指定してはいけない禁止ワード(例:「TBD」など)が図面に残っていないかを夜間バッチで一斉スキャンし、レポートをSlackやTeamsに飛ばす。
結びにかえて
AutoCAD VBAはレガシーな技術だと言われることもある。しかし、図面というアナログとデジタルの境界線上に存在するデータ構造を直接叩き、一瞬で意のままに操るための「最強の武器」であることに変わりはない。
今回提供したコードをベースに、君たちの現場のワークフローを極限まで自動化してほしい。妥協のないコードだけが、エンジニアの自由な時間を生み出すのだ。
