FilteredElementCollector Documentation

We covered the basics of FilteredElementCollector in the previous video. But now let's actually have a look at the methods in the documentation and go through others.

FilteredElementCollector Documentation

We covered the basics of FilteredElementCollector in the previous video. But now let's actually have a look at the methods in the documentation and go through others.

Summary

FEC in Revit API Docs

By now you know the basics of FEC, and it will be enough 80-90% of the time. But sometimes you will try to get more specific elements or you need to do something with your collector.

So let's open Revit API Documentation and explore FilteredElementCollector Class.

Constructors

Let's begin by looking at the Constructors, because this is the first step whenever we work with FEC.

Constructor: Regular

We already covered the First Constructor in the previous video. It's very simple, we just provide doc from where we want to get our elements.

collector = FilteredElementCollector(doc)
Constructor: Elements in View

The Second constructor allows you to get elements only from a specific View. We just need to provide ElementId of a desired view as a second argument.

It's actually used quite often, depending on the tool you are creating.

view      = doc.ActiveView #Example
collector = FilteredElementCollector(doc, view.Id)

💡 Be aware that this constructor will need to load provided view, so it might take longer on large projects!

Constructor: Set of Elements

Lastly, we can use the Third constructor that allows you to provide a set of elements from a document.

It takes 2 arguments: doc and List[ElementId]()

# .NET Imports
import clr
clr.AddReference('System')
from System.Collections.Generic import List

# List of ElementIds
el_ids      = [ElementId(12345), ElementId(12346), ElementId(12347), ]
List_el_ids = List[ELementId](el_ids)

# FilteredElementCollector with a set of elements
if List_el_ids:
    collector  = FilteredElementCollector(doc, List_el_ids )

💡 This might be useful if you want to use one of the FEC methods or Revit API filters to filter elements in your list. But for that you need to understand FEC methods.

👀 And on this note, let's dive into FEC methods, and see what else is possible to filter.

Methods

First of all let me explain.

While many methods provide functionality to collectors, there are many FEC methods for quickly and easily applying Revit API Filters.

You can even read that in the description of methods.

For example WhereElementIsElementType method says that it applies ElementIsElementTypeFilter to the collector.

💡Developers have added methods for the most common Filters, so they are more accessible and easier to use.

👀 We will focus on Filters in more detail in the next module, but I will show you one example in the end of this post!

For now, let's just start with methods in the same order as they are written in the Docs.

This method will allow you to get elements related to a specific DesignOption.

It takes 1 argument: ElementId of the DesignOption.

So we will need to get DesignOptions as well.

Have a look at the snippet below to see how it works.

# 👉 .ContainedInDesignOption()

#1️⃣ Get All Design Options
all_design_opts = FilteredElementCollector(doc)\
                        .OfClass(DesignOption)\
                        .ToElements()

#2️⃣ Iterate Through DesignOptions if any.
if all_design_opts:
    for design_opt in all_design_opts:
        
        # 3️⃣  Get All Elements from DesignOption      
        opt_collector = FilteredElementCollector(doc)\
                        .ContainedInDesignOption(design_opt.Id)\
                        .WhereElementIsNotElementType()\
                        .ToElements()

        # 4️⃣  Get only Walls from DesignOption
        opt_collector_walls = FilteredElementCollector(doc)\
                                .ContainedInDesignOption(design_opt.Id)\
                                .OfClass(Wall)\
                                .WhereElementIsNotElementType()\
                                .ToElements()
        #5️⃣ Print Results
        print('Design Option [{}] has {} Elements'.format(design_opt.Name, len(opt_collector)))
        print('Design Option [{}] has {} Walls'.format(design_opt.Name, len(opt_collector_walls)))

Let's break it down.

1️⃣ FIrst we need to get DesignOptions in the project
2️⃣ Then if we get any, we can iterate through them
3️⃣ Get All Elements from DesignOption
4️⃣ Get Only Walls from DesignOption by adding .OfClass(Wall) method
5️⃣ Print Results

💡We can keep adding more FEC methods to apply more filters.

Dispose

This method is used to destroy FilteredElementCollector to release resources and it doesn't take any arguments.

