Revit APIで要素を抽出する(1)（Revit API アドベントカレンダー2024 13日目）

Qiita Revit API アドベントカレンダー2024の13日目の記事です。

（前回の記事はこちら）

https://qiita.com/thivanao/items/b1c55374e35837bd1a0e

# 今回の内容

今回は、Revitアドインの基本中の基本である要素(Element)の抽出方法について整理したいと思います。

# 要素とは

本題に入る前に、Revitにおける「要素(Element)」について再確認しましょう。

Revitのモデル内に含まれる情報は、基本的にこの要素として表現されています。
モデル上に実際に配置されるインスタンスはもちろんのこと、その定義情報であるところのタイプやファミリなども要素の一種となります。

Revit APIでのプログラミング上では、要素はElementクラスという基本クラスに該当し、以下のような共通機能を提供しています。（以下は一例）

* ID(rvtファイル毎に一意の通し番号)
* UniqueId(rvtファイルに関わらず一意で割り振られるユニークなID)
* パラメタ
* カテゴリ
* 名前
* 位置及びレベル
* 所属ドキュメント

https://www.revitapidocs.com/2024/eb16114f-69ea-f4de-0d0d-f7388b105a16.htm

:::note warn
余談ですが、Revit2024よりIDに使用される数値（rvtファイル内での通し番号）のデータサイズが32bit整数値から64bit整数値に拡大されました。
バージョン間の移植時には注意が必要です。
:::

後述する要素抽出方法（フィルタによるもの、ユーザの選択操作によるもの、等）では、基本的にこのElement型（またはElement型を導出することができるElementId型やそれらを導出できる情報）で結果を取得でき、必要に応じてダウンキャストを用いることで特定の型に変換できます。

# Elementの抽出（取得）方法の分類

Revit APIを用いてElement型のオブジェクトを取得する方法は、大きく分けると以下のようなものがあります。

|取得方法|利用API|説明|
|:-|:-|:-|
|1.フィルタによる抽出|FilterdElementCollector|カテゴリやBoundingBoxなどの各種抽出条件を組み合わせて、ドキュメント内に存在するすべての要素から条件に合うものをリストで取得できる。|
|2.要素識別子の直接指定|Document.GetElement|要素を識別する情報（ElementId、ユニークID、参照）からElementを直接取得する。ElementIdを経由することで通し番号（整数値）やGuid、BuiltinParameterから取得することも可能。|
|3.パラメタからの取得|Parameter.AsElementId|パラメタの種類がElementIdになっているもの（Parameter.StorageTypeがStorageType.ElementIdのもの）の場合に取得できる。|
|4.3Dモデル上の視線方向ヒットテスト|ReferenceIntersector|3Dビューとフィルタ、Ray（半直線で表現する視線方向）などを指定することで、3D的に干渉する要素の参照を順次取得できる。（参照経由で要素の取得が可能）|
|5.選択中要素|Selection.GetElementIds|呼び出し時点で選択中とされている要素のリストを取得できる。|
|6.ユーザによる選択|Selection.PickObject<br>Selection.PickObjects<br>Selection.PickElementsByRectangle|ユーザ入力待ちを発生させ、ユーザが選択操作を行った対象の要素または要素への参照を取得できる。|

以下で、それぞれの取得方法について解説していきます。

# 1.フィルタによる抽出

指定したDocumentからElementを抽出する FilteredElementCollector クラスと、抽出条件を指定してフィルタリングを行う ElementFilter 派生クラスにより要素を列挙する方法です。

https://www.revitapidocs.com/2024/263cf06b-98be-6f91-c4da-fb47d01688f3.htm

https://www.revitapidocs.com/2024/b8b46cbf-9ecc-0745-ec53-c3c3b6510113.htm

メソッドチェーンの形で複数のフィルタや遅延実行処理をつなげることも可能です。

```csharp
FamilyInstance[] familyInstances = new FilteredElementCollector(doc)
   	.OfCategory(BuiltInCategory.OST_StructuralFraming)      // カテゴリフィルタ
	.OfClass(typeof(FamilyInstance))                        // 型フィルタ
	.WherePasses(new BoundingBoxContainsPointFilter(point)) // ElementFilterクラスの指定
	.Where(fi => fi.Symbol.FamilyName == "ABCファミリ")      // ラムダ式による絞り込み
	.Cast<FamilyInstance>()                                 // キャスト
	.ToArray();                                             // 配列化（即時実行）
```

上記コード例に示す通り、LINQの遅延実行をメソッドチェーン内に含めることで、配列等のコンテナ領域確保処理を1回だけにとどめることが可能です。

## フィルタの分類（高速・低速・結合）

Revitで用意されている要素フィルタは大きく３種類に分類されます。

* 論理フィルタ（ElementLogicalFilter派生クラス）
* 高速フィルタ（ElementQuickFilter派生クラス）
* 低速フィルタ（ElementSlowFilter派生クラス）

### 論理フィルタ

