AutoCAD オブジェクトモデル

オブジェクトモデル

AutoCAD の中の VLA オブジェクトの構造について概要を見ていきます。個々のオブジェクトについての詳細までは説明できないので、ヘルプを調べてください。

ActiveX のオブジェクトを使いこなすためには、AutoCAD のオブジェクトモデルのイメージについて知っておく必要があります。ActiveX を用いない場合は、entmake 関数で図形を作成したり、シンボルテーブルにアクセスすることによってレイヤーやブロックの情報を得たりと、各要素は図面データベース内でそれぞれ別々のところに有るかのように存在していますが、ActiveX を用いる場合は、オブジェクトの系統だった一つの木構造に統合されています。これは AutoCAD に限らず、他の ActiveX を用いるアプリケーションに見られる共通の構造です。

下に AutoCAD のヘルプに載っているオブジェクトモデルの図を示します。複雑に見えますが次の事を確認してください。

AutoCAD オブジェクトモデル

まず、角丸の四角がオブジェクトを表します。オブジェクトは個々の図形やレイヤーを表し、これはユーザーが図形を描いたり消したりすることによって図面データベースの中で増減します。

次に、角のとがった四角はコレクションを表します。コレクションもオブジェクトの一種ですが、これは要素をグループにまとめるもので、個々のオブジェクトはコレクションに登録されていることによって存在できます。例えば、layer オブジェクトは layers コレクションに登録されています。また、個々の図形要素の 3DFace オブジェクトや 3DPolyline オブジェクトは、Block コレクションか ModelSpace コレクション、あるいは PaperSpace コレクションなどといったものに含まれます。

これらのコレクションは Document オブジェクトに含まれます。Document オブジェクトは AutoCAD のマルチドキュメントの個々の図面に当たります。Document オブジェクトは Documents コレクションに含まれます。そして Documents コレクションは Application オブジェクトに含まれます。Application オブジェクトは AutoCAD アプリケーションそのものを指します。

このような階層構造となっていることが判った上で、具体的にオブジェクトを取得する方法について見ていきます。

アプリケーション

AutoLISP関数
(vlax-get-acad-object)
Application オブジェクトを取得します。
戻り値:VLAオブジェクト

vlax-get-acad-object 関数は、AutoCAD アプリケーションの Application オブジェクトを返します。関数の引数はありません。

_$ (vlax-get-acad-object) ⏎
#<VLA-OBJECT IAcadApplication 0000000140c89e48>

ここで得た Application オブジェクトを元にして、「vla-get-」を使ってプロパティにアクセスすることで、各コレクションやそこに含まれるオブジェクトを順にたどっていくことができます。Application オブジェクトがすべての始まりです。次は Application オブジェクトから Documents コレクションを得たうえで ModelSpace コレクションを得る例です。

