こんにちは!AutoCAD VBAの世界へようこそ。
日々、図面データの集計や一括処理に頭を悩ませていませんか?「マクロの記録」から一歩踏み出し、オブジェクトモデルを操れるようになると、AutoCADは最強の相棒になります。
今回は、実務の現場で必ずといっていいほど直面する「複雑な条件での図形選択」をテーマにお届けします。
VBAの標準機能では記述が複雑になってしまう処理を、AutoLISPの強力なエンジンを借りてスマートに解決する「ハイブリッド手法」を伝授しましょう。
ここをクリアすれば、あなたのAutoCAD VBAスキルは間違いなく中級者から上級者へとシフトします。肩の力を抜いて、一緒に見ていきましょう!
—
1. なぜVBAのフィルタリングだけでは限界があるのか?
AutoCAD VBAで図面上のオブジェクトを効率よく捕まえるために、`SelectionSets`(選択セット)という強力な機能が用意されています。特定の画層(Layer)やオブジェクトの種類(LWPOLYLINE, INSERTなど)で絞り込む「DXFグループコード」を使ったフィルタ機能ですね。
例えば、「画層 `A-WALL` にある、すべての線分を取得したい」という程度であれば、VBAの標準フィルタだけでも十分に書くことができます。
しかし、実務の図面はもっと複雑です。
- 「特定の画層にあり、かつ、特定の属性(アトリビュート)を持つブロック参照を一網打尽にしたい」
- 「図面全体(画面外も含めて)から、特定の条件に合致する要素をノータイムで抽出したい」
こんな要求が出てきたとき、VBA標準の `Select` メソッドやループ処理だけで書こうとすると、コードが驚くほど冗長になり、何より処理速度が劇的に遅くなります。図面全体を `ModelSpace` から `For Each` で総なめにするなんて、オブジェクトの数が数万個を超えた日にはコーヒーを淹れにいけるほどの時間がかかってしまいますよね。
—
2. 救世主:AutoLISPの `ssget “_X”` と `AcadApplication.Eval`
そこで登場するのが、AutoCADの裏側で静かに強力な仕事をこなすAutoLISP(オートリスプ)の力です。
AutoLISPには、図面データベースから一瞬で条件に合うオブジェクトを釣り上げる `ssget` という伝説的な選択関数があります。特に `”_X”` 引数(図面全体を対象とする)と組み合わせたフィルタリング能力は、VBAの比ではありません。
「でも、私はVBAを書いているんだから、LISPなんて分からないよ……」
ご安心ください。VBAから `AcadApplication.Eval` メソッドを使うことで、VBAのコードの中から直接AutoLISPの式を評価・実行し、その結果を受け取ることができるのです。
これこそが、VBAとAutoLISPの美味しいところ取りをした「ハイブリッド・エンジニアリング」です。
—
3. 【実践】VBAからAutoLISPを召喚するコード例
百聞は一見に如かず。実際にコードを見てみましょう。
以下のコードは、「特定の画層(例: “C-ANNO-TEXT”)に存在する、すべてのブロック参照(INSERT)」を、AutoLISPの `ssget` を使って一撃で選択し、その数をVBAのメッセージボックスで表示するサンプルです。
Sub SelectBlocksWithLispEval()
Dim acadApp As AcadApplication
Dim lispExpr As String
Dim result As Variant
Dim ssName As String
‘ 1. AutoCADのアプリケーションオブジェクトを取得
Set acadApp = ThisDrawing.Application
‘ 2. 実行したいAutoLISPのコードを文字列として組み立てる
‘ (ssget “_X” ‘((0 . “INSERT”) (8 . “C-ANNO-TEXT”)))
‘ 意味:図面全体(_X)から、タイプがINSERT(0 . “INSERT”)で、画層がC-ANNO-TEXT(8 . “C-ANNO-TEXT”)のものを選択し、選択セット名(文字列)を返す
lispExpr = “(ssget “”_X”” ‘((0 . “”INSERT””) (8 . “”C-ANNO-TEXT””)))”
On Error GoTo ErrorHandler
‘ 3. AcadApplication.Eval を使ってLISP式を評価する
‘ ※ EvalはAutoLISPの評価結果(今回は選択セットの名前を表す文字列、例: “S1″)を返す
result = acadApp.Eval(lispExpr)
‘ 4. 結果の判定
If VarType(result) = vbEmpty Or IsNull(result) Then
MsgBox “条件に一致するオブジェクトは見つかりませんでした。”, vbInformation, “結果”
Else
ssName = CStr(result)
‘ 5. 取得した選択セット名を使って、VBA側でAcadSelectionSetオブジェクトに変換する
Dim targetSS As AcadSelectionSet
Set targetSS = ThisDrawing.SelectionSets.Item(ssName)
MsgBox “抽出成功! 対象のブロック数: ” & targetSS.Count & ” 個”, vbInformation, “ハイブリッド検索完了”
‘ 務めが終わった選択セットは必ずメモリから解放(削除)する
targetSS.Delete
End If
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “致命的なエラー”
End Sub
コードのここがポイント!
- `AcadApplication.Eval`: VBAからAutoLISPの世界へダイレクトに文字列を投げ込み、その計算結果をVBAの変数(Variant型)に持ち帰ることができます。
- DXFグループコードの指定: `(0 . “INSERT”)` は「図形種別がブロック参照」、ビ `(8 . “C-ANNO-TEXT”)` は「画層名」を指しています。ここを書き換えるだけで、どんな複雑な条件も自由自在です。
- メモリ管理の鉄則: AutoCADのLISPが生成した選択セットは、VBA側から `ThisDrawing.SelectionSets.Item(ssName)` として参照できます。使い終わったら 必ず `.Delete` でメモリから破棄 してください。これをサボると、次に同じ名前のセットを作ろうとしたときにエラーの温床になります。
—
4. 陥りやすい罠とエンジニアの知見
この手法は非常に強力ですが、いくつか「知っている者だけが避けて通れる罠」があります。現場でハマらないために、以下のポイントを頭の片隅に置いておいてください。
1. 文字列のエスケープ(ダブルクォーテーションの重ね方)
VBAのコード内でLISPの文字列リテラルを書く際、ダブルクォーテーション(`”`)の中にさらに `”` を入れたい場合は、VBAの仕様として `””`(二重)にする必要があります。
- 正解例:`””INSERT””`
ここを間違えると、VBAのコンパイルエラーやLISPの構文エラーを引き起こします。
2. 選択セット名の衝突を防ぐ
`ssget` が返す選択セット名は自動的にシステム側で割り振られますが、VBAの `SelectionSets` コレクションに同名のものが既に残っていると衝突エラーを起こします。必ず事前に既存の同名セットを削除する、あるいは今回のようにLISPが返した名前をそのまま安全にラップするハンドリングを心がけましょう。
—
おわりに
いかがでしたでしょうか?
今回は、VBAの枠を超えてAutoLISPのエンジンを `Eval` で叩くという、ワンランク上のアプローチをご紹介しました。
「VBAじゃできないから諦めよう」ではなく、「どうすればAutoCADの懐に入り込んで効率よく処理できるか」を考え始めると、業務自動化の可能性は無限に広がっていきます。
ここをクリアしたあなたなら、もうマクロの記録の卒業生ではありません立派なAutoCAD自動化エンジニアです。ぜひ、日々の実務データ処理に取り入れて、定時退社を勝ち取ってくださいね!それでは、また次の知見でお会いしましょう。
