今回は、Revit API を使って Revit データにアクセスする際の方法や考え方について、AutoCAD API と比較してご紹介していきます。デスクトップ製品をカスタマイズするために API として、概念自体に大きな違いはありませんが、実施に利用するクラスはメソッド、プロパティは全くの別物であることを認識してください。それでは、順にご案内しましょう。
オブジェクト識別子
AutoCAD API と同じように Revit API でも要素(オブジェクト)を識別するための 識別子 が存在します。Revit API では、通常、ElementId クラスを用いて、ファミリ インスタンスを含む各要素を一意に識別します。ElementId は 1 つのプロジェクト ファイル内では一意ですが、複数にプロジェクト ファイルを同時に扱う場合には、重複する可能性があります。
要素に割り当てられた ElementId は、ワークセットを利用した場合や、Revit をバージョン アップした際に、古いバージョンの Revit で作成したプロジェクト ファイルを開いた際に実行されるファイル マイグレーションで変化することがあります。外部のデータベースと連携したアプリケーションなど、常に一意に識別を維持した場合は、Element.UniqueId プロパティが返す識別子(文字列)を利用すべきです。
Application/UIApplication と Document/UIDocument
Revit API では、ユーザ インタフェースから可能なデータアクセスと、すべてのデータアクセスが、系統としてクラスとして区別されています。少々ニュアンスは異なりますが、Document と UIDocument で説明するばら、AutoCAD API の Database(.NET API)/AcDbDatabase(ObjectARX)と Document(.NET API)/AcApDocument(ObectARX)と考えるといいかも知れません。UIDocument クラスで特徴的なのは、ユーザが要素を選択する際に利用する Selection プロパティです。
アドインを定義する際に 必ず Execute メソッドを実装しますが、通常、パラメータとして渡される ExternalCommandData オブジェクトから、次のようなかたちで 4 つのオブジェクトを取得して、すぐに利用できるようにするのが一般的です。
public class Command : IExternalCommand |
モデリング/作図空間としてのコンテナ オブジェクトと作図メソッド
AutoCAD では、作図空間としてモデル空間やペーパー空間(レイアウト)が用意されています。また、ユーザ定義ブロックも、API 上では作図空間として位置づけられています。いずれの空間も .NET API では BlockTableRecord クラス、ObjectARX では AcDbBlockTableRecord クラスとして用意されています。Revit ではどうでしょう。作図空間にオブジェクトを追加する際には、メモリ上に構築したグラフィカル オブジェクトを追加する際には BlockTableRecord.AppendEntity メソッド(.NET API)やAcDbBlockTableRecord::appendAcDbEntity() メンバ関数(ObjectARX)を利用すれば、どんなグラフィカル オブジェクトでも追加できるシンプルさを持っています。
Revit API 上ではどうかと言うと、残念ながら、AutoCAD とは全く異なる考え方を持っています。要素(オブジェクト)を追加して保存する先は、Document オブジェクトで、AutoCAD API で言う Database(.NET API)/AcDbDatabase(ObjectARX)で、考え方は同じです。ただし、空間という考え方は存在しません。また、ファミリ カテゴリ毎の異なる配置ルールを含めて考えていく必要があります。
例えば、新しいファミリ インスタンスを作成する場合には、Document クラスの Create プロパティを静的に利用して NewFamilyInstance メソッドを呼び出す必要があります。この NewFamilyInstance メソッドには、用途に合わせて 12 個のオーバーロード メソッドが用意されています。つまり、作成しようとするファミリ インスタンスが、どのような振る舞いで、どの要素にホストされるのかを、あらかじめ把握して利用する必要があるのです。具体的には、窓は壁にホストされますが、床にはホストされません。これを NewFamilyInsyance メソッドで表現するには、ホストとなる要素(床)をパラメータとして与えられるオーバーロードを利用する必要があるわけです。
また、システム ファミリを作成する場合には、利用するメソッドが変わります。例えば、床の作成には Document.NewFloor メソッドを、フットプリント屋根の作成には Document.NewFootPrintRoof メソッドを、それぞれ利用します。壁の場合はどうかと言うと、NewWall メソッドというメソッドはなく、Wall クラスを静的に利用した Wall.Create メソッドを利用する必要があります。Wall.Create メソッドも、用途に合わせて 5 個のオーバーロード メソッドが用意されています。
把握するのがなかなか難しいので、実際には、Revit SDK 内に用意された膨大なサンプル プロジェクトから、具体的な利用方法を探していく作業がどうしても必要になってしまいます。この厄介さを回避する目的で、バージョンアップ時にクラスやメソッド、プロパティの統廃合や変更を続けている、という側面もあるのも事実です。
ドキュメントの単位
Revit で扱うプロジェクト ファイル(.rvt)やファミリ ファイル(.rfa)内部が持つ長さ単位は、基本的にフィート単位です。このため、Revit API で各種情報にアクセスする場合には、取得した値をメートルに変換したり、設定する値をフィートに変換する処理が必要になります。
これを変換するために、Revit API には UnitUtils クラスが用意されています。このクラスに含まれるメソッドを使って、各種内部単位をミリメートルやメートルに相互変換することが出来ます。
基本単位 | Revit の単位 | 単位系 |
---|---|---|
長さ | フィート(ft) | インチ/フィート単位 |
角度 | ラジアン | メートル単位 |
マス | キログラム(kg) | メートル単位 |
時刻 | 秒(s) | メートル単位 |
電流 | アンペア(A) | メートル単位 |
温度 | ケルビン(K) | メートル単位 |
光度 | カンデラ(cd) | メートル単位 |
オブジェクトの選択
Selection.PickObject メソッドでユーザに要素を 1 つさせることが出来ます。また、Selection.PickObjects メソッドでは、複数の要素を選択させることが出来ます。Selection.PickElementsByRectangle メソッドでは、矩形領域内の要素を複数選択することも出来ます。同様に、Selection.PickPoint メソッドで座標を指示させることも可能です。
AutoCAD と違って、交差選択や窓選択、ラバーバンドといった処理を意図的に設定するオプションはありません。ただし、PickPoint メソッド利用時に有効なオブジェクト スナップを指定することは出来ます。
フィルタリング
ファミリ インスタンスやファミリ、その他、非ファミリ要素が多数存在するプロジェクト ファイルでは、効率的に目的とする要素を取得する方法が提供されています。その方法で代表的なのが、 FilteredElementCollector クラスの利用です。AutoCAD で例えるなら、実際にオブジェクト選択をせずに、フィルタリング機能を使って選択セットを作成するようなものと考えてください。
FilteredElementCollector クラスは、LINQ クエリーとともに利用することも出来ます。
シンボル名の注意
プロジェクト ファイル内のファミリ シンボル、要素などに名前(シンボル名)が付けられています。その名前を使ったフィルタリングをおこなうと、目的の要素を簡単に取得することが出来ます。Revit API を習得する場面では、このシンボル名が原因で、実行時エラーに遭遇することがあります。原因は、Revit SDK に含まれるサンプルの多くが、英語版の Revit で作られたプロジェクト ファイルやファミリを想定しているためです。
例えば、壁を作成する際に指定するレベル名が、サンプルでは "Level 1" となっています。このようなサンプルを日本語テンプレートから作成したプロジェクト ファイルを開いて実行すると、レベル名が "レベル 1" となっているため、例外が発生します。この問題は、ビュー名や参照面名など当てはまります。このため、可能な場合には、言語に依存しないように BuiltInParameter 列挙値を使ってパラメータから取得、利用するようにすることが推奨されています。
イベント
AutoCAD API と同じように、ドキュメント関連やデータベース関連のイベント処理をすることが出来ます。ただし、AutoCAD ほど多彩でシステム レベルのイベントは用意されていません。例えば、 AutoCAD API では、作図領域上のマウス カーソルの動きを Editor.PointMonitor (.NET API)や AcEdInputPointMonitor::monitorInputPoint()(ObjectARX)でモニタして座標値をチェックしたり、その座標値を使って、マウス カーソル下にあるオブジェクトの情報を取得するといった処理実装が出来ますが、Revit API では、Revit 自身が BIM モデルの中で一定程度の拘束を処理するため、このような処理の実装はサポートされていません。
また、AutoCAD では、データベース イベントを使って、あるオブジェクトの変更を別のオブジェクトに反映するような処理も実装できます。非常に柔軟な処理が可能なのですが、一方で、無限ループを誘発させてしまう危険性も合わせ持っています。Revit API では、この危険性を回避しながら、同様の実装を可能にする ダイナミック モデル アップデータ と呼ばれる特別なイベント処理が提供されています。 これを利用することで、壁長を変更した際に、配置された窓を自動的に壁長の中央に配置するといった処理を安全に実装することが出来るようになります。
拡張ストレージ
IFC レベルにも、BIM モデルとして Revit 上にもないカスタム情報を要素に付加したい場合、AutoCAD の拡張エンティティ データや拡張ディクショナリに相当する 拡張ストレージ という機能を利用することが出来ます。拡張ストレージの利用時には、あらかじめスキーマを使って付加する情報タイプを定義しておく必要があります。
Revit Loopup ツール
API を使って開発やデバッグをしていく際には、Revit プロジェクト ファイル(.rvt)やファミリ ファイル(.rfa)上の様々な要素の情報を参照したい場面が多くあるはずです。こんな時には、Revit SDK で提供されている Revit Lookup ツールを利用してみてください。Revit Lookup ツールは、.NET Framework が提供する リフレクション を使って、Revit API のクラス名やプロパティ名で、各種情報を表示する機能を提供します。
Revit Lookup ツールは、C:\Revit SDK 2014\RevitLookup\CS フォルダに Visual Srudio プロジェクトとして提供されているので、ビルド後に同じフォルダにある RevitLookup.addin アドイン マニフェストを適切に修正して、Revit が認識するパスに保存することで、外部アプリケーションとして登録されたリボン パネルから利用できます。
特に、要素を選択してから [Snoop Current Selection...] を使うと、その要素が持つ情報を API レベルで参照することが出来ます。また、[Snoop DB...] を使えば、特定の要素を選択することなく、プロジェクト内の情報をマウスクリックしながら走査していくことが出来ます。
例えば、下図のように、植栽のファミリ インスタンスを選択後に、 [Snoop Current Selection...] コマンドをクリックすると、[Snoop Objects] ダイアログにファミリ インスタンス(FamilyInstance クラス)が持つアクセスを閲覧することが出来ます。このダイアログ上で Category 部分をクリックすると、別のダイアログが開き、FamilyInstance.Category プロパティにアクセスして得られる情報を表示します。Name を参照することで、このカテゴリが「植栽」であることがわかります(Category.Name プロパティ相当)。
Revit Lookup ツールを利用することで、Revit API でアクセスできる範囲を想定することが出来ると考えて差し支えありません。
コマンド
Revit に標準で組み込まれているコマンドを、すべて同じように Revit API で模倣することが出来ない場合があります。例えば、Revit API を使って天井を自動作図することは、現在できません(API が公開されていない)。このよう場面では、UIApplication.PostCommand メソッドを使って、PostableCommand 列挙値として定義されている Revit 標準コマンドを指定することで、ユーザ インタフェースから起動するのと同じようにコマンドを実行させることが出来ます。次のコードは、独自に定義した外部コマンド内部から [天井] コマンドを呼び出すものです。
public class Command : IExternalCommand RevitCommandId id = } } |
なお、AutoCAD のようにコマンド オプションをあらかじめ指定したりすることは出来ません。コマンドを起動することが出来るのみです。
まとめ
Revit の持つ製品としてのルールや、BIM モデルが持っているルール(拘束、パラメータなど)は、当然、AutoCAD には存在しないものです。AutoCAD は、カスタマイズ プラットフォームとして様々な業種、業態で利用できるよう、このようなルールは最低限なものしかありません。これが、AutoCAD と Revit の最も大きな違いです。どのカスタマイズでも言えることですが、製品が持つ「文化」を重視しないと、製品の特徴や操作性を損なう結果になってしまいます。
By Toshiaki Isezaki
コメント