Retrieve Stairs on Level

As mentioned in the discussion on

selecting model elements
,
stairs are not represented by an own class in the Revit API, but using the generic Revit Element class instead.
They do have a valid built-in category assigned to them, however, which makes it easy to retrieve them from the database and use the generic element and parameter access to retrieve and modify a lot of their data.
We also discussed other aspects of stairs in the past, such as

listing the railing types
,

material quantity extraction
, and

geometry retrieval
.

Rocky now raised a

question
on
retrieving stair elements from the database that allows us to take another quick look at the new Revit 2011 filtering capabilities:

Question: Will you please help me out to know how to retrieve the stairs on certain levels?
E.g., if there are two stairs on the first level of the building, then on second level, how can we get these stairs?

Answer: Retrieving all the stairs on a given level is easy.
We can use the stairs built-in category OST_Stairs to identify the stairs themselves, and the Element class Level property or an appropriate built-in parameter to determine what level they are on.
Since the Revit filtering API is so flexible and powerful, it provides us with a number of options for the approach to use:

  • Explicit iteration and manual checking of a property.
  • Using LINQ.
  • Using an anonymous method.
  • Using a parameter filter.

We have demonstrated examples of all of these in several recent posts, e.g. in our analysis of

collector performance
.

In all of the approaches above, one would obviously first apply a filter to check for the built-in category, for two reasons:

  • First, it is a quick filter, so it should be applied before any slow filters or other processing.
  • Secondly, we know that it will eliminate the vast majority of all the Revit database elements, so very few elements will remain to check.

The first three options listed above all make use of post-processing of the results returned by the quick category filter, and are more or less equivalent in speed.
Below, we present untested source code sample implementation snippets for all three of these approaches:
Here is the built-in stair category constant and the element id of the level that we are searching for:


  ElementId id = level.Id;
 
  BuiltInCategory bic
    = BuiltInCategory.OST_Stairs;

Here is the retrieval using explicit iteration and manual checking of a property:


  FilteredElementCollector collector
    = new FilteredElementCollector( doc );
 
  collector.OfCategory( bic );
 
  List<Element> stairs = new List<Element>();
 
  foreach( Element e in collector )
  {
    if( e.Level.Id.Equals( id ) )
    {
      stairs.Add( e );
    }
  }

Using LINQ, it might look like this:


  FilteredElementCollector collector
    = new FilteredElementCollector( doc );
 
  collector.OfCategory( bic );
 
  IEnumerable<Element> stairsOnLevelLinq =
    from e in collector
    where e.Level.Id.Equals( id )
    select e;

Using an anonymous method, it is even shorter:


  FilteredElementCollector collector
    = new FilteredElementCollector( doc );
 
  collector.OfCategory( bic );
 
  IEnumerable<Element> stairsOnLevelAnon =
    collector.Where<Element>( e
      => e.Level.Id.Equals( id ) );

As said, the test of the built-in category uses a quick filter, so that is good.
The post-processing is very expensive and not optimal, though.

As we demonstrated in our

collector performance
analysis,
a parameter filter is twice as fast as post-processing the results, even though it is a slow filter and not a quick one.

To use a parameter filter on the stair elements retrieved by the category filter, we need a built-in parameter to test, instead of the Element Level property.
The stair object stores its base and top levels in the built-in parameters STAIRS_BASE_LEVEL_PARAM and STAIRS_TOP_LEVEL_PARAM, so that is no problem.

Here is an untested source code example of setting up a category and a parameter filter to retrieve all stairs on a given level:


  FilteredElementCollector collector
    = new FilteredElementCollector( doc );
 
  collector.OfCategory( bic );
 
  BuiltInParameter bip
    = BuiltInParameter.STAIRS_BASE_LEVEL_PARAM;
 
  ParameterValueProvider provider
    = new ParameterValueProvider(
      new ElementId( bip ) );
 
  FilterNumericRuleEvaluator evaluator
    = new FilterNumericEquals();
 
  FilterRule rule = new FilterElementIdRule(
    provider, evaluator, id );
 
  ElementParameterFilter filter
    = new ElementParameterFilter( rule );
 
  return collector.WherePasses( filter );

I hope that fully answers your question, Rocky, and provides a useful working example for many others as well.


Comments