💡To be honest, I doubt you will notice any difference by destroying collectors, so just leave them alone.

But if you want to dispose, check out this Snippet 👇

collector = FilteredElementCollector(doc).OfClass(Wall)
# Do something
collector.Dispose()

This method will allow you to exclude elements from FilteredElementCollector.

Here is an example of how to exclude currently selected elements from FEC query.

# 👉 .Excluding()

# Get Current Selection
selected_element_ids = uidoc.Selection.GetElementIds()

if selected_element_ids:
    # Get Everything in view Excluding selected elements
    excl_collector = FilteredElementCollector(doc, active_view.Id).Excluding(selected_element_ids)\
        .WhereElementIsNotElementType().ToElements()
else:
    excl_collector = FilteredElementCollector(doc, active_view.Id)\
        .WhereElementIsNotElementType().ToElements()

print('There are {} Elements Excluding current selection in the Active View'.format(len(excl_collector)))

💡 Be aware that you need to provide List[ElementId]().

In my case it is being returned from uidoc.Selection.GetElementIds() when I get my selection. But if you get your elements differently, you might need to convert to .NET List.

FirstElement / FirstElementId

We covered these in the previous lesson.
They return a random single Element or ElementId.

#1️⃣ Create Collector and get Wall Instances
collector  = FilteredElementCollector(doc)\
              .OfClass(Wall)\
              .WhereElementIsNotElementType()

#2️⃣ Get Random Element / ElementId
random_wall    = collector.FirstElement()
random_wall_id = collector.FirstElementId()
.NET Methods

👇 Then you will see the following methods:

We won't need these methods as they return you objects that might be used in C#.

💡 Just ignore all of them. At least that's what I did, and I never looked back at them.

IsViewValidForElementIteration

Identifies if the particular view is valid for iteration of drawn elements.
It checks if a view is able to represent drawn elements.

For example ViewTemplates and ViewSchedule will fail this check!
For example: we can use this method to verify if we can get elements from a view using second constructor: FEC(doc, view_id)

Here is an example

#1️⃣ Get all View3D Elements
collector_view3d = new FilteredElementCollector(document).OfClass(View3D)

#2️⃣ Get the Id of the first View3D
view_id = collector_view3d.FirstElementId()