論理フィルタはANDフィルタ(LogicalAndFilter)とORフィルタ(LogicalOrFilter)の二種類です。
これらはその名の通り、コンストラクタで指定した2つのフィルタについてAND条件（両方の条件に合致している要素を抽出する）及びOR条件（いずれかの条件に合致している要素を抽出する）でのフィルタリングを行います。

https://www.revitapidocs.com/2024/3e334aaf-2b39-58bd-d2cc-94e9c89bac57.htm

https://www.revitapidocs.com/2024/a00da224-d330-452d-a45f-5abffa2e57e6.htm

```csharp
var filter1 = new ElementClassFilter(typeof(FamilyInstance));
var filter2 = new ElementCategoryFilter(BuiltInCategory.OST_Doors);
var doorInstancesFilter = new LogicalAndFilter(filter1, filter2);
FilteredElementCollector collector = new FilteredElementCollector(doc);
IList<Element> doors = collector.WherePasses(doorInstancesFilter).ToElements();
```

:::note info
但し、「絞り込み」という性質上、ANDフィルタを使用しなくても複数フィルタを指定した場合は必然的にAND条件になるため、一般的にはANDフィルタを利用する必要性はありません。
:::

### 高速フィルタ

高速フィルタは各要素のデータをメモリ展開しなくても（索引情報だけで）フィルタの適合・不適合の判断が可能な内容についてのフィルタです。
高速フィルタで「足切り」を行っておくことで、詳細情報を参照する要素の数が限定され、抽出処理の高速化につながります。