(setq *document* (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq *model* (vla-get-ModelSpace *document*))

詳細は後述しますが、この ModelSpace コレクションに図形オブジェクトを追加したり削除したりすることで、【モデル空間】で図面の編集が行えます。

以降の実行例では、上のように *document* 変数に Document オブジェクトが代入されていることを前提としています。

コレクション

AutoCAD のオブジェクトモデルの中のコレクションオブジェクトは、種類は異なっても共通するメソッドやプロパティを持っています。代表的なのが Count プロパティと Item メソッドです。なお、これらは AutoCAD のコレクションでは問題ありませんが、後述の ActiveX オートメーションでの外部アプリケーションのコレクションでは、そのコレクションのプロパティやメソッドに応じた方法をとらなければいけない場合があります。

AutoLISP関数
(vla-get-Count collection)
collection:VLAオブジェクト(コレクション)
コレクションの要素数を返します。
戻り値:整数

vla-get-Count 関数は、コレクションの要素数を表す Count プロパティにアクセスするラッパー関数です。

Collection 引数は、調べるコレクションを指定します。

戻り値は、コレクションが保持している要素の数を整数で返します。

AutoLISP関数
(vla-item collection index)
collection:VLAオブジェクト(コレクション)
index:整数、また文字列
コレクションからインデックスを指定してVLAオブジェクトを取り出します。
戻り値:VLAオブジェクト

vla-item 関数は、インデックスを使用してコレクションから VLA オブジェクトを取り出す Item メソッドのラッパー関数です。

collection 引数は、調べるコレクションを指定します。

index 引数は、インデックスとして整数または文字列を指定します。整数のインデックスの有効範囲は 0 で始まり、コレクションの Count プロパティの -1 を上限とします。また、レイヤーや線種など AutoCAD ユーザーが名前で区別する VLA オブジェクトは文字列の Name プロパティを持っており、これをインデックスとして取り出すこともできます。

戻り値は、指定したインデックスの位置、又は名前のVLAオブジェクトです。インデックスが不正だった場合はエラーが発生します。

次の例は整数をインデックスとして、線種を格納している LineTypes コレクションから、線種一覧のリストを得る関数です。

(defun lineTypeNames (/ result linetypes count i)
  (setq linetypes (vla-get-LineTypes *document*)
        count     (vla-get-count linetypes)
        i         0
  )
  (repeat count
    (setq result (append result (list (vla-get-Name (vla-item linetypes i))))
          i      (1+ i)
    )
  )
  result
)

関数をロードして、実行すると以下のようになります。

_$ (lineTypeName) ⏎
("BYBLOCK" "BYLAYER" "CONTINUOUS" "HIDDEN" "CENTER" "CENTER2" "PHANTOM2" "HIDDEN2" "HIDDEN3" "CENTERB" "CENTERC" "HIDDENA" "HIDDENB" "HIDDENC" "PHANTOMC" "CENTERD" "PHANTOMB")

線種の名前が分かっている場合は、名前から LineType オブジェクトを得ることもできます。

_$ (vla-item (vla-get-LineTypes *document*) "HIDDEN")⏎
#<VLA-OBJECT IAcadLineType 000000000f0179c8>

こういった共通インターフェースを使ってコレクション内にアクセスする方法以外に、AutoLISP に用意されている関数を使って、コレクション内の各オブジェクト全体にアクセスする方法も用意されています。

AutoLISP関数
(vlax-for item collection [expr...])
item:シンボル
collection:VLAオブジェクト(コレクション)
expr:式
オブジェクトのコレクションに対し、各式を繰り返し評価します。
戻り値:最後に評価された expr の値

vlax-for 関数を使うとコレクションの要素に順次アクセスできます。LISP のリストにおける foreach 関数と同様の働きです。collention 引数から VLA オブジェクトを順次取り出し item に代入し、expr 引数で示される式を実行します。

戻り値は、最後に評価された expr の値となります。

次の例は線種を格納している LineTypes コレクションから、線種一覧のリストを得る関数の vlax-for 版です。

(defun lineTypeNames2 (/ ltype result)
  (vlax-for ltype (vla-get-LineTypes *document*)
    (setq result (append result (list (vla-get-Name ltype))))
  )
  result
)
AutoLISP関数
(vlax-map-collection collection 'function)
collection:VLAオブジェクト(コレクション)
function:関数
オブジェクトのコレクションに対し、各式を繰り返し評価します。
戻り値:最後に評価された expr の値

vlax-map-collection 関数は、コレクションの各 VLA オブジェクトに関数を適用します。LISP のリストの mapcar 関数に似た関数名ですが、前出の vlax-for を LISP 風に書き換えたものに過ぎません。function 引数に指定する適用関数は次のような構造となります。

(defun Foo (item)
    expr ...
)

適用関数はその副作用に意味があり、戻り値には意味がありません。vlax-map-collection 関数の戻り値は collection 引数で指定したコレクションそのものですが、ここがリストを返す mapcar 関数と決定的に異なる点です。

次の例は線種を格納している LineTypes コレクションから、線種一覧のリストを得る関数の vlax-map-collection 版です。

(defun lineTypeNames3 (/ result)
  (vlax-map-collection
    (vla-get-LineTypes *document*)
    (function
      (lambda (linetype /) (setq result (append result (list (vla-get-Name linetype)))))
    )
  )
  result
)

Block コレクションの取得

AutoCAD の図面には、一つの【モデル空間】と各レイアウトの【ペーパー空間】といった複数の「空間」があります。これらは AutoCAD オブジェクトモデルの中では Block コレクションとして表されており、このコレクションに図形オブジェクトを追加したり削除したりすることによって、各空間の図形を編集できます。

各空間のコレクションは、Layouts コレクション下 Layout オブジェクトの Block プロパティから得られる Block コレクションです。

AutoCAD Layouts correction

一方で Blocks コレクションは、各空間の Block コレクションと【ブロック図形】、そして外部参照の Block コレクションにアクセスできるコレクションです。個々の【ブロック図形】はそれぞれ Block コレクションとして表され、これが【ブロック図形】に定義された図形オブジェクトをコレクトしています。Blocks コレクション下の Block コレクション といった、やや混乱する名前の階層構造ですので注意してください。この Block コレクションに図形オブジェクトを追加したり削除したりすることで、【ブロック図形】の編集を行えます。ただし、スイープ図形など AutoCAD コマンドで生成する図形オブジェクトは、【ブロック図形】の Blockコレクション内ではコマンドが使えませんので作成できません。

AutoCAD Blocks collection

AutoCAD ユーザーにとっては【モデル空間】などの空間と【ブロック図形】は異なったもののように見えていますが、同じ Block コレクションを使って図形オブジェクトを保持しており、図形を追加したり削除したりして編集できる共通のものです。

Document オブジェクトのプロパティから、これら各所の Block オブジェクトにアクセスすることができます。なお、ここで「アクティブな【ペーパー空間】」とは、現在アクティブなレイアウトの【ペーパー空間】か、最も最近にアクティブだったレイアウトの【ペーパー空間】を意味します。

Document オブジェクトのプロパティ 説明
ActiveSpace 値が acModelSpace(1)の時【モデル空間】がアクティブ
値が acPaperSpace(0) の時【ペーパー空間】がアクティブ
システム変数 TILEMODE に対応するプロパティ
Blocks 【ブロック図形】やその他の Block コレクションを管理するコレクション
ModelSpace 【モデル空間】を指す Block コレクション
PaperSpace アクティブな【ペーパー空間】を指す Block コレクション
ActiveLayout 現在アクティブなレイアウトを指す Layout オブジェクト
Layouts 図面内の Layout オブジェクトを管理するコレクション
AutoCAD block object - space

システム変数 TILEMODE

タイプ: 整数型 保存先: 図面 初期値: 1

【モデル】タブまたは最後の【レイアウト】タブを現在のタブにします。

0 最後にアクティブだった【レイアウト】タブをアクティブにします。
1 【モデル】タブをアクティブにします。

各 Block コレクションを取得する方法は、目的の空間によってさまざまな方法がとられます。 最も単純なのが【モデル空間】です。

(setq *model* (vla-get-ModelSpace *document*))

特定のレイアウトの Block コレクションは layout オブジェクト経由でアクセスできます。ここでは「レイアウト」という名前のレイアウトの Block コレクションを取り出します。

(setq *paper* (vla-get-Block (vla-item (vla-get-Layouts *document*) "レイアウト")))

Layouts コレクションには【モデル空間】も含まれるので、Layouts コレクションからたどることによっても【モデル空間】の Block コレクションが得られます。

(setq *model* (vla-get-Block (vla-item (vla-get-Layouts *document*) "model")))

次に、特定の【ブロック図形】の Block コレクションを取得する場合は、 Blocks コレクションから検索します。次の例は、”Dot”という名前の【ブロック図形】の Block コレクションを取得しています。

(setq block (vla-item (vla-get-Blocks *document*) "Dot"))

なお、Blocks コレクションは各空間の Block コレクションも含んでいますので、ここからも【モデル空間】の Block コレクションを取得できます。

(setq *model* (vla-item (vla-get-Blocks *document*) "*MODEL_SPACE"))

このように目的の空間の Block コレクションを取得する方法は、ModelSpace プロパティだったり、Layouts コレクションを経由したり、Blocks コレクションからだったりと複数の経路が存在します。

Block コレクションの取得で最も需要があるのが、現在 AutoCAD ユーザーが操作している空間の block コレクションを得ることでしょう。これは ActiveLayout のプロパティから Layout オブジェクトを得て、そこから Blcok プロパティを得れば良いように思いますが、AutoCAD ユーザーがレイアウト上の【浮動ビューポート】をとおして【モデル空間】にアクセスしている場合は、期待に反して ActiveLayout プロパティは【ペーパー空間】のレイアウトを指したままです。

【モデル空間】や各レイアウトも含めて、現在アクティブな空間の Block オブジェクトを取得する場合は次のような関数を使います。

(defun ActiveSpaceBlock ()
  (if (or (= (vla-get-ActiveSpace *document*) acModelSpace)
          (/= (getvar "CVPORT") 1)
      )
    (vla-get-ModelSpace *document*)
    (vla-get-PaperSpace *document*)
  )
)