Revit API Cases 1

Here are the summaries of some of the Revit API ADN cases handled by me and my colleagues Joe Ye and Saikat Bhattacharya in the past few days:

  1. Set the display colour of a line.
  2. Split walls and lines, or ducts and pipes.
  3. Change colour of a family instance.
  4. Export family symbols from a project and save in an external RFA file.

1. Set the display colour of a line

Question: How can I set the display colour of a line?

Answer: In Revit 2009, I do not see any way to access the color settings in the line styles which in turn affects the color of lines. The line style Color property is not exposed to enable us to change the color.

Revit 2010 offers a new possibility to modify the line colour via the new LineColor property on the Category class. Thus, for any given line, one can access its category and its line color property, which is read and write enabled.

2. Split walls and lines, or ducts and pipes

Question: I would like to split ducts and pipes in Revit MEP. Can I call the 'Split Walls and Lines' functionality somehow from the Revit 2009 API and apply it to Ducts and Pipes? If not, is this feature going to be available in the 2010 API? I have heard that duct and pipe creation will be included.

Answer: The Revit 2010 API does not provide any API method to cut or split any of the duct, pipe or wall elements. Methods to create ducts and pipes are indeed provided in 2010. Thus you could use the NewDuct, NewPipe and NewWall methods to create a new element, shorten the original one accordingly, and set the properties and parameters obtained from the original to the newly created one. This might provide a possibility to mimic the splitting effect.

3. Change colour of a family instance

This is a continuation of the previous post on this topic:

Question: Could you provide the code to illustrate the approach you described to change the colour of a family instance?

Answer: Since the colour of an instance is defined by the material assigned to the type or symbol referenced by the instance, this involves duplicating the family symbol it references, assigning a different material colour to the newly created type, and then assigning the new type to the object that you want to colour differently. Here is the code to illustrate this approach.

For simplicity, it works with only one family instance, say a column, in the Revit model. A material has been applied through the user interface, and then the following piece of code is executed to create a duplicate symbol and access the material from the symbol. In this case, for now, it directly changes the colour of the material instead of selecting another material with a different colour or duplicating the colour. Finally, it applies the duplicated symbol to the family instance:

ElementSet elemset = doc.Selection.Elements;
 
foreach( Element e in elemset )
{
  FamilyInstance inst = e as FamilyInstance;
 
  // get the symbol and duplicate it:
  FamilySymbol dupSym = inst.Symbol.Duplicate(
    "D1" ) as FamilySymbol;
 
  // access the material:
  ElementId matId = dupSym.get_Parameter(
    "Material" ).AsElementId();
 
  Material mat = doc.get_Element( ref matId )
    as Autodesk.Revit.Elements.Material;
 
  // change the color of this material:
  mat.Color = new Color( 255, 0, 0 );
 
  // assign the new symbol to the instance:
  inst.Symbol = dupSym;
}

4. Export family symbols from a project and save as RFA files

Question: I would like to use the beta version of Revit 2010 and the new family API to save out all family symbols in an existing project to external RFA files. I am trying to use Document.EditFamily to open the family document, and then use the SaveAs method on that to export the family definition. Unfortunately, EditFamily throws an exception, System.InvalidOperationException, with the message 'Loaded Family Editing failed.'

Answer: Some families can be edited and saved to an external file, and others cannot. If the family can be edited in the Revit user interface, it should also be possible to open it through the API. Here is the result of logging the calls to EditFamily on all the families contained in a simple project named one_door.rvt containing one door symbol and an instance of it and very little else:

Error processing 'System Panel': Loaded Family Editing failed.
Error processing 'Rectangular Mullion': Loaded Family Editing failed.
Error processing 'Circular Mullion': Loaded Family Editing failed.
Error processing 'L Corner Mullion': Loaded Family Editing failed.
Error processing 'V Corner Mullion': Loaded Family Editing failed.
Error processing 'Trapezoid Corner Mullion': Loaded Family Editing failed.
Error processing 'Quad Corner Mullion': Loaded Family Editing failed.
Success processing 'M_Single-Flush'

As you can see, a number of built-in system families are impossible to edit, and calling EditFamily on those throws an exception of type System.InvalidOperationException.

The door symbol is defined through a standard family and can be edited and saved. After running the command, the family file for the door symbol is stored on disk:

2009-04-06  13:37   192,512 M_Single-Flush.rfa
2009-02-24  10:41   294,912 one_door.rvt

Here is the code for the external command which iterates through all the families in the project and tries to save each to a separate RFA file on disk:

const string _path = "C:/tmp/extract/";
 
public IExternalCommand.Result Execute(
  ExternalCommandData commandData,
  ref string message,
  ElementSet elements )
{
  Application app = commandData.Application;
  Document doc = app.ActiveDocument;
 
  Filter filter = app.Create.Filter.NewTypeFilter(
    typeof( Family ) );
 
  List<Element> fams = new List<Element>();
  doc.get_Elements( filter, fams );
 
  foreach ( Family f in fams )
  {
    string name = f.Name;
    try
    {
      Document famDoc = doc.EditFamily( f );
      famDoc.SaveAs( _path + name + ".rfa" );
      famDoc.Close( false );
      Debug.Print( "Success processing '{0}'",
        name );
    }
    catch( Exception ex )
    {
      Debug.Print( "Error processing '{0}': {1}",
        name, ex.Message );
    }
  }
  return IExternalCommand.Result.Failed;
}