Logical Filters in Revit API

Last type of filters in Revit API - Logical Filters. There are only 2 classes, and they are used to combine other filters by using OR/AND Logic. Let's learn how to use them.

Logical Filters in Revit API

Last type of filters in Revit API - Logical Filters. There are only 2 classes, and they are used to combine other filters by using OR/AND Logic. Let's learn how to use them.

Summary

Logical Filters

Let's cover the last type of Filters in Revit API - Logical Filters.
There are only 2 filters, so it will be very easy!

They are simply about combining other filters with AND / OR logic.
Meaning, that when you combine multiple filters together, either any of these filters or all of them have to return True to filter elements.

Think of View Filters in Revit. They also have this option to select AND/OR filters.

Revit API - Quick Filters

FEC Shortcut:

None

Combine Multiple Filters. The filter passes when all filters in the set pass.

FEC Shortcut:

None

Combine Multiple Filters. The filter passes when all filters in the set pass.

FEC Shortcut:

None

Combine Multiple Filters. The filter passes when any filter in the set passes.

FEC Shortcut:

None

Combine Multiple Filters. The filter passes when any filter in the set passes.

Why Using Logical Filters?

Mainly, logical filters are used to make code more efficient and to make filter combinations that aren't possible otherwise.

Sometimes, it's possible to avoid using them, and apply all the filters with shortcuts to our collector. But, when we start creating filters in loops, we might notice that efficiency starts to drop off. So usually, it's worth the effort when you need to improve the efficiency of your scripts.

We will have a good example of comparing the efficiency of using LogicalFilter in the lesson about Intersection Filters (07.06).

But, until then, let's keep it simple.

How to Create Logical Filters? (Constructors)

Let's have a look in the Revit API Documentation on how to create these filters.
LogicalAndFilter and LogicalOrFilter have identical Constructors.

There are 2 ways:

1️⃣ We can either create a List[ElementFilter]() to combine as many filters as we want.
2️⃣ Or, we can combine 2 Filters by providing them as 2 arguments.

💡Keep in mind that we can use LogicalFilters as arguments as well!

Let's have a look at a few simple examples of how to create LogicalFilters.

Example 1️⃣: LogicalOrFilter (Combine 2 Filters)

First, let's explore LogicalOrFilter.

We will keep it simple, and ignore the fact that, in this example we could use ElementMultiCategoryFilter... Focus on the Logical filter now to understand it!

#1️⃣ Example 1 LogicalOrFilters (Combine 2 Filters)
door_cat = ElementCategoryFilter(BuiltInCategory.OST_Doors)
win_cat  = ElementCategoryFilter(BuiltInCategory.OST_Windows)

cat_filter = LogicalOrFilter(door_cat, win_cat)

collector = FilteredElementCollector(doc).WherePasses(cat_filter)

In this example we will create 2 ElementCategoryFilters and combine them in a LogicalOrFilter.

So, it means that any of these filters should return True to get the elements. Therefore, we will get all Windows and Doors by using it.

Example 2️⃣: LogicalOrFilter (Combine 2+ Filters)

Let's have a look on how to use second constructor in case we have more than 2 filters.

We will need to create a List[ElementFilter] and add all the filters we want, and use it as an argument.

💡 Don't forget to import it

# 2️⃣ Example 2 LogicalOrFilters (Combine 2+ Filters)
door_cat = ElementCategoryFilter(BuiltInCategory.OST_Doors)
win_cat  = ElementCategoryFilter(BuiltInCategory.OST_Windows)
gen_cat  = ElementCategoryFilter(BuiltInCategory.OST_GenericModel)

filters = List[ElementFilter]()
filters.Add(door_cat)
filters.Add(win_cat)
filters.Add(gen_cat)

cat_filter = LogicalOrFilter(filters)


collector = FilteredElementCollector(doc).WherePasses(cat_filter)

Same as previously, we create 3 filters, but this time we combine them in a List[ElementFilter] to use the second constructor.

And again, since we use OR logic, any of these filters has to return True to get an element.

Example 3️⃣: LogicalAndFilter

Now, let's have a look at LogicalAndFilter.

It will be the same in terms of code, but all conditions will have to be meet for elements to be filtered out.

Here is an example of combining an ElementCategoryFilter and an ElementClassFilter

