Converting to Filters

This is a follow-up on the

category comparison

topic we brought up during the

Revit Structure API training in Verona
,
Italy.
We first ran into a language problem in the Revit SDK FrameBuilder sample and fixed that by converting the language dependent category comparison code to a language independent version.
Stefano Carradore did not let it rest at that but went one step further and converted the old-fashioned and ineffective 2008-style iteration to a more effective style making use of the 2009-style API filtering functionality.

As noted in the discussion of the

category comparison
,
the FrameBuilder sample works with structural beams and framing elements.
It implements a FrameData class which defines an Initialize() method to set up internal collections of column, beam and brace symbols.
They are sorted into different lists depending on their type, which is determined by comparing the category names.
In the original SDK sample, the iteration is performed over all Revit elements.
It picks out all the Level elements on one hand, and the structural framing and columns on the other.
The levels are identified by their class, i.e. System.Type, and the structural elements by their category name.
We already showed how to convert the category name comparison to a comparison of the category element id to remove the language dependence, which was preventing the code from running on the Italian version of Revit.
Still, the 2008-style iteration over the entire collection of all Revit elements remains extremely inefficient.

In Stefano’s new implementation, we make use of two separate API filters to extract the levels and the structural elements. This has the additional advantage of being intrinsically language independent.

Here is the original code:


ElementIterator itor
= m_commandData.Application.ActiveDocument.Elements;
itor.Reset();
while (itor.MoveNext())
{
  object obj = itor.Current;
 
  // add level to list
  Level aLevel = obj as Level;
  if (null != aLevel)
  {
    m_levels.Add(aLevel.Elevation, aLevel);
    continue;
  }
 
  // get Family to get FamilySymbols
  Family aFamily = obj as Family;
  if (null == aFamily)
  {
    continue;
  }
 
  foreach (FamilySymbol symbol in aFamily.Symbols)
  {
    if (null == symbol.Category)
    {
      continue;
    }
 
    // add symbols to lists according to category name
    string categoryName = symbol.Category.Name;
    if ("Structural Framing" == categoryName)
    {
      m_beambracesSymbolsMgr.AddSymbol(symbol);
    }
    else if ("Structural Columns" == categoryName)
    {
      m_columnSymbolsMgr.AddSymbol(symbol);
    }
  }
}

We replace this code by two separate API filters.
We could also use three filters, replacing the loop sorting the structural elements into the two separate collections by two separate dedicated filters, one each for columns and framing elements:


List<Element> a = new List<Element>();
doc.get_Elements( typeof( Level ), a );
 
foreach( Level lev in a )
{
  m_levels.Add( lev.Elevation, lev );
}
 
a.Clear();
Autodesk.Revit.Creation.Filter cf
  = app.Create.Filter;
 
Filter filterSymbols
  = cf.NewTypeFilter( typeof( FamilySymbol ) );
Filter filterCols
  = cf.NewCategoryFilter( bipColumn );
Filter filterFram
  = cf.NewCategoryFilter( bipFraming );
Filter filterStruct
  = cf.NewLogicOrFilter( filterCols, filterFram );
Filter filter
  = cf.NewLogicAndFilter( filterSymbols, filterStruct );
 
doc.get_Elements( filter, a );
 
foreach( FamilySymbol symbol in a )
{
  ElementId categoryId = symbol.Category.Id;
 
  if( idFraming.Equals( categoryId ) )
  {
    m_beambracesSymbolsMgr.AddSymbol( symbol );
  }
  else if( idColumn.Equals( categoryId ) )
  {
    m_columnSymbolsMgr.AddSymbol( symbol );
  }
}

When filtering only for the System.Type FamilySymbol without the additional check for the structural categories, our sample project was returning over 500 family symbols.
Adding the category filters reduced this number to 40.

Here
is the updated source code for
FrameData.cs
with the three different variants enclosed in conditional compilation pragmas.


Comments

2 responses to “Converting to Filters”

  1. i wanna list all elements using filters, i’ve tried this code :
    Dim coll As Autodesk.Revit.DB.FilteredElementCollector = New Autodesk.Revit.DB.FilteredElementCollector(myDoc)
    coll.WhereElementIsNotElementType
    but it doesn’t return eveything, don’t mean element type…
    thx for any help

  2. Dear Lotfi,
    The post above is obsolete by now, referring to the Revit 2009 and 2010 filtering mechanisms.
    In Revit 2011, you can use a Boolean OR combination of any filter and its negation, e.g.
    FilteredElementCollector collector
    = new FilteredElementCollector( doc )
    .WhereElementIsElementType();
    FilteredElementCollector collector2
    = new FilteredElementCollector( doc )
    .WhereElementIsNotElementType();
    collector.UnionWith( collector2 );
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading