タイトル: Revit API:要素の取得とフィルタ
SEOタイトル: Revit API 要素取得|FilteredElementCollector・OfClass・OfCategory・BuiltInCategory・LINQ
| この記事の要点 |
|
Revit API で何かをするには、まず「対象の要素を集める」ことから始まります。その中心となるのが FilteredElementCollector です。要素を集めたら、編集は トランザクション 内で行います。
FilteredElementCollector の基本
FilteredElementCollector は、Document(またはビュー)を対象に要素を収集するクラスです。生成しただけでは全要素が対象ですが、フィルタを連結(チェーン)して絞り込みます。フィルタは「速い順序」で適用されるよう、まず種別系で絞ってから条件を加えるのが定石です。
全要素をやみくもに走査すると遅くなるため、必要なカテゴリやクラスで早めに絞り込むことがパフォーマンスの鍵です。コレクタは「遅延評価」で、最終的に列挙(foreach や ToList、ToElements)した時点で初めて実体化します。そのため、絞り込みフィルタを連結している途中ではコストがかからず、列挙時にまとめて評価されます。ビューを対象にした new FilteredElementCollector(doc, viewId) を使えば、そのビューに表示されている要素だけに対象を限定でき、大規模モデルでの高速化に有効です。
OfClass と OfCategory
絞り込みには2系統あります。
OfClass(typeof(Wall)): .NET のクラス型で絞る。Wall、FamilyInstance、ViewPlan などクラスが明確な場合に使う。OfCategory(BuiltInCategory.OST_Walls): Revit のカテゴリ(BuiltInCategory列挙体)で絞る。「ドア」「窓」「部屋」などカテゴリ単位で集めたい場合に使う。カテゴリ名はOST_DoorsやOST_RoomsのようにOST_接頭辞が付く。
壁インスタンスを取得する基本形は次の通りです(C#、記号はエスケープ表記)。
using Autodesk.Revit.DB;
using System.Collections.Generic;
using System.Linq;
// doc は Document
FilteredElementCollector collector =
new FilteredElementCollector(doc)
.OfClass(typeof(Wall))
.WhereElementIsNotElementType();
List<Wall> walls = collector.Cast<Wall>().ToList();
TaskDialog.Show("結果", "壁の数: " + walls.Count);
List<Wall> のようなジェネリクスを多用するため、型を意識してキャストするのがポイントです。
インスタンスとタイプの区別
Revit の要素には「タイプ(ElementType: 種類・規格の定義)」と「インスタンス(実際に配置された個体)」があります。コレクタはどちらも拾うため、目的に応じて絞ります。
WhereElementIsNotElementType(): 配置済みインスタンスのみ取得。「実際に建っている壁を数える」ような用途。WhereElementIsElementType(): タイプ定義のみ取得。「使用可能な壁タイプを列挙する」ような用途。
この絞り込みを忘れると、インスタンスとタイプが混在して件数が想定と合わなくなります。
ElementId と LINQ による加工
取得した各要素は ElementId で一意に識別されます。ID から本体を得るには doc.GetElement(id) を使います。逆に要素から ID は element.Id で取得できます。
コレクタは IEnumerable<Element> を実装するため、LINQ で柔軟に処理できます。たとえばカテゴリで集めた上で、特定の高さの壁だけを抽出するには次のように書きます。
var tallWalls = new FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_Walls)
.WhereElementIsNotElementType()
.Cast<Wall>()
.Where(w => w.get_Parameter(
BuiltInParameter.WALL_USER_HEIGHT_PARAM)
.AsDouble() > 10.0) // 内部単位フィート
.ToList();
LINQ の Where でロジックを表現し、Select で値へ変換、Cast で型を確定する、という流れが基本パターンです。比較する数値は内部単位(フィート)である点に注意してください。