こんにちは!今日もAutoCADの自動化、楽しんでいますか?
「マクロの記録」を卒業し、自分の手でコードを書き始めると、図面が単なる「絵」ではなく「データの宝庫」に見えてくるはずです。
今回のテーマは、実務で非常に要望の多い「図面内にあるすべての線分(Line)から、始点・終点座標と長さを引っこ抜いてリスト化する」という処理です。
一見シンプルですが、ここにはAutoCAD VBAの心臓部である「オブジェクトモデルの階層構造」と「Variant型配列の扱い」という、中級者へステップアップするために避けては通れない極めて重要なエッセンスが凝縮されています。
「VBAはなんとなくわかるけれど、AutoCAD特有の動きでいつもエラーが出る…」という方も安心してください。この記事を読めば、エラーの原因を根本から理解し、実務でガシガシ使える堅牢なコードが書けるようになりますよ。
それでは、深く、そして分かりやすく解説していきましょう!
—
1. AutoCADオブジェクトモデルの「階層構造」を理解する
コードを書く前に、私たちがこれからアクセスする「図面データの世界」の地図を頭に入れておきましょう。
AutoCAD VBAは、以下のような美しいピラミッド構造(オブジェクトモデル)で成り立っています。
[AcadApplication] (AutoCAD本体)
│
[AcadDocument] (現在開いている図面:ThisDrawing)
│
[AcadModelSpace] (モデル空間:図形が実際に描かれている場所)
│
┌───┴───────────────┐
[AcadLine] [AcadCircle] [AcadText] … (個々の図形オブジェクト)
図面から線分(`AcadLine`)を探し出すということは、「モデル空間(ModelSpace)という箱の中に入っているおもちゃ(Entity)を1つずつ取り出して、『君は線分(Line)かい?』と問いかける」という作業に他なりません。
—
2. 実践コード:図面内の全線分データを抽出する
まずは、そのままコピー&ペーストして使える完成されたコードをご紹介します。
ただログを出すだけでなく、実務での使いやすさを考慮して、計算結果をイミディエイトウィンドウ(VBAの出力画面)に美しく整列させて出力する仕様にしています。
VBAエディタ(Alt + F11)を開き、標準モジュールを挿入して貼り付けてみてください。
Option Explicit
Sub ExportAllLinesInfo()
‘ =================================================================
‘ 機能: 図面内の全線分(Line)の始点・終点・長さを取得してリスト化
‘ 開発者向けアドバイス: イミディエイトウィンドウに結果が出力されます
‘ =================================================================
Dim objEntity As AcadEntity ‘ モデル空間内の汎用図形オブジェクト
Dim objLine As AcadLine ‘ 線分にキャスト(型変換)するための変数
Dim lngCount As Long ‘ 処理した線分の数を数えるカウンター
‘ 座標を格納するための変数(AutoCADの座標はVariant型の配列で返されます)
Dim varStartPoint As Variant
Dim varEndPoint As Variant
‘ 距離(長さ)を計算するための変数
Dim dblLength As Double
Dim dblDx As Double, dblDy As Double, dblDz As Double
‘ 1. 開始ログの出力
Debug.Print “==================================================”
Debug.Print “線分データ抽出処理を開始します…”
Debug.Print “Index | 始点(X, Y, Z) -> 終点(X, Y, Z) | 計算長さ | API長さ”
Debug.Print “==================================================”
lngCount = 0
‘ 2. モデル空間(ModelSpace)内のすべての図形をループ処理
For Each objEntity In ThisDrawing.ModelSpace
‘ 3. 図形の種類が「線分(Line)」であるか判定
If TypeOf objEntity Is AcadLine Then
‘ objEntityを「線分」として安全に扱うためにキャスト
Set objLine = objEntity
‘ 4. 座標データの取得
‘ StartPoint / EndPointプロパティは「要素数3のDouble型配列」を内包したVariantを返します
varStartPoint = objLine.StartPoint
varEndPoint = objLine.EndPoint
‘ 5. 三次元ピタゴラスの定理による距離(長さ)の計算
dblDx = varEndPoint(0) – varStartPoint(0) ‘ Xの差分
dblDy = varEndPoint(1) – varStartPoint(1) ‘ Yの差分
dblDz = varEndPoint(2) – varStartPoint(2) ‘ Zの差分
‘ 距離の公式: √(dx^2 + dy^2 + dz^2)
dblLength = Sqr(dblDx ^ 2 + dblDy ^ 2 + dblDz ^ 2)
‘ 6. カウントアップと結果の出力
lngCount = lngCount + 1
‘ イミディエイトウィンドウに見やすくフォーマットして出力
Debug.Print Format(lngCount, “000”) & ” | ” & _
FormatPoint(varStartPoint) & ” -> ” & _
FormatPoint(varEndPoint) & ” | ” & _
Format(dblLength, “0.000”) & ” | ” & _
Format(objLine.Length, “0.000”)
End If
Next objEntity
‘ 7. 終了処理とメモリの解放
Debug.Print “==================================================”
Debug.Print “処理が正常に完了しました。検出された線分: ” & lngCount & ” 件”
Debug.Print “==================================================”
‘ オブジェクト変数の明示的解放(メモリリーク防止のグッドプラクティス)
Set objLine = Nothing
Set objEntity = Nothing
End Sub
‘ —————————————————————–
‘ 補助関数: 座標配列(Variant)を “X, Y, Z” の文字列に整形する
‘ —————————————————————–
Private Function FormatPoint(ByVal varPoint As Variant) As String
FormatPoint = Format(varPoint(0), “0.0”) & “, ” & _
Format(varPoint(1), “0.0”) & “, ” & _
Format(varPoint(2), “0.0”)
End Function
—
3. 先輩が教える!このコードの「一歩深い」解説
コードをただコピペするだけでなく、「なぜこう書いているのか」の理由を知ることで、あなたのVBA力は飛躍的に向上します。重要なポイントを3つに絞って解説します。
① `TypeOf … Is AcadLine` によるスマートな型判定
図面の中には、円(Circle)や文字(Text)、ポリライン(Polyline)など、様々な図形が混在しています。
それらを無視して、いきなり「線分として座標をちょうだい!」と命令すると、プログラムは「型が違います(エラー 13)」と怒って止まってしまいます。
If TypeOf objEntity Is AcadLine Then
この一瞬の判定を入れることで、数ある図形の中から「線分」だけを安全に、かつ高速にフィルタリングしています。
② AutoCAD VBA最大の罠:「Variant型に包まれた座標配列」
AutoCAD VBAを始めた人が最も躓きやすいのが、座標の扱いです。
`objLine.StartPoint` が返す値は、単一の数値ではありません。「X座標、Y座標、Z座標の3つの実数が入った配列」です。
VBAの仕様上、これを受け取る変数は必ず `Variant` 型(何でも入る魔法の型)で宣言する必要があります。
Dim varStartPoint As Variant
varStartPoint = objLine.StartPoint
‘ 取り出すときはインデックスを指定する
‘ varStartPoint(0) -> X座標
‘ varStartPoint(1) -> Y座標
‘ varStartPoint(2) -> Z座標
これを `Dim StartPoint(2) As Double` のように固定長配列として受け取ろうとするとエラーになります。「座標はVariantで受け取って、添字(0〜2)で分解する」と暗記してしまって構いません。
③ なぜAPIの `.Length` があるのに、わざわざ数式で計算したのか?
コードの中で、三次元ピタゴラスの定理(`Sqr(dx^2 + dy^2 + dz^2)`)を使って自前で長さを計算している部分があります。
「`objLine.Length` プロパティがあるんだから、そっちを使えばいいのでは?」と思ったあなた、素晴らしい着眼点です!
あえて数式で計算して並べて出力したのには、2つの理由があります。
1. 数学的アプローチへの慣れ: 将来、線分の長さだけでなく「特定の2点間の距離」や「図形同士の干渉」を計算する際、このベクトル計算の知識が必須になるため。
2. 検証(ダブルチェック): APIが返す値(`.Length`)が、数学的に導き出した値と完全に一致することを確認し、コードの信頼性を担保するため。
—
4. 実務で絶対に躓かないためのプロの知恵(アドバンスド)
実務の現場では、図面内のオブジェクト数が数万件に及ぶことも珍しくありません。よりプロフェッショナルな開発を目指すためのアドバイスです。
1. パフォーマンスの最適化(画面更新を止める)
もし、この処理の後に「線分の色を変える」などの描画変更処理を追加する場合、処理のたびに画面が再描画(Regen)されると、PCがフリーズしたようになります。
大量の要素を処理する場合は、以下のように一時的に自動更新を制御するのがプロの技です。
ThisDrawing.Utility.Prompt “処理を実行中…”
‘ (ここにループ処理)
ThisDrawing.Regen acActiveViewport ‘ 最後に1回だけ再描画する
2. ペーパー空間やブロック内の線分は?
今回のコードは `ThisDrawing.ModelSpace`(モデル空間)の直下にある線分のみを対象にしています。
もし「レイアウト(ペーパー空間)」や「ブロック定義の中」にある線分も取得したい場合は、ループの対象を `ThisDrawing.Blocks` などに変更し、再帰的に探索する必要があります。まずは今回の基本をマスターしてから、ステップアップとして挑戦してみてください。
—
まとめ:ここをクリアすれば、AutoCAD VBAの基本はバッチリ!
お疲れ様でした!
今回学んだ内容は、AutoCAD VBAの基礎でありながら、応用範囲が最も広い領域です。
- オブジェクトモデルの階層をたどる
- 特定の図形タイプ(AcadLine)だけを狙い撃ちする
- Variant型の座標配列を分解して活用する
この3つのテクニックは、円(Circle)の半径や中心座標を取得するときも、文字(Text)の内容を書き換えるときも、全く同じ考え方で応用できます。
一歩ずつ、確実にコードの意味を理解しながら進めていけば、どんなに複雑な自動化ツールも必ず作れるようになりますよ。
何か分からないことや、「次はこんな処理に挑戦したい!」というリクエストがあれば、いつでも先輩に相談してくださいね。あなたの業務自動化への挑戦を、心から応援しています!
