Back from Easter Holidays and Various Revit API Issues

I hope you had a wonderful time over Easter.

I returned from my team meeting and subsequent brief holiday in the snow and am confronted with a long list of unanswered Revit API discussion forum issues.

I answered a dozen and present a summary of a few of the most interesting ones:

Before I get to them, two pictures relating to the past weekend.

First, a toast in the snow with the Säntis Mountain in the background:

A toast with Falk and Saentis in the background

Secondly, a snapshot of a brief and slightly sad conversation shortly after Easter:

Two chokolate Easter bunnies

Getting back to the Revit API, here are some of the recent issues raised:

Determining the Distance Between Floor and Bottom of a Beam

Raised by David in how can get of Beam element 'Level' and 'Upper Level':

Question: I am trying to get the ELEVATION (double value) the Beam element. I'm going to subtract values the Upper Elevation and Elevation the element for getting the height of the void space. For example, height = Level 4 - Level 0 = 4 meters:

Beam distance to floor

Answer: You can use the ReferenceIntersector ray tracing functionality to achieve this.

In fact, the SDK sample MeasureHeight does almost exactly what you are asking for.

It was introduced in the Revit 2011 API and originally provided via the FindReferencesByDirection method.

The example later published as the MeasureHeight SDK sample is described in FindReferencesByDirection > Measure distances > Example: Measure Distance with FindReferencesByDirection.

Consecutive Ordering of TopographySurface Boundary Points

Raised by Klanea in does TopographySurface.GetBoundaryPoints guarantee point ordering?

Question: I'd like to extract consecutive boundary points of a TopographySurface, i.e., by traversing the returned List[XYZ].

I'm simulating a continuous, vertex-by-vertex walk around the TopographySurface perimeter.

I suspect all of this information must live in the underlying data structure, but I can't find out how to get at it, and the documentation of the TopographySurface.GetBoundaryPoints method makes no mention of ordering.

I've also tried probing the Vertices member of the underlying Mesh (with a call to Geometry.GetEnumator()), but this returns boundary and interior points, also in an unknown order.

Anyone know how best to extract this information directly from the API, or else have insight into the order guaranteed by a call to TopographySurface.GetBoundaryPoint()?

Answer: In the far distant past, you could not even ask the topography surface which points were interior or exterior.

Therefore, I implemented a topo surface interior and boundary points add-in to determine this.

The interior versus exterior predicate was later added to the API, cf. What's New in the Revit 2014 API > Reading points from a TopographySurface.

However, my old add-in should help provide what you need as well.

Extracting Unique Building Element Geometry Vertices

Raised by abhijitdesale in extracting coordinates from geometry of room or any other structure:

Question: I am a newbie in using C# and Revit API programming for creating plugins.

I am trying to retrieve co-ordinates of any structure. Let's say, for a room with four walls, I need to retrieve the co-ordinates of the four corners and write them to a text file.

I have used a wall filter to extract the elements and then applied the get_Geometry method on each element.

This approach gives me a lot of duplicate co-ordinates.

I have tried the same way for using different filters for roofs, floors, doors and windows.

I don't know for sure whether I am correct or not.

Please let me know if this is a correct way of extracting the co-ordinates of any structure.

If there is a better and more correct method to do it, please let me know.

Answer: Your approach sounds fine to me.

Duplicate coordinates are to be expected, of course.

You can eliminate them in many ways.

The easiest, I find, is to implement a fuzzy point equality comparer and then add the points as keys to a dictionary.

I think I do so in my concrete setout point add-in.

I also demonstrate this approach in many other samples on The Building Coder.

Search for XyzEqualityComparer, for instance.

I implemented the original version of it that back in 2009 to analyse nested instance geometry.

Retrieving All Visible Elements

Raised by Sunil in getting all elements with HasMaterialQuantities condition:

Question: To retrieve all visible elements, we referred to the previous discussion here on retrieving all elements.

It suggests using the HasMaterialQuantities method.

But Category::HasMaterialQuantities is returning false for topography, railings, and similar elements.

So they are missing when we try to get all the Revit model elements.

Here is the snippet of managed C++ .NET code that we are trying to use:

  FilteredElementCollector^ allInstances
    = gcnew FilteredElementCollector( revitDocument );

  allInstances = allInstances->WhereElementIsNotElementType();

  for each( Element^ element in allInstances )
    if( element != nullptr && element->Category != nullptr
      && !element->Category->Name->Contains(“Legend Components”)
      && element->Category->HasMaterialQuantities )
      GeometryElement^ geomElem = element->Geometry::get(geomOption);
      if( geomElem != nullptr && geomElem->GetEnumerator()->MoveNext() )
        // if this geom element genuinely contains geometry
        // put element in list

Any idea why HasMaterialQuantities is skipping visible elements like topography, railings etc.?

If we remove the HasMaterialQuantities condition, then we are getting the topography, railings along with all other elements, but we also get extra elements such as Rooms, which are not visible in the Revit project.

So what should be the right approach so that we get all the visible elements without skipping any valid visible elements like topography, railings etc.?

Answer: I am afraid that you are encountering a basic and incontestable aspect of BIM: it is complex.

It may be hard or impossible to find a simple one-line criteria that satisfies your exact needs.

The Building Coder topic group on Filtering for all Elements discusses this exact issue.

You will probably have to implement some more complex filtering criteria, and possibly handle different groups of elements in different ways.

Here are two examples of simple first stabs at retrieving MEP and structural elements demonstrating such combinations:

You will probably have to implement a similar kind of combined filtering algorithm for your needs.

Many more filtering samples are assembled in The Building Coder samples CmdCollectorPerformance module.

Also, I am sure that you understand that the next developer's needs will differ ever so slightly from yours, so there cannot be a simple solution for this challenge.

Please let us know how you end up solving this!

Response: I am now using a Custom Exporter to retrieve all elements and it is serving the purpose.

I followed the samples that you have put on Building Coder.

I agree that special filtering logic will be needed for specific elements and there is no one generic logic that can be used.