Jeremy Tammik

July 2009

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

« Happy New Year 2009 | Main | Revit Serial Number »

January 05, 2009

Family Category and Filtering

So here we are in a brand new year, 2009. Welcome back! Here is an interesting question regarding families, their categories, and filtering, raised last year by Martin Schmid of Autodesk.

Question: In the following code, I attempt to use Revit API filtering to select all families with a built-in category value of BuiltInCategory.OST_MechanicalEquipment:

Document doc = app.ActiveDocument;
List<Element> famsInCat = new List<Element>();
 
Autodesk.Revit.Creation.Filter cf
  = app.Create.Filter;
 
TypeFilter typeFilter
  = cf.NewTypeFilter( typeof( Family ) );
 
CategoryFilter catFilter
  = cf.NewCategoryFilter( bic );
 
LogicAndFilter andFilter
  = cf.NewLogicAndFilter( typeFilter, catFilter );
 
doc.get_Elements( andFilter, famsInCat );
return famsInCat;

Unfortunately, this does not work as expected, even when some mechanical equipment families have been loaded into the model.

Instead, this more cumbersome iterative approach can be used successfully:

Category categoryMechanicalEquipment
  = doc.Settings.Categories.get_Item( bic );
 
ElementId categoryId
  = categoryMechanicalEquipment.Id;
 
ElementIterator it
  = doc.get_Elements( typeof( Family ) );
 
while( it.MoveNext() )
{
  Family family = it.Current as Family;
  bool categoryMatches
    = family.FamilyCategory.Id.Equals( categoryId );
 
  if( categoryMatches )
  {
    famsInCat.Add( family );
  }
}
return famsInCat;

Do you see any errors in my logic?

Answer: The reason it does not work is because the Family class does not implement the Category property for all family files. Although the property is provided by the Family class, it sometimes returns null. The filter is probably using this property internally, but to no avail.

Therefore, you have to use some other method to check the category of a family. On some family instances, you can use FamilyCategory instead of Category, like you are doing in your working code snippet. Unfortunately, even this work-around is not reliable for all families. On some families, the FamilyCategory property is not implemented either. The most reliable method is to check the Category property on any one symbol contained in the family. Mostly, it is practical to just use the first symbol defined in the family. Here is some updated code demonstrating this approach:

Category categoryMechanicalEquipment
  = doc.Settings.Categories.get_Item( bic );
 
ElementId categoryId
  = categoryMechanicalEquipment.Id;
 
ElementIterator it
  = doc.get_Elements( typeof( Family ) );
 
while( it.MoveNext() )
{
  Family family = it.Current as Family;
  foreach( Symbol s in family.Symbols )
  {
    if( s.Category.Id.Equals( categoryId ) )
    {
      famsInCat.Add( family );
    }
    break; // only need to look at first symbol
  }
}
return famsInCat;

Unfortunately, as Martin points out above, this does indeed mean that you have to add some own slightly cumbersome code after the filtered element retrieval to check for the desired category.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00e553e168978833010536b10dc4970c

Listed below are links to weblogs that reference Family Category and Filtering:

Comments

Hi Jeremy,
Is it possible to trigger the Property Dialog of a Family through API (to show it)? I'm afraid not but I ask ;-). Would be cool not have to program it again.
Roozbeh

Dear Roozbeh,

Just as you suspect, the official API provides no such functionality. You might try various tricks using the Win32 API to simulate some user interaction:

http://thebuildingcoder.typepad.com/blog/2008/12/driving-revit-from-outside.html

There are also tools available that make use of this kind of technique internally and shield you from some of the nitty gritty details, such as AutoHotKey:

http://thebuildingcoder.typepad.com/blog/2009/01/autohotkey.html

Cheers, Jeremy.

Hi Jeremy,
thanks for the answer. I tested the example code, and changed it to get a Revit App through Windows Title Bar Text but it gets tricky to get the correct Revit instance if there are more than one Revit instances active. That's why I think I would try to retrieve the parameters of my interest in a Dialog.

Best Regards
Roozbeh

Hi Roozbeh,

I am glad you were able to make some use of the code and modify it for your use. One possible way to avoid the issue of selecting the correct one out of multiple running Revit instances may be provided by making use of System.Diagnostics.Process.GetCurrentProcess. If you are inside a Revit command, that will ensure you get the instance of Revit that you are running in.

You can definitely implement an application that sits and waits and watches for a certain dialogue to pop up, and then extracts data from it. This can be achieved using a windows hook based on the CBTProc function: The CBTProc hook procedure is an application-defined or library-defined call-back function used with the SetWindowsHookEx function. The system calls this function before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window.

Cheers, Jeremy.

Thanks for pointing out the extra information Jeremy!

Regards Roozbeh

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

RSS Feed

Search

Search