#3️⃣ Test if the view is valid for element filtering
if (FilteredElementCollector.IsViewValidForElementIteration(doc, view_id):
  
    #4️⃣ Get visible Walls in the view
    viewCollector = new FilteredElementCollector(doc, view_id).OfClass(Wall)

OfCategory / OfCategoryId / OfClass

We covered these methods in the previous lesson, and they are the most used methods when we work with FilteredElementCollector in my opinion.

Choose one of them and provide the appropriate argument!

#1️⃣ OfCategory
all_walls_by_cat = FilteredElementCollector(doc)\
                     .OfCategory(BuiltInCategory.OST_Walls)\
                     .ToElements()
print("Walls using OfCategory: {}".format(len(all_walls_by_cat)))

#2️⃣ OfCategoryId
wall_cat_id = ElementId(BuiltInCategory.OST_Walls)
all_walls_by_cat_id = FilteredElementCollector(doc)\
                        .OfCategoryId(wall_category_id)\
                        .ToElements()
print("Walls using OfCategoryId:{}".format(len(all_walls_by_category_id)))

#3️⃣ OfClass
all_walls_by_class = FilteredElementCollector(doc).OfClass(Wall).ToElements()
print("Walls using OfClass: {}".format(len(all_walls_by_class)))
OwnedByView / WhereElementIsViewIndependent

These methods both apply the same filter ElementOwnerViewFilter to FilteredElementCollector but one of them gives you reversed results.

They filter 3D or 2D elements depending on which one you use.
2D Elements are OwnedByView, because they are only shown in a single view.

👇 You can use these Snippets to get these elements and only print unique types to get an idea of what they return.

# 👉 .OwnedByView()
owned_view_collector = FilteredElementCollector(doc)\
                       .OwnedByView(active_view.Id)\
                       .ToElements()

# Print Unique Types
unique = []
for el in view_independent_elements:
    if type(el) not in unique:
        unique.append(type(el))
        print(type(el))
# 👉 WhereElementIsViewIndependent()
view_independent_elements = FilteredElementCollector(doc)\
                             .WhereElementIsViewIndependent()\
                             .ToElements()

# Print Unique Types       
unique = []
for el in view_independent_elements:
    if type(el) not in unique:
        unique.append(type(el))
        print(type(el))

ToElementIds / ToElements

These 2 methods you already know really well.

Not only you learnt about them in the previous lesson, we also used them throughout this lesson. So I guess we can skip an example 😉

UnionWith

Combine multiple collectors into one by using this method.

Usually I use python lists to combine elements that come out of collectors, but use this method if you want to combine 2 collectors and then keep using FEC's methods or apply more Revit API Filters!

Here is an example

#1️⃣ Create Collectors
wall  = FilteredElementCollector(doc).OfClass(Wall)
floor = FilteredElementCollector(doc).OfClass(Floor)
#💡DO NOT USE .ToElements() if you want to use UnionWith()

#2️⃣ Combined Collector
collector = walls.UnionWith(floors)

#3️⃣ Use New Collector
instances = collector.WhereElementIsNotElementType() #Keep Filtering...
WhereElementIsCurveDriven

This method applies an ElementIsCurveDrivenFilter.

If you are going to look inside this Filter you will see the following description:
"A filter used to match elements which are curve driven."

It didn't help to understand it either…

But if we scroll down to Remarks:

"The term "curve driven" indicates that the element's Location property is a LocationCurve. Example elements found by this filter include walls, beams, and curve elements. "

So if you look inside your elements in RevitLookup, you can check Location property.

In my case I have a Wall snooped, and it says that Location has an element of class LocationCurve.

This is what this filter will check.

👇 Here is an example of how to use.

# 👉 .WhereElementIsCurveDriven()
curve_driven_elements = FilteredElementCollector(doc)\
                         .WhereElementIsCurveDriven()\
                         .ToElements()

# Print Types of Element
unique = []
for el in curve_driven_elements:
    if type(el) not in unique:
        unique.append(type(el))
        print(type(el))

💡 It will also print you all unique types of elements so you get a better understand of what is being returned.

WhereElementIsElementType / WhereElementIsNotElementType

These 2 methods apply ElementIsElementTypeFilter, and it's quite self explanatory.

One will return you Types and the other Instances.

And you already know really good how to use it 😉

WherePasses

And lastly, WherePasses method.

This method take a single argument - ElementFilter and applies it to the collector.
This is a base class for Revit API Filters.

We will cover filters in the next module in great detail, but for now let's have a look at 1 example of how to use it.


I want to show you how to use ElementMulticategoryFilter

As you can see it takes a single argument of ICollection[BuiltInCategory]().
But we will use List[BuiltInCategory]() instead.

Here is an example

# 👉 .WherePasses()

#1️⃣ Create List of Categories
cats = [BuiltInCategory.OST_Walls,
        BuiltInCategory.OST_Floors,
        BuiltInCategory.OST_Roofs,
        BuiltInCategory.OST_Ceilings]
List_cats = List[BuiltInCategory](cats)

#2️⃣ Create Filter
multi_cat_filter = ElementMulticategoryFilter(List_cats)

#3️⃣ Apply Filter to FEC
combined_collector = FilteredElementCollector(doc)\
                           .WherePasses(multi_cat_filter)\
                           .WhereElementIsNotElementType()\
                           .ToElements()

# 👀 Print Results                           
print(combined_collector)

1️⃣ First of all we need to prepare a list of categories.

I made a python list of categories that I wanted to combine and then converted it into List[BuiltInCategory]

2️⃣ Create ElementMulticategoryFilter instance by providing our list as argument.

3️⃣ Once you have a Filter, we can provide it as an argument in WherePasses(filter)

💡 We can add as many filters as we want!

Or we can combine all of them using LogicalFilters, and you will learn about all of this in the next module.

Questions:

When is next module about filter coming?

When is next module about filter coming?

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API