As I’ve said before on AUGI, if you aren’t using Filters in your command development then you should be with Revit 2009. However as you start to use them in more complicated scenarios your code can get a little unwieldy.
In this post I’m going to show you some methods to tidy up your code a little. In the following example we’re going to get all doors where the sill is less than 0.0 above the floor level and all windows where the sill is less than 760mm above the floor level. Here is the standard filter approach.
1: Autodesk.Revit.Application rvtApp = commandData.Application;
2: //Doors
3: Filter doors = rvtApp.Create.Filter.NewCategoryFilter(BuiltInCategory.OST_Doors);
4: // get all instances with sill less than zero
5: Filter sillLTZeroFilters = rvtApp.Create.Filter.NewParameterFilter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM,CriteriaFilterType.LessThan, 0.0);
6: Filter doorSillsFilter = rvtApp.Create.Filter.NewLogicAndFilter(doors, sillLTZeroFilters);
7: //Windows
8: Filter windows = rvtApp.Create.Filter.NewCategoryFilter(BuiltInCategory.OST_Windows);
9: Filter window760Filter = rvtApp.Create.Filter.NewParameterFilter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM, CriteriaFilterType.LessThan, 760.0);
10: Filter windowSillsFilter = rvtApp.Create.Filter.NewLogicAndFilter(windows, window760Filter);
11: // finished filter
12: Filter completeFilter = rvtApp.Create.Filter.NewLogicOrFilter(windowSillsFilter, doorSillsFilter);
13: ElementIterator itor = rvtApp.ActiveDocument.get_Elements(completeFilter);
Here’s 3 techniques for simplifying your code:
1.. Class libraries
You can combine standard filter functionality in your own libraries. For example I’ve defined one that &&’s a Category Filter with a Parameter Filter which allows the code to be simplified to:
1: Filter doorSillsFilter = myfilters.CategoryParameterFilter(BuiltInCategory.OST_Doors,
2: BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM,
3: CriteriaFilterType.LessThan, 0.0);
4: //Windows
5: Filter windowSillsFilter = myfilters.CategoryParameterFilter(BuiltInCategory.OST_Windows,
6: BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM,
7: CriteriaFilterType.LessThan, 760.0);
8: // finished filter
9: Filter completeFilter = rvtApp.Create.Filter.NewLogicOrFilter(windowSillsFilter, doorSillsFilter);
10: ElementIterator itor = rvtApp.ActiveDocument.get_Elements(completeFilter);
2.. Enumerating Filters
Although not useful in this example ,you can use an IEnumerable method to build filters. Useful for building Filters that combine a large number of filters, for example:
1: Filter allFilters = myfilters.BuildCategoryFilters(
2: new BuiltInCategory[] { BuiltInCategory.OST_Doors,BuiltInCategory.OST_Windows });
3.. Filter Logic Operators
This one requires at a minimum .NET3.0, if you don’t use .NET3.0 I’d suggest .NET 3.5SP1. You need >.NET3.0 because it uses extension methods which allow you to tidy up logic filters. Allowing you to write the example code like this:
1: Autodesk.Revit.Application rvtApp = commandData.Application;
2: //Doors
3: Filter doors = rvtApp.Create.Filter.NewCategoryFilter(BuiltInCategory.OST_Doors)
4: .And(rvtApp.Create.Filter.NewParameterFilter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM, CriteriaFilterType.LessThan, 0.0));
5: //Windows
6: Filter windows = rvtApp.Create.Filter.NewCategoryFilter(BuiltInCategory.OST_Windows)
7: .And(rvtApp.Create.Filter.NewParameterFilter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM, CriteriaFilterType.LessThan, 760.0));
8:
9: ElementIterator itor = rvtApp.ActiveDocument.get_Elements(doors.Or(windows));
If you’re wondering why I didn’t use Operator overloading, they can’t be implemented on static methods which excludes extension methods unfortunately. Would be cool being able to write .getElements(doors && windows).
BTW, although the RevitAPI help suggests this is possible because Autodesk.Revit.Filter is an abstract class. You need to implement Autodesk.Revit.Filter.elementPassesFilter(ElemRecAccess**, ADocument*) .Which we’ll leave for now ;-)
You can find all the code and an example Revit project for these techniques here.