13 responses to “Retrieve Stairs on Level”

  1. Hi Jeremy,
    Thanks for your reply and provide such a usefull information.
    But I want to know the exact position of stairs start at first level and exact end point of that stairs at second level means exact location fo the stairs. for example: if a stairs starts at first level and it will end at second level then
    How will I know at second level the start of stairs at first level?
    I am using revit architecture 2010 with the c#
    Regards
    Rocky

  2. Dear Rocky,
    I am afraid that information is not easy to obtain, because the stair object is not yet fully exposed through the Revit API.
    I believe that you best bet will be to retrieve the stair geometry and try to extract the data you are looking for from that.
    For example, look at my conversation with Shifali in the comments on
    http://thebuildingcoder.typepad.com/blog/2009/05/selecting-model-elements.html
    Cheers, Jeremy.

  3. Hi Jeremy,
    Thanks for replying.
    Can u please suggest the way to find opening in wall that is neither door nor window?
    Regards
    Rocky

  4. Dear Rocky,
    Sure. Just filter for all openings in the document and select the one whose host is the wall. It is very similar to the code given above, except that I could not find a suitable parameter to implement the parameter filter, so I was stuck with just using explicit post-processing of the collector results. Here is some example code:
    void GetOpeningsInWall(
    Document doc,
    Wall wall )
    {
    ElementId id = wall.Id;
    BuiltInCategory bic
    = BuiltInCategory.OST_SWallRectOpening;
    FilteredElementCollector collector
    = new FilteredElementCollector( doc );
    collector.OfClass( typeof( Opening ) );
    collector.OfCategory( bic );
    // explicit iteration and manual
    // checking of a property:
    List openings = new List();
    foreach( Opening e in collector )
    {
    if( e.Host.Id.Equals( id ) )
    {
    openings.Add( e );
    }
    }
    // using LINQ:
    IEnumerable openingsOnLevelLinq =
    from e in collector.Cast()
    where e.Host.Level.Id.Equals( id )
    select e;
    // using an anonymous method:
    IEnumerable openingsOnLevelAnon =
    collector.Cast().Where( e
    => e.Host.Id.Equals( id ) );
    }
    From now on, my friend, you will have to solve your own element filtering problems.
    Cheers, Jeremy.

  5. We are working on Revit Structures. We draw the Reinforcements with line work. Is there any way to filter line work with API?

  6. Dear Babu,
    Sure, you can use the filtered element collector to retrieve detail lines, for instance.
    Look at the various posts in
    http://thebuildingcoder.typepad.com/blog/filters
    Something as simple as this should do the trick:
    FilteredElementCollector collector
    = new FilteredElementCollector( _doc );
    collector.OfClass( typeof( DetailCurve ) );
    Since I will be going on holiday now, I will not be able to answer any updates for while, so please be patient … Thank you!
    Cheers, Jeremy.

  7. Hi Jeremy,
    I am unable to find the stairs information using this method.
    ElementId id = level.Id;
    BuiltInCategory bic
    = BuiltInCategory.OST_Stairs;
    FilteredElementCollector collector
    = new FilteredElementCollector( doc );
    collector.OfCategory( bic );
    List stairs = new List();
    foreach( Element e in collector )
    {
    if( e.Level.Id.Equals( id ) )
    {
    stairs.Add( e );
    }
    }
    I am using Revit API 2013.
    Please help me out.
    Thanks.

  8. Dear Nitin,
    Maybe your stairs are different than mine.
    You can use RevitLookup to discover the proper category to filter for the stairs you are interested in.
    Cheers, Jeremy.

  9. LeeJaeYoung Avatar
    LeeJaeYoung

    Hi, Jeremy Tammik
    I am study that create stairs in revit sdk 2013.
    BuiltInCategory bic = BuiltInCategory.OST_Stairs;
    ……
    if (e.Category.Name == “Stairs”)
    …..
    m_stairsRun = StairsRun.CreateStraightRun(document, stairsId, geomLine, StairsRunJustification.Center);
    I made stairs a.m. method.
    I want to modify stair type what I select stair type.
    Can you advice me How I do?
    m_stairsRun.get_Parameter(Autodesk.Revit.DB.BuiltInParameter.? or Other way.

  10. Dear LeeJaeYoung,
    You can use the Element.ChangeTypeId method to change the type of an element.
    Cheers, Jeremy.

  11. LeeJaeYoung Avatar
    LeeJaeYoung

    Hi, Jeremy Tammik.
    Thank you so much.
    ^^
    And I want to create railing on the Level
    (I don’t want to create stair railing. hahaha)
    I study railing but I just find to create railing stair.
    Can you advice me How I do?

  12. Dear LeeJaeYoung,
    As you have noticed, the Railing.Create method requires the id of a stair.
    To create a free-standing railing with no stair, Rolando Hijar reports in a comment
    http://thebuildingcoder.typepad.com/blog/2009/02/list-railing-types.html?cid=6a00e553e16897883301676406fe61970b#comment-6a00e553e16897883301676406fe61970b
    “I found a way to create railings using the API:
    – pick an existing railing
    – create a group of it
    – copy the group
    – ungroup
    – change the railing location line.
    I did this to place railings over the top of walls in a perimeter fence.”
    Railings do not have a location curve, because they are sketch-based. The railing location is defined by a model curve associated with the railing instead, and the GeometryCurve property of this model curve can be set to some other curve to modify it.
    Please see whether you can create a minimal sample demonstrating a working solution for sharing with the rest of the developer community. Thank you!
    Cheers, Jeremy.

  13. Jack Zhu Avatar
    Jack Zhu

    Dear Jeremy Tammik
    I want to create railing on top of walls Recently。
    According to the above point,I copy an existing railing in 【ElementTransformUtils.CopyElement】,although I Can’t change the railing loaction。
    Could you teach me related source code When convenient。
    ※I am foreigner,Level of English is not good :)

Leave a Reply

Discover more from Autodesk Developer Blog

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

Continue reading