Outer Walls, Lookup Update and Filtering

Returning once again to freshen up a few of our favourite recurring topics:

RevitLookup 2023.1.0

A new version of RevitLookup is available.

RevitLookup release 2023.1.0 includes the following enhancements:

They are discussed in more depth in the enhancements discussion #124.

Thank you very much, Roman, Роман @Nice3point Карпович, for your great ideas and diligent maintenance work!

Filter Multiple Built-In Categories

A short note from the Revit API discussion forum thread on filtering different built-in categories at the same time:

Question: Is it possible to filter different BuiltInCategories at same time?

Because I want to improve my code efficiency in my big Revit file, so I only want to filter once.

Or is there any other way to get instances of these built-in categories in a list?

bic_beam = DB.BuiltInCategory.OST_StructuralFraming
bic_collumn = DB.BuiltInCategory.OST_StructuralColumns
bic_beam_tag = DB.BuiltInCategory.OST_StructuralFramingTags
bic_collumn_tag = DB.BuiltInCategory.OST_StructuralColumnTags

So far, I only know the basic collector and filtering for one BuiltInCategory:

collector = DB.FilteredElementCollector(doc, doc.Active.Id)
beam_filter = DB.ElementCategoryFilter(DB.BuiltInCategory.OST_StructuralFraming)
beam_elements = collector.WherePasses(beam_filter ).ToElementIds()

Answer: First, a comment on your second code snippet: it is always advisable to use the filter shortcuts.

In this case, use OfCategory instead of ElementCategoryFilter + WherePasses. It is shorter, clearer, and guarantees that you are using a quick filter.

Second, the answer to your question is yes. I think this is the one and only purpose of the FilterCategoryRule class.

Read the article on how to use FilterCategoryRule for more info.

It also mentions how you can easily achieve the same without using FilterCategoryRule, by using a Boolean OR combination filter of ElementCategoryFilter instances, showing how that approach can be used to:

For yet more info, please refer to The Building Coder topic group on filtering for elements.

Last but not least, you can also use the ElementMulticategoryFilter class, a filter used to find elements whose category matches any of a given set of categories, e.g.:

cat_list = [BuiltInCategory.OST_Walls, BuiltInCategory.OST_Windows, BuiltInCategory.OST_Doors, BuiltInCategory.OST_Floors, BuiltInCategory.OST_Ceilings]
types = List[BuiltInCategory](cat_list)
multiCat = ElementMulticategoryFilter(types)
Elements = FilteredElementCollector(doc).WherePasses(multiCat).WhereElementIsNotElementType().ToElements()

Response: Thank you! That is exactly what I need!

Two questions to clarify:

So, the two approaches OfCategory and ElementCategoryFilter + WherePasses both achieve the same goal. In addition, both ways are quick filters. However, using OfCategory directly can be more readable and clearer.

Is that right?

I will compare using FilterCategoryRule with ElemenetMulticategoryFilter.

Answer: Yes, that is absolutely correct.

I prefer ElementMulticategoryFilter myself, now I think about it. It is clearer and more direct. It did not exist when I originally implemented the samples to retrieve MEP elements and structural elements, or I would have opted for that back then.

Retrieving All Outer Walls

Mark de Vries of ICN Development shared some important real-world considerations in the discussion about how to get all the outermost walls in the model that we edited and shared here four years ago in the article on FilterRule use and retrieving exterior walls:

This algorithm to create a room around the building and let it determine its boundary walls is the most reliable and fastest solution to this particular problem of finding the exterior walls of a building. It also works better with, e.g., Dutch drawing practice, where compound walls are split into individual walls for its layers, making approaches that rely on isExternal properties or the count of bounded rooms unreliable at best.

There is however one caveat that is important to keep in mind. This is essentially a 2D approach to finding boundaries, as you are working with boundary lines, and not planes. This appears to be a fundamental limitation of the Revit API. This is not normally a problem for this particular algorithm, but it will become one if your model has vertically stacked walls within a single level. In that case, only one wall of that stack will be found, usually the one closest to the bottom of the temporary room.

There are of course workarounds to this: Determine the z-heights of each wall in the stack and create a separate room for each of those heights. This of course has to be done for every wall that falls into or crosses a particular z-height range that you are interested in, so the scan for finding all the z-heights that need to be checked separately can be time consuming for large designs.

I am guessing the BuildingEnvelopeAnalyzer needs a cell size variable to solve this same problem (though they are more likely to internally use a horizontal section plane to find intersecting walls and determine the exterior walls from a much smaller set of candidates).

So, the room around the entire design is probably the best solution with the least requirements, but it will need some non-trivial modifications to be able to handle designs with stacked walls.

Thank you, Mark, for sharing your valuable knowledge and experience.

Zen and the Art of React Programming

An unusual and beautiful two-and-a-half-hour full-length feature film with beautiful views on how to build Gmail-like UI with React Native at the Zen temple Koshoji is chockful of information and calming at the same time.

Zen and the Art of React Programming