💡Again, keep in mind that it would be better to use OfCategory / OfClass, but focus on understanding LogicalFilters instead.

❗We will cover more complex examples in a moment.

#3️⃣ Example 3 LogicalAndFilters ()
f_door_cat = ElementCategoryFilter(BuiltInCategory.OST_Doors)
f_instance = ElementClassFilter(FamilyInstance)

f_combined = LogicalAndFilter(f_door_cat, f_instance)

collector  = FilteredElementCollector(doc).WherePasses(f_combined)

#💡 Make sure your LogicalFilters makes sense to use
# collector = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Doors).OfClass(FamilyInstance)
Example 4️⃣: LogicalAndFilter + LogicalOrFilter

Now, let's create a more interesting example where you will understand why we want to combine our filters using LogicalFilters.

Combining 2-3 filters, is not why they are used. They are used when you can create an 'n' number of filters depending on a for loop that you are making, or special AND/OR combinations of filters you are trying to achieve.

In this example, we will use both LogicalAndFilter and LogicalOrFilter. Also, we will create a UI form to ask the user for levels to create ElementLevelFilters.

In this case, we don't know how many Levels the user will select, and therefore it makes sense to use logical filters to combine them all into a single filter!

Here is the snippet:

#4️⃣ Example 4 LogicalAndFilter + LogicalOrFilter

# Categories OR Filter
door_cat   = ElementCategoryFilter(BuiltInCategory.OST_Doors)
win_cat    = ElementCategoryFilter(BuiltInCategory.OST_Windows)
filter_cat = LogicalOrFilter(door_cat, win_cat)


# Levels OR Filter
all_levels = FilteredElementCollector(doc).OfClass(Level)

sel_lvls = forms.SelectFromList.show(all_levels,
                                multiselect=True,
                                name_attr='Name',
                                button_name='Select Levels')

lvl_filters = List[ElementFilter]()
for lvl in sel_lvls:
    lvl_f = ElementLevelFilter(lvl.Id)
    lvl_filters.Add(lvl_f)
filter_levels = LogicalOrFilter(lvl_filters)


# FamilyInstance
filter_instance = ElementClassFilter(FamilyInstance)


# Combine
last_filter   = LogicalAndFilter(filter_cat, filter_levels)
last_filter   = LogicalAndFilter(last_filter, filter_instance)


# Get Elements
collector      = FilteredElementCollector(doc).WherePasses(last_filter)

for el in collector:
    print(type(el), el.Id)

1️⃣ First of all we want to filter Doors and Windows, so let's create a LogicalOrFilter.

2️⃣ Then, let's get all levels, and create a form by using SelectFromList from pyrevit.forms

3️⃣ After that, we can iterate through all selected levels and combine them in a list of LevelFilters to create a LogicalOrFilter

4️⃣ Then, let's also add an ElementClassFilter so we only get instances by providing the FamilyInstance Class.

5️⃣ Lastly, we want to combine all these filters. I will just use LogicalAndFilter 2 times, to quickly combine them, but we could also create a list of filters.

6️⃣ And now, we can create a collector.

It will have the following criteria in human language:

Get me elements that:
- Have a Category of Door OR Window
- They are placed on one of the Selected Levels
- AND they have a Class of FamilyInstance

Example 5️⃣: EF-Tools Select Similar Example

Lastly, you can explore the code I wrote 3 years ago for selecting similar types in Revit. As you remember, we couldn't do that in Revit before…

❗Keep in mind that the code was never refactored properly, and I was very new to Revit API filters back then. So it's not a perfect example. In fact, I am a bit embarrassed to use it as an example. But it works!

And you also get to see how LogicalFilters can be useful when you are making lots of filters in for loops and you need to combine them.

👇Here is the link to GitHub to see the code:

When to use LogicalFilters

I know that you might not have a good idea of when to use LogicalFilter right now, but that's fine!

You will know it when you need to use one, because your script logic will tell you that. Or you will have slow run time when you use filters inside for loops inefficiently and you decide to improve that.

Just keep in mind that we can combine filters using AND / OR logic and you will know when you need it.

⌨️ Happy Coding!

Questions:

Are LogicalFilters More Efficient?

Are LogicalFilters More Efficient?

Should I use Shortcut methods or Logical Filter?

Should I use Shortcut methods or Logical Filter?

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