|高速フィルタクラス|説明|
|:-|:-|
|[BoundingBoxContainsPointFilter](https://www.revitapidocs.com/2024/a5ea9f5a-ddba-9db7-eaa0-2b37098f0142.htm)|指定点が要素のBoundingBoxに含まれるか？|
|[BoundingBoxIntersectsFilter](https://www.revitapidocs.com/2024/1fbe1cff-ed94-4815-564b-05fd9e8f61fe.htm)|指定したBoundingBoxが要素のBoundingBoxと干渉するか？|
|[BoundingBoxIsInsideFilter](https://www.revitapidocs.com/2024/eb8735d7-28fc-379d-9de9-1e02326851f5.htm)|指定したBoundingBoxが要素のBoundingBoxに内包されるか？|
|[ElementCategoryFilter](https://www.revitapidocs.com/2024/b492ddf4-3058-8f9b-dfcc-8d5c4abb3605.htm)|指定カテゴリか？(OfCategoryと同等)|
|[ElementMulticategoryFilter](https://www.revitapidocs.com/2024/8d2774eb-3c47-5c3d-2866-8d4ab7408d2d.htm)|指定されたカテゴリか？（複数指定）|
|[ElementClassFilter](https://www.revitapidocs.com/2024/4b7fb6d7-cb9c-d556-56fc-003a0b8a51b7.htm)|指定された型か？(OfClassと同等)|
|[ElementMulticlassFilter](https://www.revitapidocs.com/2024/acb0ecb3-afcb-4e94-641d-450716e9ac73.htm)|指定された型か？（複数指定）|
|[ElementIdSetFilter](https://www.revitapidocs.com/2024/b13469b1-1ef3-23af-feb5-4dc847ab6359.htm)|指定されたIdか？（複数指定）|
|[ExclusionFilter](https://www.revitapidocs.com/2024/28581bc9-42ad-9178-edcc-e33f42090bc9.htm)|指定されたId以外か？（複数指定）|
|[ElementOwnerViewFilter](https://www.revitapidocs.com/2024/cfaecf4c-b6b9-1481-de4f-e8d74e743911.htm)|指定されたビューが所有する要素か？|
|[VisibleInViewFilter](https://www.revitapidocs.com/2024/2425b0fb-7b28-1609-e45e-f1e196885248.htm)|指定したビューで表示される要素か？|
|[ElementIsElementTypeFilter](https://www.revitapidocs.com/2024/607fd199-b1ba-f21f-ad98-33b65fbf5fe5.htm)|ElementTypeか？|
|[FamilySymbolFilter](https://www.revitapidocs.com/2024/24cfdb4a-07e4-522d-4b9a-e0bba9387d5f.htm)|指定したファミリシンボルか？|
|[ElementDesignOptionFilter](https://www.revitapidocs.com/2024/bde93f54-1852-8a32-aca5-a1c23e607b91.htm)|指定されたDesign Optionか？|
|[ElementIsCurveDrivenFilter](https://www.revitapidocs.com/2024/f4538d9d-e681-d486-f466-0a3de13bf2cc.htm)|LocationがLocationCurveで表現される要素か？|
|[ElementStructuralTypeFilter](https://www.revitapidocs.com/2024/e9b102e4-ef0d-15c7-98e9-e5887050d301.htm)|指定されたStructuralTypeか？|
|[ElementWorksetFilter](https://www.revitapidocs.com/2024/9fef9119-9ab1-b63a-15a3-804d08228d7e.htm)|指定されたWorkSetか？|
|[ExtensibleStorageFilter](https://www.revitapidocs.com/2024/81cb1798-3dbe-658b-5a04-d97aa2cb4de9.htm)|指定したGuidの拡張ストレージを持つ要素か？|

### 低速フィルタ

低速フィルタは既定義のフィルタではあるものの、各要素の詳細情報を参照しないと適合の有無を判断できないような条件を判断するため、高速フィルタよりは処理時間を要するフィルタです。
可能な限り高速フィルタで絞り込んだ後で、これらの低速フィルタを利用するのが望ましいとされています。

|低速フィルタクラス|説明|
|:-|:-|
|[RoomFilter](https://www.revitapidocs.com/2024/356881b1-5ee4-621a-0379-965c3e6f6dcf.htm)|要素が部屋か？|
|[RoomTagFilter](https://www.revitapidocs.com/2024/24dc181b-f767-f32d-7ae4-2c41ff1ceba9.htm)|要素が部屋タグか？|
|[AreaFilter](https://www.revitapidocs.com/2024/a13bb51e-5370-99ed-d212-bdd60297393d.htm)|要素がエリアか？|
|[AreaTagFilter](https://www.revitapidocs.com/2024/23cb7fbc-e93c-e3ea-54ca-e17a82d4116c.htm)|要素がエリアタグか？|
|[SpaceFilter](https://www.revitapidocs.com/2024/aefc66b3-bbf1-f66a-4901-953137e9c051.htm)|要素がスペースか？|
|[SpaceTagFilter](https://www.revitapidocs.com/2024/b552fa72-06b5-fee9-507e-2e97afe8241e.htm)|要素がスペースタグか？|
|[CurveElementFilter](https://www.revitapidocs.com/2024/d31574f5-4400-c4f9-04dd-4418c302e3c5.htm)|指定したCurveElementTypeに該当する要素か？|
|[ElementIntersectsElementFilter](https://www.revitapidocs.com/2024/404df79f-2e48-ad4d-2654-a49aa5bf4443.htm)|指定した要素と干渉している要素か？|
|[ElementIntersectsSolidFilter](https://www.revitapidocs.com/2024/19276b94-fa39-64bb-bfb8-c16967c83485.htm)|指定したSolidと干渉している要素か？|
|[ElementLevelFilter](https://www.revitapidocs.com/2024/844e4928-e11a-563f-b1e4-d4d16b8bd76b.htm)|指定したレベルか？|
|[ElementParameterFilter](https://www.revitapidocs.com/2024/b0b40351-690c-eb5d-30c2-d4447a42fda1.htm)|指定したパラメタのFilterRuleに合致する要素か？|
|[ElementPhaseStatusFilter](https://www.revitapidocs.com/2024/7767020a-2564-2c46-689d-59c2abe6e777.htm)|指定したPhase Statusに合致する要素か？|
|[FamilyInstanceFilter](https://www.revitapidocs.com/2024/ec0bdad7-e213-f22a-94ef-bc0fd96ac641.htm)|指定したファミリシンボルに合致するファミリインスタンスか？|
|[PrimaryDesignOptionMemberFilter](https://www.revitapidocs.com/2024/9d96ca9c-c89a-818c-44bb-63e5926b72fd.htm)|要素がPrimary Design Optionか？|
|[FamilyStructuralMaterialTypeFilter](https://www.revitapidocs.com/2024/964fd00d-21ec-b212-07b5-159c85bbc021.htm)|指定したStructuralMaterialTypeに合致する要素か？|
|[StructuralInstanceUsageFilter](https://www.revitapidocs.com/2024/d75dfb58-cf2f-1d33-20f1-add1cedad770.htm)|指定したStructuralInstanceUsageに合致する要素か？|
|[StructuralMaterialTypeFilter](https://www.revitapidocs.com/2024/8f1f6134-11dd-3c10-a4df-d11f30ee9ae8.htm)|指定したStructuralMaterialTypeに合致する要素か？|
|[StructuralWallUsageFilter](https://www.revitapidocs.com/2024/43b4c666-5f81-bd42-dfb5-d1d86f517dee.htm)|指定したStructuralWallUsageに合致する要素か？|
|[SelectableInViewFilter](https://www.revitapidocs.com/2024/4def5498-f47f-870c-ea25-0408b6603dac.htm)|指定されたビューから選択可能な要素か？|

少し長くなったので今日はここまで。
次回は引き続き要素抽出方法の2～6について説明します。

## このシリーズの予定
(1) [RevitAPIについてのリンク集](https://qiita.com/thivanao/items/cbee5072aa582672888c)
(2) [Revitでの幾何計算(1)](https://qiita.com/thivanao/items/866bdcaf092ee315e39b)
(3) [Revitでの幾何計算(2)](https://qiita.com/thivanao/items/b1c55374e35837bd1a0e)
(4) Revit APIで要素を抽出する(1) ★今回★
(4b) Revit APIで要素を抽出する(2)
(5) Revitアドインのエントリーポイント
(6) RevitでCADっぽい挙動（ラバー・一時図形・ラージカーソル）を実現してみる
(7) Revitアドイン開発 Debug Tips