Jeremy Tammik blogging on the Revit API

June 13, 2011

Creating and Inserting an Extrusion Family

Today is the
Pentecost or
Whit Monday holiday
in Neuchâtel, which gave me some time to explore an interesting and important issue in a bit more depth.

Several developers recently asked about creating families programmatically, so here is a first simple example to demonstrate this.
It creates a new structural stiffener family as an extrusion of a profile based on a list of XYZ points and inserts an instance of it into the current document.
Here are the required steps one by one:

In order to create an extrusion from the contour data, we need a sketch plane and a CurveArrArray instance.
The curve array array contains a list of loops, since the extrusion may require an outer loop and optional inner loops representing cavities.

In this case, the method is designed to work in a family based on the structural stiffener family template, which contains a sketch plane in the XY plane named "Ref. Level" that we can work with.
Actually, it redundantly contains three of them, and we can simply pick the first one.
One way to select the existing sketch plane if we know the exact structure of the document we are working with is to explicitly use a hard coded element id for it:

That has the advantage of not being language dependent, but makes us completely dependent on the internal database structure of the family template file instead.
A slightly more flexible approach is to search for the element by name using a helper function such as this:

This method is making use of LINQ.
A more efficient approach would use a filtered element collector based on a
parameterfilter to
check the name instead.
The advantage of that approach is that the filtering then happens on the internal Revit side, before the retrieved element data is passed out from Revit to the managed .NET environment.
In our case, there are not many sketch planes in the document to examine, so the overhead is negligible.

Using this method to find the sketch plane, and with the curve array and thickness in hand, the call to create the extrusion element in a family document can be set up like this:

Next, let us see how to create a new family document in the background to make use of this method.

2. Creating an Extrusion Family

Creating a new family to contain our extrusion is a simple process:

Open the appropriate family template file.

Create the extrusion.

Save and close the file.

In theory, it should be possible to avoid the last step of saving the newly generated family document to a disk file, since it is possible to load the generated family document into a project environment straight from memory.
Unfortunately, I was unable to get this to work, because the call to 'fdoc.LoadFamily( doc )' caused a "serious error".
Saving the family to a disk file and using 'doc.LoadFamily( filename, out family )' instead works, though.

It would also not be necessary to require a different file to be open to start with, but if it is not, it is impossible to close the family document.
It has to be closed, though, in order to use the new Revit 2012 API OpenAndActivateDocument method on it, in case we want to see the results of our new family definition in the family environment instead of looking at an insertion in the project environment.

Now that the family has been created and save to a file, we can either add a call to open it programmatically in the foreground to view it using 'uiapp.OpenAndActivateDocument( filename )', or, assuming that we have an open active project document in the Revit user interface, immediately insert an instance of it.
In this case, let's go for the latter.

Here is an example of how we can place an instance of our newly created stiffener family into the current project at a selected point.
We make use of one of the simplest overloads of the NewFamilyInstance method taking just a point, the family symbol, and a structural type argument.

Before inserting the instance, we need to ensure that the family is in fact loaded at all.

Before loading the family, we need to check whether it has already been loaded.
This may happen, for instance, if the command is run multiple times.

Once loaded, we extract the family symbol from its container family, prompt the user for an insertion point, and create the new instance:

Another very common question in this area is how to perform Boolean operations, both in the family and project context.
That is a topic that I would like to take a look at in the near future, expanding on the example presented here.