0% found this document useful (0 votes)
132 views200 pages

Revit 2014 Platform API Developers Guidelines-1-200

The Revit 2014 Platform API Developers Guidelines document provides an overview and guidelines for developing add-ins and applications using the Revit 2014 Platform API. It covers topics such as getting started, adding ribbons and commands, working with elements, geometry, materials, families, views, disciplines, storing data, transactions, events, dockable panels, dynamic updates, and more advanced topics. The document is intended to help developers understand what can be done with the Revit API and how to properly structure and develop their applications and plugins.

Uploaded by

Ramiro Uluri
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
132 views200 pages

Revit 2014 Platform API Developers Guidelines-1-200

The Revit 2014 Platform API Developers Guidelines document provides an overview and guidelines for developing add-ins and applications using the Revit 2014 Platform API. It covers topics such as getting started, adding ribbons and commands, working with elements, geometry, materials, families, views, disciplines, storing data, transactions, events, dockable panels, dynamic updates, and more advanced topics. The document is intended to help developers understand what can be done with the Revit API and how to properly structure and develop their applications and plugins.

Uploaded by

Ramiro Uluri
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 200

Revit 2014 Platform API

Developers Guidelines

[email protected]
Index
Developers

• Introduction
 Welcome to the Revit Platform API
 What Can you do with the Revit Platform API
 Requirements
 Installation
 Supported Programming Languages
 User Manual
 Documentation Conventions
 Whats new in this release
o Getting Started
 Walkthroughs
 Walkthrough: Hello World
 Walkthrough: Add Hello World Ribbon Panel
 Walkthrough: Retrieve Selected Elements
 Walkthrough: Retrieve Filtered Elements
o Add-In Integration
 Overview
 External Commands
 External Application
 Add-In Registration
 Localization
 Attributes
 Revit Exceptions
 Ribbon Panels and Controls
 Revit Style Task Dialogs
 DB Level External Applications
o Application and Document
 Application Functions
• Discipline Controls
• How to use Application properties to enforce a correct version for your add-in
 Document Functions
 Document and File Management
 Settings
 Units
o Element Essentials
 Element Classification
 Other Classifications
 Element Retrieval
 General Properties
• Basic Interaction with Revit Elements
o Filtering
 Create a FilteredElementCollector
 Applying Filters
 Getting filtered elements or element ids
 LINQ Queries
 Bounding Box filters
 Element Intersection Filters
o Selection
 Changing the Selection
 User Selection
 Filtered User Selection
o Parameters
 Walkthrough: Get Selected Elements Parameters
 Definition
 Builtin Parameters
 Storage Types
 asValueString() and SetValueString()
 Parameter Relationships
 Adding Parameters to Elements
o Collections
 Interface
 Collections and Iterators
o Editing Elements
 Moving Elements
 Copying Elements
 Rotating Elements
 Aligning Elements
 Mirroring Elements
 Grouping Elements
 Creating Arrays of Elements
 Deleting Elements
 Pinned Elements
o Views
 About views
 View Types
• Overview
• View3D
• ViewPlan
• ViewDrafting
• ViewSelection
• ViewSheet
• ViewSchedule
o Creating a schedule
o Working with ViewSchedule
o TableView and TableData
 View Filters
 View Cropping
 Displaced Views
 UIView
• Revit Geometric Elements
o Walls, Floors, Ceilings, Roofs and Openings
 Walls
 Floors, Ceilings and Foundations
 Roofs
 Curtains
 Other Elements
 Compound Structure
 Opening
 Thermal Properties
o Family Instances
 Identifying Elements
 Family
 Family Instances
 Code Samples
 FamilySymbol
o Family Documents
 About family documents
 Creating elements in families
• Create a Form Element
• Create an Annotation
 Visibility of family elements
 Managing family types and parameters
o Conceptual Design
 Point and curve objects
 Forms
 Rationalizing a Surface
 Adaptive Components
o Datum and Information Elements
 Levels
 Grids
 Phase
 Design Options
o Annotation Elements
 Dimensions and Constraints
 Detail Curve
 Tags
 Text
 Annotation Symbol
o Geometry
 Example: Retrieve Geometry Data from a Wall
 Geometry Object Class
• Curves
o Curve Analysis
o Curve Collections
o Curve Creation
o Curve Parameterization
o Curve Types
o Mathematical representations of curve types
• GeometryInstances
• Meshes
• Points
• PolyLines
• Solids, Faces and Edges
o Edge and face parameterization
o Faces
o Face analysis
o Face splitting
o Face types
o Mathematical representation of face types
o Solid analysis
o Solid and face creation
 Geometry Helper Class
 Collection Classes
 Example: Retrieve Geometry Data from a Beam
 Extrusion Analysis of a Solid
 Finding geometry by ray projection
 Geometry Utility Classes
 Room and Space Geometry
o Sketching
 The 2D Sketch Class
 3D Sketch Class
 Model Curve
o Material
 General Material Information
 Material Management
 Element Material
 Material quantities
 Painting the Face of an Element
o Stairs and Railings
 Creating and Editing Stairs
 Railings
 Stairs Annotations
 Stair Components
• Discipline-Specific Functionality
o Revit Architecture
 Rooms
o Revit Structure
 Structural Model Elements
 Analytical Model
 Loads
 Analysis Links
 Analytical Links
o Revit MEP
 MEP Element Creation
• Create Pipes and Ducts
• Placeholders
• Systems
 Connectors
 Family Creation
 Mechanical Settings
 Electrical Settings
 Routing Preferences
• Advanced Topics
o Storing Data in the Revit model
 Shared Parameters
 Definition File
 Definition File Access
 Binding
 Extensible Storage
o Transactions
 Transaction Classes
 Transactions in Events
 Failure Handling Options
 Getting Element Geometry and AnalyticalModel
 Temporary Transations
o Events
 Database Events
• DocumentChanged event
 User Interface Events
 Registering Events
 Canceling Events
o External Events
o Dockable Dialog Panes
o Dynamic Model Update
 Implementing IUpdater
 The Execute method
 Registering Updaters
 Exposure to End-User
o Commands
o Failure Posting and Handling
 Posting Failures
 Handling Failures
o Performance Advisor
o Point Clouds
 Point Cloud Client
 Point Cloud Engine
o Analysis
 Energy Data
 Analysis Visualization
• Manager for analysis results
• Creating analysis results data
• Anlaysis Results Display
• Updating Analysis Results
 Conceptual Energy Analysis
 Detailed Energy Analysis Model
o Place and Locations
 Place
 City
 Project Location
 Project Position
o Worksharing
 Elements in Worksets
 Element Ownership
 Opening a Workshared Document
 Visibility and Display
 Worksets
 Workshared File Management
o Construction Modeling
 Assemblies and Views
 Parts
o Linked Files
 Revit Links
 Managing External Files
o Export
 Export Tables
 IFC Export
 Custom Export
• Appendices
o Glossary
 Array
 BIM
 Class
 Events
 Iterator
 Method
 Namespace
 Overloading
 Properties
 Revit Families
 Revit Parameters
 Revit Types
 Sets
 Element ED
 Element UID
o FAQ
 General Questions
 Revit Structure Questions
o Hello World for VB.Net
 Create a New Project
 Add Reference and Namespace
 Change the Class Name
 Add Code
 Creat a *.addin manifest file
 Build the Program
 Debug the Program
o Material Properties Internal Units
o Concrete Section Definitions
 Concrete-Rectangular Beam
 Precast-Rectangular Beam
 Precast-L Shaped Beam
 Precast-Single Tee
 Precast-Inverted Tee
 Precast-Double Tee
o API User Interface Guidelines
 Introduction
 Consistency
 Speaking the Users Language
 Good Layout
 Good Defaults
 Progressive Disclosure
 Localization of the User Interface
 Dialog Guidelines
 Ribbon Guidelines
 Common Definitions
 Terminology Definitions

Note: The Contents of this document were copied from the http://wikihelp.autodesk.com/Revit/enu/2014/Help/3665-Developers website on 16 & 17/11/2013
and are up to date as of that point. The Copyright and ownership of the information contained within remain as per the original copyright notices on the
website. This document has been put together for the purposes of offline reading and educational purposes and should only be used for this purpose. By
reading further you are agreeing to respect all copyright and ownership laws. Thank you

Most links copied will direct back to the orginal source location on the internet rather than internally within the document so differences may occur depending
on information updates
Developers
This API Developer's Guide describes how to use the application programming interface (API) for Autodesk Revit 2014.

Topics in this section

• Introduction
• Basic Interaction with Revit Elements
• Revit Geometric Elements
• Discipline-Specific Functionality
• Advanced Topics
• Appendices
Introduction
Welcome to the Revit Platform API
All Revit-based products are Parametric Building Information Modeling (BIM) tools. These tools are similar to Computer-Aided Design (CAD)
programs but are used to build 3D models as well as 2D drawings. In Revit, you place real-world elements like columns and walls into the
model. Once the model is built, you can create model views such as sections and callouts. Views are generated from the 3D physical model;
consequently, changes made in one view automatically propagate through all views. This virtually eliminates the need to update multiple
drawings and details when you make changes to the model.

Introduction to the Revit Platform API


The Revit .NET API allows you to program with any .NET compliant language including Visual Basic.NET, C#, and C++/CLI.

Revit Architecture 2013, Revit Structure 2013, and Revit MEP 2013 all contain the Revit Platform API so that you can integrate your
applications into Revit. The three APIs are very similar and are jointly referred to as the Revit Platform API. Before using the API, learn to
use Revit and its features so that you can better understand the relevant areas related to your programming. Learning Revit can help you:

• Maintain consistency with the Revit UI and commands.

• Design your add-in application seamlessly.

• Master API classes and class members efficiently and effectively.

If you are not familiar with Revit or BIM, learn more in the Revit product center at www.autodesk.com/revit.

What Can You Do with the Revit Platform API?


You can use the Revit Platform API to:

• Gain access to model graphical data.


• Gain access to model parameter data.
• Create, edit, and delete model elements like floors, walls, columns, and more.
• Create add-ins to automate repetitive tasks.
• Integrate applications into Revit-based vertical products. Examples include linking an external relational database to Revit or sending
model data to an analysis application.
• Perform analysis of all sorts using BIM.
• Automatically create project documentation.

Requirements
To go through the user manual, you need the following:

1. A working understanding of Revit Architecture 2013, Revit Structure 2013, or Revit MEP 2013.
2. Familiarity with a Common Language Specification compliant language like C# or VB.NET.
3. Microsoft Visual Studio 2010, or Microsoft Visual Studio 2010 Express Edition. Alternatively, you can use the built-in SharpDevelop
development environment in Revit.
4. Microsoft .NET Framework 4.0.
5. The Revit Software Developer's Kit (SDK) which you can download from the Autodesk Developer Network (ADN) or the Revit
installation CD/DVD (<DVD_Drive>:\Utilities\Common\Software Development Kit).

Installation
The Revit Platform API is installed with Revit Architecture, Revit Structure, and Revit MEP. Any .NET based application will reference the
RevitAPI.dll and the RevitAPIUI.dll located in the Revit Program directory. The RevitAPI.dll contains methods used to access Revit's
application, documents, elements and parameters at the database level. The RevitAPIUI.dll contains the interfaces related to manipulation
and customization of the Revit user interface.
Supported Programming Languages
The Revit Platform API is fully accessible by any language compatible with the Microsoft .NET Framework 4.0, such as Visual Basic .NET or
Visual C#.

User Manual
This document is part of the Revit SDK. It provides an introduction to implementing Revit add-in applications using the Revit Platform API.

Before creating a Revit Platform API add-in application read through the manual and try the sample code. If you already have some
experience with the Revit Platform API, you may just want to review the Notes and Troubleshooting sections.

Introduction to the Revit Platform API

The first two chapters present an introduction to the Revit Platform API and provide an overview of the User Manual.

Welcome to the Revit Platform API - Presents an introduction to the Revit Platform API and necessary prerequisite knowledge before you
create your first add-in.

Getting Started - Step-by-step instructions for creating your first Hello World add-in application using Visual Studio 2010 and four other
walkthroughs covering primary add-in functions.

Basic Topics

These chapters cover the Revit Platform API basic mechanisms and functionality.

Add-in Integration - Discusses how an add-in is integrated into the Revit UI and invoked by user commands or specific Revit events such as
program startup.

Application and Document - Application and Document classes respectively represent the Revit application and project file in the Revit
Platform API. This chapter explains basic concepts and links to pertinent chapters and sections.

Elements Essentials - The bulk of the data in a Revit project is in a collection of Elements. This chapter discusses the essential Element
mechanism, classification, and features.

Filtering - Filtering is used to get a set of elements from the document.

Selection - Working with the set of selected elements in a document

Parameters - Most Element information is stored as Parameters. This chapter discusses Parameter functionality.

Collection - Utility collection types such as Array, Map, Set collections, and related Iterators.

Element Topics

Elements are introduced based on element classification. Make sure that you read the Elements Essentials and Parameter chapters before
reading about the individual elements.

Editing Elements - Learn how to move, rotate, delete, mirror, group, and array elements.

Wall, Floors, Roofs and Openings - Discusses Elements, their corresponding ElementTypes representing built-in place construction, and
different types of Openings in the API.

Family Instances - Learn about the relationship between family and family instance, family and family instance features, and how to load or
create them.

Family Creation - Learn about creation and modification of Revit Family documents.

Conceptual Design - Discusses how to create complex geometry and forms in a Revit Conceptual Mass document.

Datum and Information Elements - Learn how to set up grids, add levels, use design options, and more.

Annotation Elements - Discusses document annotation including adding dimensions, detail curves, tags, and annotation symbols.

Sketching - Sketch functions include 2D and 3D sketch classes such as SketchPlane, ModelCurve, GenericForm, and more.

Views - Learn about the different ways to view models and components and how to manipulate the view in the API.

Material - Material data is an Element that identifies the physical materials used in the project as well as texture, color, and more.
Advanced Topics

Geometry - Discusses graphics-related types in the API used to describe the graphical representation of the model including the three
classes that describe and store the geometry information.

Place and Locations - Defines the project location including city, country, latitude, and longitude.

Shared Parameters - Shared parameters are external text files containing parameter specifications. This chapter introduces how to access to
shared parameters through the Revit Platform API.

Transaction - Introduces the two uses for Transaction and the limits that you must consider when using Transaction.

Events - Discusses how to take advantage of Revit Events.

Dynamic Model Update - Learn how to use updaters to modify the model in reaction to changes in the document.

Failure Posting and Handling - Learn how to post failures and interact with Revit's failure handling mechanism.

Analysis Visualization - How to display analysis results in a Revit project.

Product Specific

Revit products include Revit Architecture, Revit Structure, and Revit MEP. Some APIs only work in specific products.

Revit Architecture - Discusses the APIs specific to Revit Architecture.

Revit Structure - Discusses the APIs specific to Revit Structure.

Revit MEP - Discusses the APIs specific to Revit MEP.

Other

Appendix - Additional information such as Frequently Asked Questions, Using Visual Basic.Net for programming, and more.

Documentation Conventions
This document contains class names in namespace format, such as Autodesk.Revit.DB.Element. In C++/CLI Autodesk.Revit.Element is
Autodesk::Revit::DB::Element. Since only C# is used for sample code in this manual, the default namespace is Autodesk.Revit.DB. If you
want to see code in Visual Basic, you will find several VB.NET applications in the SDK Samples directory.

Indexed Properties

Some Revit Platform API class properties are "indexed", or described as overloaded in the API help file (RevitAPI.chm). For example, the
Element.Geometry property. In the text of this document, these are referred to as properties, although you access them as if they were
methods in C# code by pre-pending the property name with "get_" or "set_". For example, to use the Element.Geometry(Options) property,
you use Element.get_Geometry(Options).

What's new in this release


Please see the "What's New" section in Revit 2012 API.chm for information about changes and new features.
Getting Started
The Revit Platform API is fully accessible by any language compatible with the Microsoft .NET Framework 4.0, such as Visual C# or Visual
Basic .NET (VB.NET). Both Visual C# and VB.NET are commonly used to develop Revit Platform API applications. However, the focus of this
manual is developing applications using Visual C#.

Walkthroughs
If you are new to the Revit Platform API, the following topics are good starting points to help you understand the product. Walkthroughs
provide step-by-step instructions for common scenarios, helping you learn about the product or a particular feature. The following
walkthroughs will help you get started using the Revit Platform API:

Walkthrough: Hello World - Illustrates how to create an add-in using the Revit Platform API.

Walkthrough: Add Hello World Ribbon Panel - Illustrates how to add a custom ribbon panel.

Walkthrough: Retrieve Selected Elements - Illustrates how to retrieve selected elements.

Walkthrough: Retrieve Filtered Elements - Illustrates how to retrieve elements based on filter criteria.
Walkthrough: Hello World
Use the Revit Platform API and C# to create a Hello World program using the directions provided. For information about how to create an
add-in application using VB.NET, refer to Hello World for VB.NET.

The Hello World walkthrough covers the following topics:

• Create a new project.

• Add references.

• Change the class name.

• Write the code

• Debug the add-in.

All operations and code in this section were created using Visual Studio 2010.

Create a New Project

The first step in writing a C# program with Visual Studio is to choose a project type and create a new Class Library.

1. From the File menu, select New Project….

2. In the Installed Templates frame, click Visual C#.

3. In the right-hand frame, click Class Library (see Figure 1: Add New Project below). This walkthrough assumes that the project
location is: D:\Sample.

4. In the Name field, type HelloWorld as the project name.

5. Click OK.

Figure 1: Add New Project


Add References

1. To add the RevitAPI reference:

o From the View menu select Solution Explorer if the Solution Explorer window is not open.

o In the Solution Explorer, right-click References to display a context menu.

o From the context menu, click Add Reference. The Add Reference dialog box appears.

o In the Add Reference dialog box, click the Browse tab. Locate the folder where Revit is installed and click the RevitAPI.dll. For
example, the installed folder location is usually C:\Program Files\Autodesk\Revit Architecture 2012\Program\RevitAPI.dll.
o Click OK to select the .dll and close the dialog box. RevitAPI appears in the Solution Explorer reference tree.

o Note: You should always set the Copy Local property of RevitAPI.dll to false for new projects. This saves disk space, and
prevents the Visual Studio debugger from getting confused about which copy of the DLL to use. Right-click the RevitAPI.dll,
select Properties, and change the Copy Local setting from true (the default) to false.
2. Repeat the steps above for the RevitAPIUI.dll.

Add Code

Add the following code to create the add-in:

Code Region 2-1: Getting Started


using System;

using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
namespace HelloWorld
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Automatic)]
public class Class1 : IExternalCommand
{
{
public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message, ElementSet elements)
{
TaskDialog.Show("Revit", "Hello World");
return Autodesk.Revit.UI.Result.Succeeded;
}
}
}
TipThe Visual Studio Intellisense feature can create a skeleton implementation of an interface for you, adding stubs for all the required
methods. After you add ":IExternaCommand" after Class1 in the example above, you can select "Implement IExternalCommand" from the
Intellisense menu to get the code:

Figure 2: Using Intellisense to Implement Interface

Every Revit add-in application must have an entry point class that implements the IExternalCommand interface, and you must implement
the Execute() method. The Execute() method is the entry point for the add-in application similar to the Main() method in other programs.
The add-in entry point class definition is contained in an assembly. For more details, refer to Add-in Integration.

Build the Program

After completing the code, you must build the file. From the Build menu, click Build Solution. Output from the build appears in the Output
window indicating that the project compiled without errors.

Create a .addin manifest file

The HelloWorld.dll file appears in the project output directory. If you want to invoke the application in Revit, create a manifest file to register
it into Revit.

1. To create a manifest file, create a new text file in Notepad.


2. Add the following text:
Code Region 2-2: Creating a .addin manifest file for an external command
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<RevitAddIns>
<AddIn Type="Command">
<Assembly>D:\Sample\HelloWorld\bin\Debug\HelloWorld.dll</Assembly>
<AddInId>239BD853-36E4-461f-9171-C5ACEDA4E721</AddInId>
<FullClassName>HelloWorld.Class1</FullClassName>
<Text>HelloWorld</Text>
<VendorId>ADSK</VendorId>
<VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
</AddIn>
</RevitAddIns>

3. Save the file as HelloWorld.addin and put it in the following location:

o For Windows XP - C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2012\

o For Vista/Windows 7 - C:\ProgramData\Autodesk\Revit\Addins\2012\

o If your application assembly dll is on a network share instead of your local hard drive, you must modify Revit.exe.config to
allow .NET assemblies outside your local machine to be loaded. In the "runtime" node in Revit.exe.config, add the element
<loadFromRemoteSources enabled="true"/> " as shown below.
o <runtime>
o <generatePublisherEvidence enabled="false" />
o <loadFromRemoteSources enabled="true"/>
</runtime>

Refer to Add-in Integration for more details using manifest files.

Debug the Add-in

Running a program in Debug mode uses breakpoints to pause the program so that you can examine the state of variables and objects. If
there is an error, you can check the variables as the program runs to deduce why the value is not what you might expect.

1. In the Solution Explorer window, right-click the HelloWorld project to display a context menu.

2. From the context menu, click Properties. The Properties window appears.

3. Click the Debug tab.

4. Under the Start Action section, click Start external program and browse to the Revit.exe file. By default, the file is located at the
following path, C:\Program Files\Autodesk\Revit Structure 2012\Program\Revit.exe.
Figure 3: Set debug environment

5. From the Debug menu, select Toggle Breakpoint (or press F9) to set a breakpoint on the following line.

TaskDialog.Show("Revit", "Hello World");

6. Press F5 to start the debug procedure.

Test debugging:

• On the Add-Ins tab, HelloWorld appears in the External Tools menu-button.

Figure 4: HelloWorld External Tools command

• Click HelloWorld to execute the program, activating the breakpoint.

• Press F5 to continue executing the program. The following system message appears.

Figure 5: TaskDialog message

Troubleshooting

Q: My add-in application will not compile.

A: If an error appears when you compile the sample code, the problem may be with the version of the RevitAPI used to compile the add-in.
Delete the old RevitAPI reference and load a new one. For more details, refer to Add Reference.

Q: Why is there no Add-Ins tab or why isn't my add-in application displayed under External Tools?

A: In many cases, if an add-in application fails to load, Revit will display an error dialog on startup with information about the failure. For
example, if the add-in DLL cannot be found in the location specified in the manifest file, a message similar to the following appears.

Figure 6: External Tools Error Message

Error messages will also be displayed if the class name specified in ECClassName is not found or does not inherit from IExternalCommand.
However, in some cases, an add-in application may fail to load without any message. Possible causes include:

• The add-in application is compiled with a different RevitAPI version

• The manifest file is not found

• There is a formatting error in the .addin manifest file

Q: Why does my add-in application not work?

A: Even though your add-in application is available under External Tools, it may not work. This is most often caused by an exception in the
code.

For example:

Code Region 2-3: Exceptions in Execute()


Command: IExternalCommand
{
A a = new A();//line x
public IExternalCommand.Result Execute ()
{
//…
}
}
Class A
{
//…
}

The following two exceptions clearly identify the problem:

• An error in line x

• An exception is thrown in the Execute() method.

Revit will display an error dialog with information about the uncaught exception when the command fails.

Figure 7: Unhandled exception in External Command

This is intended as an aid to debugging your command; commands deployed to users should use try..catch..finally in the example entry
method to prevent the exception from being caught by Revit. Here's an example:
Code Region 2-4: Using try catch in execute:
public IExternalCommand.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
ExternalCommandData cdata = commandData;
Autodesk.Revit.ApplicationServices.Application app = cdata.Application;

try
{
// Do some stuff
}

catch (Exception ex)


{
message = ex.Message;
return Autodesk.Revit.UI.Result.Failed;
}
return Autodesk.Revit.UI.Result.Succeeded;
}
Walkthrough: Add Hello World Ribbon Panel
In the Walkthrough: Hello World section you learn how to create an add-in application and invoke it in Revit. You also learn to create a
.addin manifest file to register the add-in application as an external tool. Another way to invoke the add-in application in Revit is through a
custom ribbon panel.

Create a New Project

Complete the following steps to create a new project:

1. Create a C# project in Visual Studio using the Class Library template.

2. Type AddPanel as the project name.

3. Add references to the RevitAPI.dll and RevitAPIUI.dll using the directions in the previous walkthrough, Walkthrough: Hello World.

4. Add the PresentationCore reference:

o In the Solution Explorer, right-click References to display a context menu.

o From the context menu, click Add Reference. The Add Reference dialog box appears.

o In the Add Reference dialog box, click the .NET Tab.

o From the Component Name list, select PresentationCore.

o Click OK to close the dialog box. PresentationCore appears in the Solution Explorer reference tree.

Figure 8: Add Reference

5. Add the WindowsBase reference as well as System.Xaml following similar steps as above.

Change the Class Name

To change the class name, complete the following steps:

1. In the class view window, right-click Class1 to display a context menu.

2. From the context menu, select Rename and change the class' name to CsAddPanel.

3. In the Solution Explorer, right-click the Class1.cs file to display a context.

4. From the context menu, select Rename and change the file's name to CsAddPanel.cs.

5. Double click CsAddPanel.cs to open it for editing.

Add Code
The Add Panel project is different from Hello World because it is automatically invoked when Revit runs. Use the IExternalApplication
interface for this project. The IExternalApplication interface contains two abstract methods, OnStartup() and OnShutdown(). For more
information about IExternalApplication, refer to Add-in Integration.

Add the following code for the ribbon panel:

Code Region 2-5: Adding a ribbon panel


using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using System.Windows.Media.Imaging;
class CsAddpanel : Autodesk.Revit.UI.IExternalApplication
{
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application)
{
// add new ribbon panel
RibbonPanel ribbonPanel = application.CreateRibbonPanel("NewRibbonPanel");

//Create a push button in the ribbon panel "NewRibbonPanel"


//the add-in application "HelloWorld" will be triggered when button is pushed

PushButton pushButton = ribbonPanel.AddItem(new PushButtonData("HelloWorld",


"HelloWorld", @"D:\HelloWorld.dll", "HelloWorld.CsHelloWorld")) as PushButton;

// Set the large image shown on button


Uri uriImage = new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_32x32.png");
BitmapImage largeImage = new BitmapImage(uriImage);
pushButton.LargeImage = largeImage;

return Result.Succeeded;
}

public Result OnShutdown(UIControlledApplication application)


{
return Result.Succeeded;
}
}

Build the Application

After completing the code, build the application. From the Build menu, click Build Solution. Output from the build appears in the Output
window indicating that the project compiled without errors. AddPanel.dll is located in the project output directory.

Create the .addin manifest file

To invoke the application in Revit, create a manifest file to register it into Revit.

1. Create a new text file using Notepad.

2. Add the following text to the file:


Code Region 2-6: Creating a .addin file for an external application
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<RevitAddIns>
<AddIn Type="Application">
<Name>SampleApplication</Name>
<Assembly>D:\Sample\AddPanel\AddPanel\bin\Debug\AddPanel.dll</Assembly>
<AddInId>604B1052-F742-4951-8576-C261D1993107</AddInId>
<FullClassName>AddPanel.CsAddPanel</FullClassName>
<VendorId>ADSK</VendorId>
<VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
</AddIn>
</RevitAddIns>

3. Save the file as HelloWorldRibbon.addin and put it in the following location:

o For Windows XP - C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2012\

o For Vista/Windows 7 - C:\ProgramData\Autodesk\Revit\Addins\2012\


Note The AddPanel.dll file is in the default file folder in a new folder called Debug (D:\Sample\HelloWorld\bin\Debug\AddPanel.dll). Use the
file path to evaluate Assembly.

Refer to Add-in Integration for more information about .addin manifest files.

Debugging

To begin debugging, build the project, and run Revit. A new ribbon panel appears on the Add-Ins tab named NewRibbonPanel and Hello
World appears as the only button on the panel, with a large globe image.

Figure 9: Add a new ribbon panel to Revit

Click Hello World to run the application and display the following dialog box.

Figure 10: Hello World dialog box


Walkthrough: Retrieve Selected Elements
This section introduces you to an add-in application that gets selected elements from Revit.

In add-in applications, you can perform a specific operation on a specific element. For example, you can get or change an element's
parameter value. Complete the following steps to get a parameter value:

1. Create a new project and add the references as summarized in the previous walkthroughs.

2. Use the UIApplication.ActiveUIDocument.Selection.Elements property to retrieve the selected object.

The selected object is a Revit SelElementSet. Use the IEnumerator interface or foreach loop to search the ElementSet.

The following code is an example of how to retrieve selected elements.

Code Region 2-7: Retrieving selected elements


[Autodesk.Revit.Attributes.Transaction(TransactionMode.ReadOnly)]
public class Document_Selection : IExternalCommand
{
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData,
ref string message, ElementSet elements)
{
try
{
// Select some elements in Revit before invoking this command

// Get the handle of current document.


UIDocument uidoc = commandData.Application.ActiveUIDocument;
// Get the element selection of current document.
Selection selection = uidoc.Selection;
ElementSet collection = selection.Elements;

if (0 == collection.Size)
{
// If no elements selected.
TaskDialog.Show("Revit","You haven't selected any elements.");
}
else
{
String info = "Ids of selected elements in the document are: ";
foreach (Element elem in collection)
{
info += "\n\t" + elem.Id.IntegerValue;
}

TaskDialog.Show("Revit",info);
}
}
catch (Exception e)
{
message = e.Message;
return Autodesk.Revit.UI.Result.Failed;
}

return Autodesk.Revit.UI.Result.Succeeded;
}
}

After you get the selected elements, you can get the properties or parameters for the elements. For more information, see Parameter.
Walkthrough: Retrieve Filtered Elements
You can use a filter to select only elements that meet certain criteria. For more information on creating and using element filters, see
Iterating the Elements Collection.

This example retrieves all the doors in the document and displays a dialog listing their ids.

Code Region 2-8: Retrieve filtered elements


// Create a Filter to get all the doors in the document
ElementClassFilter familyInstanceFilter = new ElementClassFilter(typeof(FamilyInstance));
ElementCategoryFilter doorsCategoryfilter =
new ElementCategoryFilter(BuiltInCategory.OST_Doors);
LogicalAndFilter doorInstancesFilter =
new LogicalAndFilter(familyInstanceFilter, doorsCategoryfilter);
FilteredElementCollector collector = new FilteredElementCollector(document);
ICollection<ElementId> doors = collector.WherePasses(doorInstancesFilter).ToElementIds();

String prompt = "The ids of the doors in the current document are:";
foreach(ElementId id in doors)
{
prompt += "\n\t" + id.IntegerValue;
}

// Give the user some information


TaskDialog.Show("Revit",prompt);
Add-In Integration
Developers add functionality by creating and implementing External Commands and External Applications. Revit identifies the new
commands and applications using .addin manifest files.

• External Commands appear under the External Tools menu-button on the Add-Ins tab.

• External Applications are invoked when Revit starts up and unloaded when Revit shuts down

This chapter focuses on the following:

• Learning how to add functionality using External Commands and External Applications.

• How to access Revit events.

• How to customize the Revit UI.

Overview
The Revit Platform API is based on Revit application functionality. The Revit Platform API is composed of two class Libraries that only work
when Revit is running.

The RevitAPI.dll contains methods used to access Revit's application, documents, elements, and parameters at the database level. It also
contains IExternalDBApplication and related interfaces.

The RevitAPIUI.dll contains all API interfaces related to manipulation and customization of the Revit user interface, including:

• IExternalCommand and External Command related interfaces

• IExternalApplication and related interfaces

• Selection

• RibbonPanel, RibbonItem and subclasses

• TaskDialogs

As the following picture shows, Revit Architecture, Revit Structure, and Revit MEP are specific to Architecture, Structure, and MEP
respectively.
Figure 11: Revit, RevitAPI and Add-ins

To create a RevitAPI based add-in, you must provide specific entrypoint types in your add-in DLL. These entrypoint classes implement
interfaces, either IExternalCommand, IExternalApplication, or IExternalDBApplication. In this way, the add-in is run automatically on certain
events or, in the case of IExternalCommand and IExternalApplication, manually from the External Tools menu-button.

IExternalCommand, IExternalApplication, IExternalDBApplication, and other available Revit events for add-in integration are introduced in
this chapter.

External Commands
Developers can add functionality by implementing External Commands which appear in the External Tools menu-button.

Loading and Running External Commands

When no other commands or edit modes are active in Revit, registered external commands are enabled. When a command is selected, a
command object is created and its Execute() method is called. Once this method returns back to Revit, the command object is destroyed. As
a result, data cannot persist in the object between command executions. However, there are other ways to save data between command
executions; for example you can use the Revit shared parameters mechanism to store data in the Revit project.

You can add External Commands to the External Tools Panel under the External Tools menu-button, or as a custom ribbon panel on the Add-
Ins tab, Analyze tab or a new custom ribbon tab. See the Walkthrough: Hello World and Walkthrough: Add Hello World Ribbon Panel for
examples of these two approaches.

External tools, ribbon tabs and ribbon panels are initialized upon start up. The initialization steps are as follows:

• Revit reads manifest files and identifies:

o External Applications that can be invoked.

o External Tools that can be added to the Revit External Tools menu-button.

• External Application session adds panels and content to the Add-ins tab.
IExternalCommand

You create an external command by creating an object that implements the IExternalCommand interface. The IExternalCommand interface
has one abstract method, Execute, which is the main method for external commands.

The Execute() method has three parameters:

• commandData (ExternalCommandData)

• message (String)

• elements (ElementSet)

commandData (ExternalCommandData)

The ExternalCommandData object contains references to Application and View which are required by the external command. All Revit data is
retrieved directly or indirectly from this parameter in the external command.

For example, the following statement illustrates how to retrieve Autodesk.Revit.Document from the commandData parameter:

Code Region 3-1: Retrieving the Active Document


Document doc = commandData.Application.ActiveUIDocument.Document;

The following table illustrates the ExternalCommandData public properties

Table 1: ExternalCommandData public properties

Property Description

Application (Autodesk.Revit.UI.UIApplication) Retrieves an object that represents the current UIApplication for external command.

JournalData A data map that can be used to read and write data to the Revit journal file.
(IDictionary<String, String>)

View (Autodesk.Revit.DB.View) Retrieves an object that represents the View external commands work on.

message (String):

Error messages are returned by an external command using the output parameter message. The string-type parameter is set in the external
command process. When Autodesk.Revit.UI.Result.Failed or Autodesk.Revit.UI.Result.Cancelled is returned, and the message parameter is
set, an error dialog appears.

The following code sample illustrates how to use the message parameter.

Code Region 3-2: Setting an error message string


1. class IExternalCommand_message : IExternalCommand
2. {
3. public Autodesk.Revit.UI.Result Execute(
4. Autodesk.Revit.ExternalCommandData commandData, ref string message,
5. Autodesk.Revit.ElementSet elements)
6. {
7. message = "Could not locate walls for analysis.";
8. return Autodesk.Revit.UI.Result.Failed;
9. }
10. }
Implementing the previous external command causes the following dialog box to appear:

Figure 12: Error message dialog box

elements (ElementSet):

Whenever Autodesk.Revit.UI.Result.Failed or Autodesk.Revit.UI.Result.Canceled is returned and the parameter message is not empty, an
error or warning dialog box appears. Additionally, if any elements are added to the elements parameter, these elements will be highlighted
on screen. It is a good practice to set the message parameter whenever the command fails, whether or not elements are also returned.

The following code highlights pre-selected walls:

Code Region 3-3: Highlighting walls


1. class IExternalcommand_elements : IExternalCommand
2. {
3. public Result Execute(
4. Autodesk.Revit.UI.ExternalCommandData commandData, ref string message,
5. Autodesk.Revit.DB.ElementSet elements)
6. {
7. message = "Please note the highlighted Walls.";
8. FilteredElementCollector collector = new FilteredElementCollector(commandData.Application.ActiveUIDocument.Document);
9. ICollection<Element> collection = collector.OfClass(typeof(Wall)).ToElements();
10. foreach (Element e in collection)
11. {
12. elements.Insert(e);
13. }
14.
15. return Result.Failed;
16. }
17. }

The following picture displays the result of the previous code.


Figure 13: Error message dialog box and highlighted elements

Return

The Return result indicates that the execution failed, succeeded, or is canceled by the user. If it does not succeed, Revit reverses changes
made by the external command.

Table 2: IExternalCommand.Result

Member Name Description

Autodesk.Revit.UI.Result.Succeeded The external command completed successfully. Revit keeps all changes made by the external command.

Autodesk.Revit.UI.Result.Failed The external command failed to complete the task. Revit reverses operations performed by the external command. If
the message parameter of Execute is set, Revit displays a dialog with the text "Error - cannot be ignored".

Autodesk.Revit.UI.Result.Cancelled The user cancelled the external command. Revit reverses changes made by the external command. If the message
parameter of Execute is set, Revit displays a dialog with the text "Warning - can be ignored".
The following example displays a greeting message and allows the user to select the return value. Use the Execute() method as the entrance
to the Revit application.

Code Region 3-4: Prompting the user


1. public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData,
2. ref string message, ElementSet elements)
3. {
4. try
5. {
6. Document doc = commandData.Application.ActiveUIDocument.Document;
7. UIDocument uidoc = commandData.Application.ActiveUIDocument;
8. // Delete selected elements
9. ICollection<Autodesk.Revit.DB.ElementId> ids =
10. doc.Delete(uidoc.Selection.GetElementIds());
11.
12. TaskDialog taskDialog = new TaskDialog("Revit");
13. taskDialog.MainContent =
14. ("Click Yes to return Succeeded. Selected members will be deleted.\n" +
15. "Click No to return Failed. Selected members will not be deleted.\n" +
16. "Click Cancel to return Cancelled. Selected members will not be deleted.");
17. TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Yes |
18. TaskDialogCommonButtons.No | TaskDialogCommonButtons.Cancel;
19. taskDialog.CommonButtons = buttons;
20. TaskDialogResult taskDialogResult = taskDialog.Show();
21.
22. if (taskDialogResult == TaskDialogResult.Yes)
23. {
24. return Autodesk.Revit.UI.Result.Succeeded;
25. }
26. else if (taskDialogResult == TaskDialogResult.No)
27. {
28. elements = uidoc.Selection.Elements;
29. message = "Failed to delete selection.";
30. return Autodesk.Revit.UI.Result.Failed;
31. }
32. else
33. {
34. return Autodesk.Revit.UI.Result.Cancelled;
35. }
36. }
37. catch
38. {
39. message = "Unexpected Exception thrown.";
40. return Autodesk.Revit.UI.Result.Failed;
41. }
42. }

IExternalCommandAvailability

This interface allows you control over whether or not an external command button may be pressed. The IsCommandAvailable interface
method passes the application and a set of categories matching the categories of selected items in Revit to your implementation. The typical
use would be to check the selected categories to see if they meet the criteria for your command to be run.

In this example the accessibility check allows a button to be clicked when there is no active selection, or when at least one wall is selected:

Code Region 3-5: Setting Command Availability


1. public class SampleAccessibilityCheck : IExternalCommandAvailability
2. {
3. public bool IsCommandAvailable(AutodeskAutodesk.Revit.UI.UIApplication applicationData,
4. CategorySet selectedCategories)
5. {
6. // Allow button click if there is no active selection
7. if (selectedCategories.IsEmpty)
8. return true;
9. // Allow button click if there is at least one wall selected
10. foreach (Category c in selectedCategories)
11. {
12. if (c.Id.IntegerValue == (int)BuiltInCategory.OST_Walls)
13. return true;
14. }
15. return false;
16. }
External Application
Developers can add functionality through External Applications as well as External Commands. Ribbon tabs and ribbon panels are customized
using the External Application. Ribbon panel buttons are bound to an External command.

IExternalApplication

To add an External Application to Revit, you create an object that implements the IExternalApplication interface.

The IExternalApplication interface has two abstract methods, OnStartup() and OnShutdown(), which you override in your external
application. Revit calls OnStartup() when it starts, and OnShutdown() when it closes.

This is the OnStartup() and OnShutdown() abstract definition:

Code Region 3-6: OnShutdown() and OnStartup()


public interface IExternalApplication
{
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application);
public Autodesk.Revit.UI.Result OnShutdown(UIControlledApplication application);
}

The UIControlledApplication parameter provides access to certain Revit events and allows customization of ribbon panels and controls and
the addition of ribbon tabs. For example, the public event DialogBoxShowing of UIControlledApplication can be used to capture the event of
a dialog being displayed. The following code snippet registers the handling function that is called right before a dialog is shown.

Code Region 3-7: DialogBoxShowing Event


application.DialogBoxShowing += new
EventHandler<Autodesk.Revit.Events.DialogBoxShowingEventArgs>(AppDialogShowing);

The following code sample illustrates how to use the UIControlledApplication type to register an event handler and process the event when it
occurs.

Code Region 3-8: Using ControlledApplication


public class Application_DialogBoxShowing : IExternalApplication
{
// Implement the OnStartup method to register events when Revit starts.
public Result OnStartup(UIControlledApplication application)
{
// Register related events
application.DialogBoxShowing +=
new EventHandler<Autodesk.Revit.UI.Events.DialogBoxShowingEventArgs>(AppDialogShowing);
return Result.Succeeded;
}

// Implement this method to unregister the subscribed events when Revit exits.
public Result OnShutdown(UIControlledApplication application)
{

// unregister events
application.DialogBoxShowing -=
new EventHandler<Autodesk.Revit.UI.Events.DialogBoxShowingEventArgs>(AppDialogShowing);
return Result.Succeeded;
}

// The DialogBoxShowing event handler, which allow you to


// do some work before the dialog shows
void AppDialogShowing(object sender, DialogBoxShowingEventArgs args)
{
// Get the help id of the showing dialog
int dialogId = args.HelpId;

// Format the prompt information string


String promptInfo = "A Revit dialog will be opened.\n";
promptInfo += "The help id of this dialog is " + dialogId.ToString() + "\n";
promptInfo += "If you don't want the dialog to open, please press cancel button";
// Show the prompt message, and allow the user to close the dialog directly.
TaskDialog taskDialog = new TaskDialog("Revit");
taskDialog.MainContent = promptInfo;
TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Ok |
TaskDialogCommonButtons.Cancel;
taskDialog.CommonButtons = buttons;
TaskDialogResult result = taskDialog.Show();
if (TaskDialogResult.Cancel == result)
{
// Do not show the Revit dialog
args.OverrideResult(1);
}
else
{
// Continue to show the Revit dialog
args.OverrideResult(0);
}
}
}
Add-in Registration
External commands and external applications need to be registered in order to appear inside Revit. They can be registered by adding them
to a .addin manifest file.

The order that external commands and applications are listed in Revit is determined by the order in which they are read in when Revit starts
up.

Manifest Files

Starting with Revit 2011, the Revit API offers the ability to register API applications via a .addin manifest file. Manifest files are read
automatically by Revit when they are placed in one of two locations on a user's system:

In a non-user-specific location in "application data":

• For Windows XP - C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2014\

• For Vista/Windows 7 - C:\ProgramData\Autodesk\Revit\Addins\2014\

In a user-specific location in "application data":

• For Windows XP - C:\Documents and Settings\<user>\Application Data\Autodesk\Revit\Addins\2014\

• For Vista/Windows 7 - C:\Users\<user>\AppData\Roaming\Autodesk\Revit\Addins\2014\

All files named .addin in these locations will be read and processed by Revit during startup. All of the files in both the user-specific location
and the all users location are considered together and loaded in alphabetical order. If an all users manifest file shares the same name with a
user-specific manifest file, the all users manifest file is ignored. Within each manifest file, the external commands and external applications
are loaded in the order in which they are listed.

A basic file adding one ExternalCommand looks like this:

Code Region 3-9: Manifest .addin ExternalCommand


1. <?xml version="1.0" encoding="utf-8" standalone="no"?>
2. <RevitAddIns>
3. <AddIn Type="Command">
4. <Assembly>c:\MyProgram\MyProgram.dll</Assembly>
5. <AddInId>76eb700a-2c85-4888-a78d-31429ecae9ed</AddInId>
6. <FullClassName>Revit.Samples.SampleCommand</FullClassName>
7. <Text>Sample command</Text>
8. <VendorId>ADSK</VendorId>
9. <VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
10. <VisibilityMode>NotVisibleInFamily</VisibilityMode>
11. <Discipline>Structure</Discipline>
12. <Discipline>Architecture</Discipline>
13. <AvailabilityClassName>Revit.Samples.SampleAccessibilityCheck</AvailabilityClassName>
14. <LongDescription>
15. <p>This is the long description for my command.</p>
16. <p>This is another descriptive paragraph, with notes about how to use the command properly.</p>
17. </LongDescription>
18. <TooltipImage>c:\MyProgram\Autodesk.png</TooltipImage>
19. <LargeImage>c:\MyProgram\MyProgramIcon.png</LargeImage>
20. </AddIn>
21. </RevitAddIns>

A basic file adding one ExternalApplication looks like this:

Code Region 3-10: Manifest .addin ExternalApplication


1. <?xml version="1.0" encoding="utf-8" standalone="no"?>
2. <RevitAddIns>
3. <AddIn Type="Application">
4. <Name>SampleApplication</Name>
5. <Assembly>c:\MyProgram\MyProgram.dll</Assembly>
6. <AddInId>604B1052-F742-4951-8576-C261D1993107</AddInId>
7. <FullClassName>Revit.Samples.SampleApplication</FullClassName>
8. <VendorId>ADSK</VendorId>
9. <VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
10. </AddIn>
11. </RevitAddIns>

A basic file adding one DB-level External Application looks like this:
Code Region: Manifest .addin ExternalDBApplication
1. <?xml version="1.0" encoding="utf-8" standalone="no"?>
2. <RevitAddIns>
3. <AddIn Type="DBApplication">
4. <Assembly>c:\MyDBLevelApplication\MyDBLevelApplication.dll</Assembly>
5. <AddInId>DA3D570A-1AB3-4a4b-B09F-8C15DFEC6BF0</AddInId>
6.
7. <FullClassName>MyCompany.MyDBLevelAddIn</FullClassName>
8.
9. <Name>My DB-Level AddIn</Name>
10. <VendorId>ADSK</VendorId>
11. <VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
12. </AddIn>
13. </RevitAddIns>

Multiple AddIn elements may be provided in a single manifest file.

The following table describes the available XML tags:

Tag Description

Assembly The full path to the add-in assembly file. Required for all ExternalCommands and ExternalApplications.

FullClassName The full name of the class in the assembly file which implements IExternalCommand or IExternalApplication. Required for all
ExternalCommands and ExternalApplications.

AddInId A GUID which represents the id of this particular application. AddInIds must be unique for a given session of Revit.
Autodesk recommends you generate a unique GUID for each registered application or command. Required for all
ExternalCommands and ExternalApplications.

Name The name of application. Required; for ExternalApplications only.

Text The name of the button. Optional; use this tag for ExternalCommands only. The default is "External Tool".

VendorId A string conforming to the Autodesk vendor ID standard. Required for all ExternalCommands and ExternalApplications.
Register your vendor id string with Autodesk at http://www.autodesk.com/symbreg.

VendorDescription Description containing vendor's legal name and/or other pertinent information. Optional.

Description Short description of the command, will be used as the button tooltip. Optional; use this tag for ExternalCommands only.
The default is a tooltip with just the command text.

VisibilityMode The modes in which the external command will be visible. Multiple values may be set for this option. Optional; use this tag for
ExternalCommands only.
The default is to display the command in all modes, including when there is no active document. Previously written external
commands which need to run against the active document should either be modified to ensure that the code deals with
invocation of the command when there is no active document, or apply the NotVisibleWhenNoActiveDocument mode. See
table below for more information.

Discipline The disciplines in which the external command will be visible. Multiple values may be set for this option. Optional; use this tag
for ExternalCommands only.
The default is to display the command in all disciplines. If any specific disciplines are listed, the command will only be visible in
those disciplines. See table below for more information.

AvailabilityClassName The full name of the class in the assembly file which implemented IExternalCommandAvailability. This class allows the
command button to be selectively grayed out depending on context. Optional; use this tag for ExternalCommands only.
The default is a command that is available whenever it is visible.

LargeImage The icon to use for the button in the External Tools pulldown menu. Optional; use this tag for ExternalCommands only.
The default is to show a button without an icon.

SmallImage The icon to use if the button is promoted to the Quick Access Toolbar. Optional; use this tag for ExternalCommands only.
The default is to show a Quick Access Toolbar button without an icon, which can be confusing to users.

LongDescription Long description of the command, will be used as part of the button extended tooltip, shown when the mouse hovers over the
command for a longer amount of time. Optional; use this tag for ExternalCommands only. If this property and TooltipImage
are not supplied, the button will not have an extended tooltip.

TooltipImage An image file to show as a part of the button extended tooltip, shown when the mouse hovers over the command for a longer
amount of time. Optional; use this tag for ExternalCommands only. If this property and TooltipImage are not supplied, the
button will not have an extended tooltip.

LanguageType Localization setting for Text, Description, LargeImage, LongDescription, and TooltipImage of external tools buttons. Revit will
load the resource values from the specified language resource dll. The value can be one of the eleven languages supported by
Revit. If no LanguageType is specified, the language resource which the current session of Revit is using will be automatically
loaded. For more details see the section on Localization.

AllowLoadIntoExistingSession The flag for loading permission. Set to false to prevent Revit from automatically loading addins in a newly added .addin
manifest file without restarting. Optional. By default. Revit will automatically load addins from newly added .addin manifest
files without restarting Revit.

Table 3: VisibilityMode Members

Member Name Description

AlwaysVisible The command is available in all possible modes supported by the Revit API.

NotVisibleInProject The command is invisible when there is a project document active.

NotVisibleInFamily The command is invisible when there is a family document active.

NotVisibleWhenNoActiveDocument The command is invisible when there is no active document.

Table 4: Discipline Members

Member Name Description

Any The command is available in all possible disciplines supported by the Revit API.

Architecture The command is visible in Autodesk Revit Architecture.

Structure The command is visible in Autodesk Revit Structure.

StructuralAnalysis The command is visible when the Structural Analysis discipline editing tools are available.

MassingAndSite
The command is visible when the Massing and Site discipline editing tools are available.

EnergyAnalysis The command is visible when Energy Analysis discipline editing tools are available.

Mechanical The command is visible when the Mechanical discipline editing tools are available, e.g. in Autodesk Revit MEP.

Electrical The command is visible when the Electrical discipline editing tools are available, e.g. in Autodesk Revit MEP.

Piping The command is visible when the Piping discipline editing tools are available, e.g. in Autodesk Revit MEP.

MechanicalAnalysis The command is visible when the Mechanical Analysis discipline editing tools are available.

PipingAnalysis The command is visible when the Piping Analysis discipline editing tools are available.

ElectricalAnalysis The command is visible when the Electrical Analysis discipline editing tools are available.

.NET Add-in Utility for manifest files

The .NET utility DLL RevitAddInUtility.dll offers a dedicated API capable of reading, writing and modifying Revit Add-In manifest files. It is
intended for use from product installers and scripts. Consult the API documentation in the RevitAddInUtility.chm help file in the SDK
installation folder.
Code Region 3-11: Creating and editing a manifest file
1. //create a new addin manifest
2. RevitAddInManifest Manifest = new RevitAddInManifest();
3.
4. //create an external command
5. RevitAddInCommand command1 = new RevitAddInCommand("full path\\assemblyName.dll",
6. Guid.NewGuid(), "namespace.className");
7. command1.Description = "description";
8. command1.Text = "display text";
9.
10. // this command only visible in Revit MEP, Structure, and only visible
11. // in Project document or when no document at all
12. command1.Discipline = Discipline.Mechanical | Discipline.Electrical |
13. Discipline.Piping | Discipline.Structure;
14. command1.VisibilityMode = VisibilityMode.NotVisibleInFamily;
15.
16. //create an external application
17. RevitAddInApplication application1 = new RevitAddInApplication("appName",
18. "full path\\assemblyName.dll", Guid.NewGuid(), "namespace.className");
19.
20. //add both command(s) and application(s) into manifest
21. Manifest.AddInCommands.Add(command1);
22. Manifest.AddInApplications.Add(application1);
23.
24. //save manifest to a file
25. RevitProduct revitProduct1 = RevitProductUtility.GetAllInstalledRevitProducts()[0];
26. Manifest.SaveAs(revitProduct1.AllUsersAddInFolder + "\\RevitAddInUtilitySample.addin");

Code Region 3-12: Reading an existing manifest file


1. RevitProduct revitProduct1 = RevitProductUtility.GetAllInstalledRevitProducts()[0];
2.
3. RevitAddInManifest revitAddInManifest =
4. Autodesk.RevitAddIns.AddInManifestUtility.GetRevitAddInManifest(
5. revitProduct1.AllUsersAddInFolder + "\\RevitAddInUtilitySample.addin");

Add-in Registration
External commands and external applications need to be registered in order to appear inside Revit. They can be registered by adding them
to a .addin manifest file.

The order that external commands and applications are listed in Revit is determined by the order in which they are read in when Revit starts
up.

Manifest Files

Starting with Revit 2011, the Revit API offers the ability to register API applications via a .addin manifest file. Manifest files are read
automatically by Revit when they are placed in one of two locations on a user's system:

In a non-user-specific location in "application data":

• For Windows XP - C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2014\

• For Vista/Windows 7 - C:\ProgramData\Autodesk\Revit\Addins\2014\

In a user-specific location in "application data":

• For Windows XP - C:\Documents and Settings\<user>\Application Data\Autodesk\Revit\Addins\2014\

• For Vista/Windows 7 - C:\Users\<user>\AppData\Roaming\Autodesk\Revit\Addins\2014\

All files named .addin in these locations will be read and processed by Revit during startup. All of the files in both the user-specific location
and the all users location are considered together and loaded in alphabetical order. If an all users manifest file shares the same name with a
user-specific manifest file, the all users manifest file is ignored. Within each manifest file, the external commands and external applications
are loaded in the order in which they are listed.
A basic file adding one ExternalCommand looks like this:

Code Region 3-9: Manifest .addin ExternalCommand


1. <?xml version="1.0" encoding="utf-8" standalone="no"?>
2. <RevitAddIns>
3. <AddIn Type="Command">
4. <Assembly>c:\MyProgram\MyProgram.dll</Assembly>
5. <AddInId>76eb700a-2c85-4888-a78d-31429ecae9ed</AddInId>
6. <FullClassName>Revit.Samples.SampleCommand</FullClassName>
7. <Text>Sample command</Text>
8. <VendorId>ADSK</VendorId>
9. <VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
10. <VisibilityMode>NotVisibleInFamily</VisibilityMode>
11. <Discipline>Structure</Discipline>
12. <Discipline>Architecture</Discipline>
13. <AvailabilityClassName>Revit.Samples.SampleAccessibilityCheck</AvailabilityClassName>
14. <LongDescription>
15. <p>This is the long description for my command.</p>
16. <p>This is another descriptive paragraph, with notes about how to use the command properly.</p>
17. </LongDescription>
18. <TooltipImage>c:\MyProgram\Autodesk.png</TooltipImage>
19. <LargeImage>c:\MyProgram\MyProgramIcon.png</LargeImage>
20. </AddIn>
21. </RevitAddIns>

A basic file adding one ExternalApplication looks like this:

Code Region 3-10: Manifest .addin ExternalApplication


1. <?xml version="1.0" encoding="utf-8" standalone="no"?>
2. <RevitAddIns>
3. <AddIn Type="Application">
4. <Name>SampleApplication</Name>
5. <Assembly>c:\MyProgram\MyProgram.dll</Assembly>
6. <AddInId>604B1052-F742-4951-8576-C261D1993107</AddInId>
7. <FullClassName>Revit.Samples.SampleApplication</FullClassName>
8. <VendorId>ADSK</VendorId>
9. <VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
10. </AddIn>
11. </RevitAddIns>

A basic file adding one DB-level External Application looks like this:

Code Region: Manifest .addin ExternalDBApplication


1. <?xml version="1.0" encoding="utf-8" standalone="no"?>
2. <RevitAddIns>
3. <AddIn Type="DBApplication">
4. <Assembly>c:\MyDBLevelApplication\MyDBLevelApplication.dll</Assembly>
5. <AddInId>DA3D570A-1AB3-4a4b-B09F-8C15DFEC6BF0</AddInId>
6.
7. <FullClassName>MyCompany.MyDBLevelAddIn</FullClassName>
8.
9. <Name>My DB-Level AddIn</Name>
10. <VendorId>ADSK</VendorId>
11. <VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
12. </AddIn>
13. </RevitAddIns>
Multiple AddIn elements may be provided in a single manifest file.

The following table describes the available XML tags:

Tag Description

Assembly The full path to the add-in assembly file. Required for all ExternalCommands and ExternalApplications.

FullClassName The full name of the class in the assembly file which implements IExternalCommand or IExternalApplication. Required for all
ExternalCommands and ExternalApplications.

AddInId A GUID which represents the id of this particular application. AddInIds must be unique for a given session of Revit.
Autodesk recommends you generate a unique GUID for each registered application or command. Required for all
ExternalCommands and ExternalApplications.

Name The name of application. Required; for ExternalApplications only.

Text The name of the button. Optional; use this tag for ExternalCommands only. The default is "External Tool".

VendorId A string conforming to the Autodesk vendor ID standard. Required for all ExternalCommands and ExternalApplications.
Register your vendor id string with Autodesk at http://www.autodesk.com/symbreg.

VendorDescription Description containing vendor's legal name and/or other pertinent information. Optional.

Description Short description of the command, will be used as the button tooltip. Optional; use this tag for ExternalCommands only.
The default is a tooltip with just the command text.

VisibilityMode The modes in which the external command will be visible. Multiple values may be set for this option. Optional; use this tag for
ExternalCommands only.
The default is to display the command in all modes, including when there is no active document. Previously written external
commands which need to run against the active document should either be modified to ensure that the code deals with
invocation of the command when there is no active document, or apply the NotVisibleWhenNoActiveDocument mode. See
table below for more information.

Discipline The disciplines in which the external command will be visible. Multiple values may be set for this option. Optional; use this tag
for ExternalCommands only.
The default is to display the command in all disciplines. If any specific disciplines are listed, the command will only be visible in
those disciplines. See table below for more information.

AvailabilityClassName The full name of the class in the assembly file which implemented IExternalCommandAvailability. This class allows the
command button to be selectively grayed out depending on context. Optional; use this tag for ExternalCommands only.
The default is a command that is available whenever it is visible.

LargeImage The icon to use for the button in the External Tools pulldown menu. Optional; use this tag for ExternalCommands only.
The default is to show a button without an icon.

SmallImage The icon to use if the button is promoted to the Quick Access Toolbar. Optional; use this tag for ExternalCommands only.
The default is to show a Quick Access Toolbar button without an icon, which can be confusing to users.

LongDescription Long description of the command, will be used as part of the button extended tooltip, shown when the mouse hovers over the
command for a longer amount of time. Optional; use this tag for ExternalCommands only. If this property and TooltipImage
are not supplied, the button will not have an extended tooltip.

TooltipImage An image file to show as a part of the button extended tooltip, shown when the mouse hovers over the command for a longer
amount of time. Optional; use this tag for ExternalCommands only. If this property and TooltipImage are not supplied, the
button will not have an extended tooltip.

LanguageType Localization setting for Text, Description, LargeImage, LongDescription, and TooltipImage of external tools buttons. Revit will
load the resource values from the specified language resource dll. The value can be one of the eleven languages supported by
Revit. If no LanguageType is specified, the language resource which the current session of Revit is using will be automatically
loaded. For more details see the section on Localization.

AllowLoadIntoExistingSession The flag for loading permission. Set to false to prevent Revit from automatically loading addins in a newly added .addin
manifest file without restarting. Optional. By default. Revit will automatically load addins from newly added .addin manifest
files without restarting Revit.
Table 3: VisibilityMode Members

Member Name Description

AlwaysVisible The command is available in all possible modes supported by the Revit API.

NotVisibleInProject The command is invisible when there is a project document active.

NotVisibleInFamily The command is invisible when there is a family document active.

NotVisibleWhenNoActiveDocument The command is invisible when there is no active document.

Table 4: Discipline Members

Member Name Description

Any The command is available in all possible disciplines supported by the Revit API.

Architecture The command is visible in Autodesk Revit Architecture.

Structure The command is visible in Autodesk Revit Structure.

StructuralAnalysis The command is visible when the Structural Analysis discipline editing tools are available.

MassingAndSite
The command is visible when the Massing and Site discipline editing tools are available.

EnergyAnalysis The command is visible when Energy Analysis discipline editing tools are available.

Mechanical The command is visible when the Mechanical discipline editing tools are available, e.g. in Autodesk Revit MEP.

Electrical The command is visible when the Electrical discipline editing tools are available, e.g. in Autodesk Revit MEP.

Piping The command is visible when the Piping discipline editing tools are available, e.g. in Autodesk Revit MEP.

MechanicalAnalysis The command is visible when the Mechanical Analysis discipline editing tools are available.

PipingAnalysis The command is visible when the Piping Analysis discipline editing tools are available.

ElectricalAnalysis The command is visible when the Electrical Analysis discipline editing tools are available.

.NET Add-in Utility for manifest files

The .NET utility DLL RevitAddInUtility.dll offers a dedicated API capable of reading, writing and modifying Revit Add-In manifest files. It is
intended for use from product installers and scripts. Consult the API documentation in the RevitAddInUtility.chm help file in the SDK
installation folder.

Code Region 3-11: Creating and editing a manifest file


1. //create a new addin manifest
2. RevitAddInManifest Manifest = new RevitAddInManifest();
3.
4. //create an external command
5. RevitAddInCommand command1 = new RevitAddInCommand("full path\\assemblyName.dll",
6. Guid.NewGuid(), "namespace.className");
7. command1.Description = "description";
8. command1.Text = "display text";
9.
10. // this command only visible in Revit MEP, Structure, and only visible
11. // in Project document or when no document at all
12. command1.Discipline = Discipline.Mechanical | Discipline.Electrical |
13. Discipline.Piping | Discipline.Structure;
14. command1.VisibilityMode = VisibilityMode.NotVisibleInFamily;
15.
16. //create an external application
17. RevitAddInApplication application1 = new RevitAddInApplication("appName",
18. "full path\\assemblyName.dll", Guid.NewGuid(), "namespace.className");
19.
20. //add both command(s) and application(s) into manifest
21. Manifest.AddInCommands.Add(command1);
22. Manifest.AddInApplications.Add(application1);
23.
24. //save manifest to a file
25. RevitProduct revitProduct1 = RevitProductUtility.GetAllInstalledRevitProducts()[0];
26. Manifest.SaveAs(revitProduct1.AllUsersAddInFolder + "\\RevitAddInUtilitySample.addin");
Code Region 3-12: Reading an existing manifest file
1. RevitProduct revitProduct1 = RevitProductUtility.GetAllInstalledRevitProducts()[0];
2.
3. RevitAddInManifest revitAddInManifest =
4. Autodesk.RevitAddIns.AddInManifestUtility.GetRevitAddInManifest(
5. revitProduct1.AllUsersAddInFolder + "\\RevitAddInUtilitySample.addin");

Localization
You can let Revit localize the user-visible resources of an external command button (including Text, large icon image, long and short
descriptions and tooltip image). You will need to create a .NET Satellite DLL which contains the strings, images, and icons for the button.
Then change the values of the tags in the .addin file to correspond to the names of resources in the Satellite dll, but prepended with the
@character. So the tag:

Code Region 3-13: Non-localized Text Entry


<Text>Extension Manager</Text>

Becomes:

Code Region 3-14: Localized Text Entry


<Text>@ExtensionText</Text>

where ExtensionText is the name of the resource found in the Satellite DLL.

The Satellite DLLs are expected to be in a directory with the name of the language of the language-culture, such as en or en-US. The
directory should be located in the directory that contains the add-in assembly. See http://msdn.microsoft.com/en-us/library/e9zazcx5.aspx
to create managed Satellite DLLs.

You can force Revit to use a particular language resource DLL, regardless of the language of the Revit session, by specifying the language
and culture explicitly with a LanguageType tag.

Code Region 3-15: Using LanguageType Tag


<LanguageType>English_USA</LanguageType>

For example, the entry above would force Revit to always load the values from the en-US Satellite DLL and to ignore the current Revit
language and culture settings when considering the localizable members of the external command manifest file.

Revit supports the 11 languages defined in the Autodesk.Revit.ApplicationServices.LanguageType enumerated type: English_USA, German,
Spanish, French, Italian, Dutch, Chinese_Simplified, Chinese_Traditional, Japanese, Korean, and Russian.
Attributes
The Revit API provides several attributes for configuring ExternalCommand and ExternalApplication behavior.

TransactionAttribute

The custom attribute Autodesk.Revit.Attributes.TransactionMode must be applied to your implementation class of the IExternalCommand
interface to control transaction behavior for external command. There is no default for this option. This mode controls how the API
framework expects transactions to be used when the command is invoked. The supported values are:

• TransactionMode.Automatic - Revit will create a transaction in the active document before the external command is executed and
the transaction will be committed or rolled back after the command is completed (based upon the return value of the
ExternalCommand callback). The command cannot create and start its own Transactions, but it can create SubTransactions. The
command must report its success or failure status with the Result return value.

• TransactionMode.Manual - Revit will not create a transaction (but it will create an outer transaction group to roll back all changes if
the external command returns a failure). Instead, you may use combinations of Transactions, SubTransactions, and
TransactionGroups as you please. You will have to follow all rules regarding use of transactions and related classes. You will have to
give your transactions names which will then appear in the Undo menu. Revit will check that all transactions (also groups and sub-
transactions) are properly closed upon return from an external command. If not, Revit will discard all changes made to the model.

• TransactionMode.ReadOnly - No transaction (nor group) will be created, and no transaction may be created for the lifetime of the
command. The External Command may only use methods that read from the model. Exceptions will be thrown if the command
either tries to start a transaction (or group) or attempts to write to the model.

In all three modes, the TransactionMode applies only to the active document. You may open other documents during the course of the
command, and you may have complete control over the creation and use of Transactions, SubTransactions, and TransactionGroups on those
other documents (even in ReadOnly mode).

For example, to set an external command to use automatic transaction mode:

Code Region 3-18: TransactionAttribute


[Transaction(TransactionMode.Automatic)]
public class Command : IExternalCommand
{
public Autodesk.Revit.IExternalCommand.Result Execute(
Autodesk.Revit.ExternalCommandData commandData,
ref string message, Autodesk.Revit.DB.ElementSet elements)
{
// Command implementation, which modifies the active document directly
// and no need to start/commit transaction.
}
}

See Transactions.

JournalingAttribute

The custom attribute Autodesk.Revit.Attributes.JournalingAttribute can optionally be applied to your implementation class of the
IExternalCommand interface to control the journaling behavior during the external command execution. There are two options for
journaling:

• JournalMode.NoCommandData - Contents of the ExternalCommandData.JournalData map are not written to the Revit journal. This
option allows Revit API calls to write to the journal as needed. This option allows commands which invoke the Revit UI for selection
or responses to task dialogs to replay correctly.

• JournalMode.UsingCommandData - Uses the IDictionary<String, String> supplied in the command data. This will hide all Revit
journal entries between the external command invocation and the IDictionary<String, String> entry. Commands which invoke the
Revit UI for selection or responses to task dialogs may not replay correctly. This is the default if the JournalingAttribute is not
specified.
Code Region 3-19: JournalingAttribute
[Journaling(JournalingMode.UsingCommandData)]
public class Command : IExternalCommand
{
public Autodesk.Revit.IExternalCommand.Result Execute(
Autodesk.Revit.ExternalCommandData commandData,
ref string message, Autodesk.Revit.DB.ElementSet elements)
{
return Autodesk.Revit.UI.Result.Succeeded;
}
}

Revit Exceptions
When API methods encounter a non-fatal error, they throw an exception. Exceptions should be caught by Revit add-ins. The Revit API help
file specifies exceptions that are typically encountered for specific methods. All Revit API methods throw a subclass of
Autodesk.Revit.Exceptions.ApplicationException. These exceptions closely mirror standard .NET exceptions such as:

• ArgumentException

• InvalidOperationException

• FileNotFoundException

However, some of these subclasses are unique to Revit:

• AutoJoinFailedException

• RegenerationFailedException

• ModificationOutsideTransactionException

In addition, there is a special exception type called InternalException, which represents a failure path which was not anticipated. Exceptions
of this type carry extra diagnostic information which can be passed back to Autodesk for diagnosis.
Ribbon Panels and Controls
Revit provides API solutions to integrate custom ribbon panels and controls. These APIs are used with IExternalApplication. Custom ribbon
panels can be added to the Add-Ins tab, the Analyze tab or to a new custom ribbon tab.

Panels can include buttons, both large and small, which can be either simple push buttons, pulldown buttons containing multiple commands,
or split buttons which are pulldown buttons with a default push button attached. In addition to buttons, panels can include radio groups,
combo boxes and text boxes. Panels can also include vertical separators to help separate commands into logical groups. Finally, panels can
include a slide out control accessed by clicking on the bottom of the panel.

Please see Ribbon Guidelines in the API User Interface Guidelines section for information on developing a user interface that is compliant
with the standards used by Autodesk.

Create a New Ribbon Tab

Although ribbon panels can be added to the Add-Ins or Analyze tab, they can also be added to a new custom ribbon tab. This option should
only be used if necessary. To ensure that the standard Revit ribbon tabs remain visible, a limit of 20 custom ribbon tabs is imposed. The
following image shows a new ribbon tab with one ribbon panel and a few simple controls.

Below is the code that generated the above ribbon tab.

Code Region: New Ribbon tab


1. publicResult OnStartup(UIControlledApplication application)
2. {
3. // Create a custom ribbon tab
4. String tabName = "This Tab Name";
5. application.CreateRibbonTab(tabName);
6.
7. // Create two push buttons
8. PushButtonData button1 = newPushButtonData("Button1", "My Button #1",
9. @"C:\ExternalCommands.dll", "Revit.Test.Command1");
10. PushButtonData button2 = newPushButtonData("Button2", "My Button #2",
11. @"C:\ExternalCommands.dll", "Revit.Test.Command2");
12.
13. // Create a ribbon panel
14. RibbonPanel m_projectPanel = application.CreateRibbonPanel(tabName, "This Panel Name");
15. // Add the buttons to the panel
16. List<RibbonItem> projectButtons = newList<RibbonItem>();
17. projectButtons.AddRange(m_projectPanel.AddStackedItems(button1, button2));
18.
19. returnResult.Succeeded;
20. }

Create a New Ribbon Panel and Controls

The following image shows a ribbon panel on the Add-Ins tab using various ribbon panel controls. The following sections describe these
controls in more detail and provide code samples for creating each portion of the ribbon.

Figure 14: New ribbon panel and controls


The following code outlines the steps taken to create the ribbon panel pictured above. Each of the functions called in this sample is provided
in subsequent samples later in this section. Those samples assume that there is an assembly located at D:\
Sample\HelloWorld\bin\Debug\Hello.dll which contains the External Command Types:

• Hello.HelloButton

• Hello.HelloOne

• Hello.HelloTwo

• Hello.HelloThree

• Hello.HelloA

• Hello.HelloB

• Hello.HelloC

• Hello.HelloRed

• Hello.HelloBlue

• Hello.HelloGreen
Code Region: Ribbon panel and controls
1. public Result OnStartup(Autodesk.Revit.UI.UIControlledApplication app)
2. {
3. RibbonPanel panel = app.CreateRibbonPanel("New Ribbon Panel");
4.
5. AddRadioGroup(panel);
6. panel.AddSeparator();
7. AddPushButton(panel);
8. AddSplitButton(panel);
9. AddStackedButtons(panel);
10. AddSlideOut(panel);
11.
12. return Result.Succeeded;
13. }

Ribbon Panel

Custom ribbon panels can be added to the Add-Ins tab (the default) or the Analyze tab, or they can be added to a new custom ribbon tab.
There are various types of ribbon controls that can be added to ribbon panels which are discussed in more detail in the next section. All
ribbon controls have some common properties and functionality.

Ribbon Control Classes

Each ribbon control has two classes associated with it - one derived from RibbonItemData that is used to create the control (i.e.
SplitButtonData) and add it to a ribbon panel and one derived from RibbonItem (i.e. SplitButton) which represents the item after it is added
to a panel. The properties available from RibbonItemData (and the derived classes) are also available from RibbonItem (and the
corresponding derived classes). These properties can be set prior to adding the control to the panel or can be set using the RibbonItem class
after it has been added to the panel.

Tooltips

Most controls can have a tooltip set (using the ToolTip property) which is displayed when the user moves the mouse over the control. When
the user hovers the mouse over a control for an extended period of time, an extended tooltip will be displayed using the LongDescription and
the ToolTipImage properties. If neither LongDescription nor ToolTipImage are set, the extended tooltip is not displayed. If no ToolTip is
provided, then the text of the control (RibbonItem.ItemText) is displayed when the mouse moves over the control.

Figure 15: Extended Tooltip


Contextual Help

Controls can have contextual help associated with them. When the user hovers the mouse over the control and hits F1, the contextual help
is triggered. Contextual help options include linking to an external URL, launching a locally installed help (chm) file, or linking to a topic on
the Autodesk help wiki. The ContextualHelp class is used to create a type of contextual help, and then RibbonItem.SetContextualHelp() (or
RibbonItemData.SetContextualHelp()) associates it with a control. When a ContextualHelp instance is associated with a control, the text
"Press F1 for more help" will appear below the tooltip when the mouse hovers over the control, as shown below.

The following example associates a new ContextualHelp with a push button control. Pressing F1 when hovered over the push button will
open the Autodesk homepage in a new browser window.

Code Region: Contextual Help


1. private void AddPushButton(RibbonPanel panel)
2. {
3. PushButton pushButton = panel.AddItem(new PushButtonData("HelloWorld",
4. "HelloWorld", @"D:\Sample\HelloWorld\bin\Debug\HelloWorld.dll", "HelloWorld.CsHelloWorld")) as PushButton;
5.
6. // Set ToolTip and contextual help
7. pushButton.ToolTip = "Say Hello World";
8. ContextualHelp contextHelp = new ContextualHelp(ContextualHelpType.Url,
9. "http://www.autodesk.com");
10. pushButton.SetContextualHelp(contextHelp);
11.
12. // Set the large image shown on button
13. pushButton.LargeImage =
14. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_32x32.png"));
15. }

The ContextualHelp class has a Launch() method that can be called to display the help topic specified by the contents of this ContextualHelp
object at any time, the same as when the F1 key is pressed when the control is active. This allows the association of help topics with user
interface components inside dialogs created by an add-in application.

Associating images with controls

All of these controls can have an image associated with them using the LargeImage property. The best size for images associated with large
controls, such as non-stacked ribbon and drop-down buttons, is 32×32 pixels, but larger images will be adjusted to fit the button. Stacked
buttons and small controls such as text boxes and combo boxes should have a 16×16 pixel image set. Large buttons should also have a
16×16 pixel image set for the Image property. This image is used if the command is moved to the Quick Access Toolbar. If the Image
property is not set, no image will be displayed if the command is moved to the Quick Access Toolbar. Note that if an image larger than
16×16 pixels is used, it will NOT be adjusted to fit the toolbar.

The ToolTipImage will be displayed below the LongDescription in the extended tooltip, if provided. There is no recommended size for this
image.

Ribbon control availability

Ribbon controls can be enabled or disabled with the RibbonItem.Enabled property or made visible or invisible with the RibbonItem.Visible
property.
Ribbon Controls

In addition to the following controls, vertical separators can be added to ribbon panels to group related sets of controls.

Push Buttons

There are three types of buttons you can add to a panel: simple push buttons, drop-down buttons, and split buttons. The HelloWorld button
in Figure 13 is a push button. When the button is pressed, the corresponding command is triggered.

In addition to the Enabled property, PushButton has the AvailabilityClassName property which can be used to set the name of an
IExternalCommandAvailability interface that controls when the command is available.

Code Region: Adding a push button


1. private void AddPushButton(RibbonPanel panel)
2. {
3. PushButton pushButton = panel.AddItem(new PushButtonData("HelloWorld",
4. "HelloWorld", @"D:\HelloWorld.dll", "HelloWorld.CsHelloWorld")) as PushButton;
5.
6. pushButton.ToolTip = "Say Hello World";
7. // Set the large image shown on button
8. pushButton.LargeImage =
9. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_32x32.png"));
10. }

Drop-down buttons

Drop-down buttons expand to display two or more commands in a drop-down menu. In the Revit API, drop-down buttons are referred to as
PulldownButtons. Horizontal separators can be added between items in the drop-down menu.

Each command in a drop-down menu can also have an associated LargeImage as shown in the example above.

Split buttons

Split buttons are drop-down buttons with a default push button attached. The top half of the button works like a push button while the
bottom half functions as a drop-down button. The Option One button in Figure 13 is a split button.

Initially, the push button will be the top item in the drop-down list. However, by using the IsSynchronizedWithCurrentItem property, the
default command (which is displayed as the push button top half of the split button) can be synchronized with the last used command. By
default it will be synched. Selecting Option Two in the split button from Figure 13 above yields:

Figure 16: Split button synchronized with current item

Note that the ToolTip, ToolTipImage and LongDescription properties for SplitButton are ignored. The tooltip for the current push button is
shown instead.
Code Region: Adding a split button
1. private void AddSplitButton(RibbonPanel panel)
2. {
3. string assembly = @"D:\Sample\HelloWorld\bin\Debug\Hello.dll";
4.
5. // create push buttons for split button drop down
6. PushButtonData bOne = new PushButtonData("ButtonNameA", "Option One",
7. assembly, "Hello.HelloOne");
8. bOne.LargeImage =
9. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\One.bmp"));
10.
11. PushButtonData bTwo = new PushButtonData("ButtonNameB", "Option Two",
12. assembly, "Hello.HelloTwo");
13. bTwo.LargeImage =
14. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Two.bmp"));
15.
16. PushButtonData bThree = new PushButtonData("ButtonNameC", "Option Three",
17. assembly, "Hello.HelloThree");
18. bThree.LargeImage =
19. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Three.bmp"));
20.
21. SplitButtonData sb1 = new SplitButtonData("splitButton1", "Split");
22. SplitButton sb = panel.AddItem(sb1) as SplitButton;
23. sb.AddPushButton(bOne);
24. sb.AddPushButton(bTwo);
25. sb.AddPushButton(bThree);
26. }

Radio buttons

A radio button group is a set of mutually exclusive toggle buttons; only one can be selected at a time. After adding a RadioButtonGroup to a
panel, use the AddItem() or AddItems() methods to add toggle buttons to the group. Toggle buttons are derived from PushButton. The
RadioButtonGroup.Current property can be used to access the currently selected button.

Note that tooltips do not apply to radio button groups. Instead, the tooltip for each toggle button is displayed as the mouse moves over the
individual buttons.

Code Region: Adding radio button group


1. private void AddRadioGroup(RibbonPanel panel)
2. {
3. // add radio button group
4. RadioButtonGroupData radioData = new RadioButtonGroupData("radioGroup");
5. RadioButtonGroup radioButtonGroup = panel.AddItem(radioData) as RadioButtonGroup;
6.
7. // create toggle buttons and add to radio button group
8. ToggleButtonData tb1 = new ToggleButtonData("toggleButton1", "Red");
9. tb1.ToolTip = "Red Option";
10. tb1.LargeImage = new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Red.bmp"));
11. ToggleButtonData tb2 = new ToggleButtonData("toggleButton2", "Green");
12. tb2.ToolTip = "Green Option";
13. tb2.LargeImage = new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Green.bmp"));
14. ToggleButtonData tb3 = new ToggleButtonData("toggleButton3", "Blue");
15. tb3.ToolTip = "Blue Option";
16. tb3.LargeImage = new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Blue.bmp"));
17. radioButtonGroup.AddItem(tb1);
18. radioButtonGroup.AddItem(tb2);
19. radioButtonGroup.AddItem(tb3);
20. }

Text box

A text box is an input control for users to enter text. The image for a text box can be used as a clickable button by setting the
ShowImageAsButton property to true. The default is false. The image is displayed to the left of the text box when ShowImageAsButton is
false, and displayed at the right end of the text box when it acts as a button, as in Figure 13.

The text entered in the text box is only accepted if the user hits the Enter key or if they click the associated image when the image is shown
as a button. Otherwise, the text will revert to its previous value.

In addition to providing a tooltip for a text box, the PromptText property can be used to indicate to the user what type of information to
enter in the text box. Prompt text is displayed when the text box is empty and does not have keyboard focus. This text is displayed in italics.
The text box in Figure 13 has the prompt text "Enter a comment".

The width of the text box can be set using the Width property. The default is 200 device-independent units.
The TextBox.EnterPressed event is triggered when the user presses enter, or when they click on the associated image for the text box when
ShowImageAsButton is set to true. When implementing an EnterPressed event handler, cast the sender object to TextBox to get the value
the user has entered as shown in the following example.

Code Region: TextBox.EnterPressed event handler


1. void ProcessText(object sender, Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs args)
2. {
3. // cast sender as TextBox to retrieve text value
4. TextBox textBox = sender as TextBox;
5. string strText = textBox.Value as string;
6. }

The inherited ItemText property has no effect for TextBox. The user-entered text can be obtained from the Value property, which must be
converted to a string.

See the section on stacked ribbon items for an example of adding a TextBox to a ribbon panel, including how to register the event above.

Combo box

A combo box is a pulldown with a set of selectable items. After adding a ComboBox to a panel, use the AddItem() or AddItems() methods to
add ComboBoxMembers to the list.

Separators can also be added to separate items in the list or members can be optionally grouped using the ComboBoxMember.GroupName
property. All members with the same GroupName will be grouped together with a header that shows the group name. Any items not
assigned a GroupName will be placed at the top of the list. Note that when grouping items, separators should not be used as they will be
placed at the end of the group rather than in the order they are added.

Figure 17: Combo box with grouping

ComboBox has three events:

• CurrentChanged - triggered when the current item of the ComboBox is changed

• DropDownClosed - triggered when the drop-down of the ComboBox is closed

• DropDownClosed - triggered when the drop-down of the ComboBox is opened

See the code region in the following section on stacked ribbon items for a sample of adding a ComboBox to a ribbon panel.

Stacked Panel Items

To conserve panel space, you can add small panel items in stacks of two or three. Each item in the stack can be a push button, a drop-down
button, a combo box or a text box. Radio button groups and split buttons cannot be stacked. Stacked buttons should have an image
associated through their Image property, rather than LargeImage. A 16×16 image is ideal for small stacked buttons.
The following example produces the stacked text box and combo box in Figure 13.

Code Region: Adding a text box and combo box as stacked items
1. private void AddStackedButtons(RibbonPanel panel)
2. {
3. ComboBoxData cbData = new ComboBoxData("comboBox");
4.
5. TextBoxData textData = new TextBoxData("Text Box");
6. textData.Image =
7. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_16x16.png"));
8. textData.Name = "Text Box";
9. textData.ToolTip = "Enter some text here";
10. textData.LongDescription = "<p>This is text that will appear next to the image</p>"
11. + "<p>when the user hovers the mouse over the control</p>";
12. textData.ToolTipImage =
13. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_32x32.png"));
14.
15. IList<RibbonItem> stackedItems = panel.AddStackedItems(textData, cbData);
16. if (stackedItems.Count > 1)
17. {
18. TextBox tBox = stackedItems[0] as TextBox;
19. if (tBox != null)
20. {
21. tBox.PromptText = "Enter a comment";
22. tBox.ShowImageAsButton = true;
23. tBox.ToolTip = "Enter some text";
24. // Register event handler ProcessText
25. tBox.EnterPressed +=
26. new EventHandler<Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs>(ProcessText);
27. }
28.
29. ComboBox cBox = stackedItems[1] as ComboBox;
30. if (cBox != null)
31. {
32. cBox.ItemText = "ComboBox";
33. cBox.ToolTip = "Select an Option";
34. cBox.LongDescription = "Select a number or letter";
35.
36. ComboBoxMemberData cboxMemDataA = new ComboBoxMemberData("A", "Option A");
37. cboxMemDataA.Image =
38. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\A.bmp"));
39. cboxMemDataA.GroupName = "Letters";
40. cBox.AddItem(cboxMemDataA);
41.
42. ComboBoxMemberData cboxMemDataB = new ComboBoxMemberData("B", "Option B");
43. cboxMemDataB.Image =
44. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\B.bmp"));
45. cboxMemDataB.GroupName = "Letters";
46. cBox.AddItem(cboxMemDataB);
47.
48. ComboBoxMemberData cboxMemData = new ComboBoxMemberData("One", "Option 1");
49. cboxMemData.Image =
50. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\One.bmp"));
51. cboxMemData.GroupName = "Numbers";
52. cBox.AddItem(cboxMemData);
53. ComboBoxMemberData cboxMemData2 = new ComboBoxMemberData("Two", "Option 2");
54. cboxMemData2.Image =
55. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Two.bmp"));
56. cboxMemData2.GroupName = "Numbers";
57. cBox.AddItem(cboxMemData2);
58. ComboBoxMemberData cboxMemData3 = new ComboBoxMemberData("Three", "Option 3");
59. cboxMemData3.Image =
60. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\Three.bmp"));
61. cboxMemData3.GroupName = "Numbers";
62. cBox.AddItem(cboxMemData3);
63. }
64. }
65. }
Slide-out panel

Use the RibbonPanel.AddSlideOut() method to add a slide out to the bottom of the ribbon panel. When a slide-out is added, an arrow is
shown on the bottom of the panel, which when clicked will display the slide-out. After calling AddSlideOut(), subsequent calls to add new
items to the panel will be added to the slide-out, so the slide-out must be added after all other controls have been added to the ribbon panel.

Figure 18: Slide-out

The following example produces the slide-out shown above:

Code Region: TextBox.EnterPressed event handler


1. private static void AddSlideOut(RibbonPanel panel)
2. {
3. string assembly = @"D:\Sample\HelloWorld\bin\Debug\Hello.dll";
4.
5. panel.AddSlideOut();
6.
7. // create some controls for the slide out
8. PushButtonData b1 = new PushButtonData("ButtonName1", "Button 1",
9. assembly, "Hello.HelloButton");
10. b1.LargeImage =
11. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_32x32.png"));
12. PushButtonData b2 = new PushButtonData("ButtonName2", "Button 2",
13. assembly, "Hello.HelloTwo");
14. b2.LargeImage =
15. new BitmapImage(new Uri(@"D:\Sample\HelloWorld\bin\Debug\39-Globe_16x16.png"));
16.
17. // items added after call to AddSlideOut() are added to slide-out automatically
18. panel.AddItem(b1);
19. panel.AddItem(b2);
Revit-style Task Dialogs
A TaskDialog is a Revit-style alternative to a simple Windows MessageBox. It can be used to display information and receive simple input
from the user. It has a common set of controls that are arranged in a standard order to assure consistent look and feel with the rest of Revit.

Figure 19: Revit-style Task Dialog

There are two ways to create and show a task dialog to the user. The first option is to construct the TaskDialog, set its properties
individually, and use the instance method Show() to show it to the user. The second is to use one of the static Show() methods to construct
and show the dialog in one step. When you use the static methods only a subset of the options can be specified.

Please see Task Dialog in the API User Interface Guidelines section for information on developing a task dialog that is compliant with the
standards used by Autodesk.

The following example shows how to create and display the task dialog shown above.

Code Region 3-27: Displaying Revit-style TaskDialog


[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Automatic)]
class TaskDialogExample : IExternalCommand
{
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet
elements)
{
// Get the application and document from external command data.
Application app = commandData.Application.Application;
Document activeDoc = commandData.Application.ActiveUIDocument.Document;

// Creates a Revit task dialog to communicate information to the user.


TaskDialog mainDialog = new TaskDialog("Hello, Revit!");
mainDialog.MainInstruction = "Hello, Revit!";
mainDialog.MainContent =
"This sample shows how to use a Revit task dialog to communicate with the user."
+ "The command links below open additional task dialogs with more information.";

// Add commmandLink options to task dialog


mainDialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink1,
"View information about the Revit installation");
mainDialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink2,
"View information about the active document");

// Set common buttons and default button. If no CommonButton or CommandLink is added,


// task dialog will show a Close button by default
mainDialog.CommonButtons = TaskDialogCommonButtons.Close;
mainDialog.DefaultButton = TaskDialogResult.Close;

// Set footer text. Footer text is usually used to link to the help document.
mainDialog.FooterText =
"<a href=\"http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=2484975 \">"
+ "Click here for the Revit API Developer Center</a>";
TaskDialogResult tResult = mainDialog.Show();

// If the user clicks the first command link, a simple Task Dialog
// with only a Close button shows information about the Revit installation.
if (TaskDialogResult.CommandLink1 == tResult)
{
TaskDialog dialog_CommandLink1 = new TaskDialog("Revit Build Information");
dialog_CommandLink1.MainInstruction =
"Revit Version Name is: " + app.VersionName + "\n"
+ "Revit Version Number is: " + app.VersionNumber + "\n"
+ "Revit Version Build is: " + app.VersionBuild;

dialog_CommandLink1.Show();

// If the user clicks the second command link, a simple Task Dialog
// created by static method shows information about the active document
else if (TaskDialogResult.CommandLink2 == tResult)
{
TaskDialog.Show("Active Document Information",
"Active document: " + activeDoc.Title + "\n"
+ "Active view name: " + activeDoc.ActiveView.Name);
}

return Autodesk.Revit.UI.Result.Succeeded;
}
}
DB-level External Applications
Database-level add-ins are External Applications that do not add anything to the Revit UI. DB-level External Applications can be used when the purpose of the
application is to assign events and/or updaters to the Revit session.

To add a DB-level External Application to Revit, you create an object that implements the IExternalDBApplication interface.

The IExternalDBApplication interface has two abstract methods, OnStartup() and OnShutdown(), which you override in your DB-level external application. Revit
calls OnStartup() when it starts, and OnShutdown() when it closes. This is very similar to IExternalApplication, but note that these methods return
Autodesk.Revit.DB.ExternalDBApplicationResult rather than Autodesk.Revit.UI.Result and use ControlledApplication rather than UIControlledApplication.

Code Region: IExternalDBApplication OnShutdown() and OnStartup()


1. public interface IExternalDBApplication
2. {
3. public Autodesk.Revit.DB.ExternalDBApplicationResult OnStartup(ControlledApplication application);
4. public Autodesk.Revit.DB.ExternalDBApplicationResult OnShutdown(ControlledApplication application);
5. }

The ControlledApplication parameter provides access to Revit database events. Events and Updaters to which the database-level application will respond can
be registered in the OnStartup method.
Application and Document
The top level objects in the Revit Platform API are application and document. These are represented by the classes Application,
UIApplication, Document and UIDocument.

• The application object refers to an individual Revit session, providing access to documents, options, and other application-wide data
and settings.

o Autodesk.Revit.UI.UIApplication - provides access to UI-level interfaces for the application, including the ability to add
RibbonPanels to the user interface, and the ability to obtain the active document in the user interface.

o Autodesk.Revit.ApplicationServices.Application - provides access to all other application level properties.

• The document object is a single Revit project file representing a building model. Revit can have multiple projects open and multiple
views for one project.

o Autodesk.Revit.UI.UIDocument - provides access to UI-level interfaces for the document, such as the contents of the
selection and the ability to prompt the user to make selections and pick points

o Autodesk.Revit.DB.Document - provides access to all other document level properties

• If multiple documents are open, the active document is the one whose view is active in the Revit session.

This chapter identifies all Application and Document functions, and then focuses on file management, settings, and units. For more details
about the Element class, refer to Elements Essentials and Editing Elements and refer to the Views for more details about the view elements.

Application Functions
Application functions provide access to documents, objects, and other application data and settings. All Application and UIApplication
functions are identified and defined in the following sections.

Application

The class represents the Autodesk Revit Application, providing access to documents, options and other application wide data and settings.

Application Version Information

Application properties include VersionBuild, VersionNumber and VersionName. These can be used to provide add-in behavior based on the
release and build of Revit, as shown in How to use Application properties to enforce a correct version for your add-in.

Application-wide Settings

The SharedParametersFilename property and GetLibraryPaths() and SetLibraryPaths() methods provide access to these application-wide
settings.

Document Management

The Application class provides methods to create the following types of documents:

• Family document

• Project document

• Project template

The OpenDocumentFile() method can be used to open any of these document types.

All open documents can be retrieved using the Documents property.

For more details, see Document and Management.

Session Information

Properties such as UserName and methods such as GetRevitServerNetworkHosts() provide read-only access to this session specific
information.

Shared Parameter Management

Revit uses one shared parameter file at a time. The Application.OpenSharedParameterFile() method accesses the shared parameter file
whose path is set in the SharedParametersFilename property. For more details, see Shared Parameter.
Events

The Application class exposes document and application events such as document open and save. Subscribing to these events notifies the
application when the events are enabled and acts accordingly. For more details, see Access to Revit Event in the Add-In Integration section.

Create

The Create property returns an Object Factory used to create application-wide utility and geometric objects in the Revit Platform API. Create
is used when you want to create an object in the Revit application memory rather than your application's memory.

Failure Posting and Handling

The FailureDefinitionRegistry, which contains all registered FailureDefinitions is available from the static GetFailureDefinitionRegistry()
method. The static method RegisterFailuresProcessor() can be used to register a custom IFailuresProcessor. For more information on posting
and handling failures, see Failure Posting and Handling.

UIApplication

This class represents an active session of the Autodesk Revit user interface, providing access to UI customization methods, events, and the
active document.

Document Management

The UIApplication provides access to the active document using the UIActiveDocument property. Additionally, a Revit document may be
opened using the overloaded OpenAndActivateDocument() method. The document will be opened with the default view active. This method
may not be called inside a transaction and may only be invoked during an event when no active document is open yet in Revit and the event
is not nested inside another event.

Add-in Management

The ActiveAddInId property gets the current active external application or external command id, while the LoadedApplications property
returns an array of successfully loaded external applications.

Ribbon Panel Utility

Use the UIApplication object to add new ribbon panels and controls to Revit.

For more details, see Ribbon Panel and Controls in the Add-In Integration section.

Extents

The DrawingAreaExtents property returns a rectangle that represents the screen pixel coordinates of drawing area, while the
MainWindowExtents property returns the rectangle that represents the screen pixel coordinates of the Revit main window

Events

The UIApplication class exposes UI related events such as when a dialog box is displayed. Subscribing to these events notifies the application
when the events are enabled and acts accordingly. For more details, see Access to Revit Event in the Add-In Integration section.
Discipline Controls
The properties:

• Application.IsArchitectureEnabled
• Application.IsStructureEnabled
• Application.IsStructuralAnalysisEnabled
• Application.IsMassingEnabled
• Application.IsEnergyAnalysisEnabled
• Application.IsSystemsEnabled
• Application.IsMechanicalEnabled
• Application.IsMechanicalAnalysisEnabled
• Application.IsElectricalEnabled
• Application.IsElectricalAnalysisEnabled
• Application.IsPipingEnabled
• Application.IsPipingAnalysisEnabled

provide read and modify access to the available disciplines. An application can read the properties to determine when to enable or disable aspects of it's UI.

When a discipline's status is toggled, Revit's UI will be adjusted, and certain operations and features will be enabled or disabled as appropriate. Enabling an
analysis mode will only take effect if the corresponding discipline is enabled. For example, enabling mechanical analysis will not take effect unless the
mechanical discipline is also enabled.

How to use Application properties to enforce a correct version for your


add-in
Sometimes you need your add-in to operate only in the presence of a particular Update Release of Revit due to the presence of specific fixes or compatible
APIs. The following sample code demonstrates a technique to determine if the Revit version is any Update Release after the initial known Revit release.

Code Region: Use VersionBuild to identify if your add-in is compatible


1. public void GetVersionInfo(Autodesk.Revit.ApplicationServices.Application app)
2. {
3. // 20110309_2315 is the datecode of the initial release of Revit 2012
4. if (app.VersionNumber == "2012" &&
5. String.Compare(app.VersionBuild, "20110309_2315") > 0)
6. {
7. TaskDialog.Show("Supported version",
8. "This application supported in this version.");
9. }
10. else
11. {
12. TaskDialog dialog = new TaskDialog("Unsupported version.");
13. dialog.MainIcon = TaskDialogIcon.TaskDialogIconWarning;
14. dialog.MainInstruction = "This application is only supported in Revit 2012 UR1 and later.";
15. dialog.Show();
16. }
Document Functions
Document stores the Revit Elements, manages the data, and updates multiple data views. The Document class mainly provides the following
functions.

Document

The Document class represents an open Autodesk Revit project.

Settings Property

The Settings property returns an object that provides access to general components within Revit projects. For more details, see Settings.

Place and Locations

Each project has only one site location that identifies the physical project location on Earth. There can be several project locations for one
project. Each location is an offset, or rotation, of the site location. For more details, see Place and Locations.

Type Collections

Document provides properties such as FloorTypes, WallTypes, and so on. All properties return a collection object containing the
corresponding types loaded into the project.

View Management

A project document can have multiple views. The ActiveView property returns a View object representing the active view. You can filter the
elements in the project to retrieve other views. For more details, see Views.

Element Retrieval

The Document object stores elements in the project. Retrieve specific elements by ElementId or UniqueId using the Element property.

For more details, see Elements Essential.

File Management

Each Document object represents a Revit project file. Document provides the following functions:

• Retrieve file information such as file path name and project title.

• Provides Close() and Save() methods to close and save the document.

For more details, see Document and File management.

Element Management

Revit maintains all Element objects in a project. To create new elements, use the Create property which returns an Object Factory used to
create new project element instances in the Revit Platform API, such as FamilyInstance or Group.

The Document class can also be used to delete elements. Use the Delete() method to delete an element in the project. Deleted elements and
any dependent elements are not displayed and are removed from the Document. References to deleted elements are invalid and cause an
exception. For more details, see Editing Element.

Events

Events are raised on certain actions, such as when you save a project using Save or Save As. To capture the events and respond in the
application, you must register the event handlers. For more details, see Events.
Document Status

Several properties provide information on the status of the document:

• IsModifiable - whether the document may be modified

• IsModified - whether the document was changed since it was opened or saved

• IsReadOnly - whether the document is currently read only or can be modified

• IsReadOnlyFile - whether the document was opened in read-only mode

• IsFamilyDocument - whether the document is a family document

• IsWorkshared - whether worksets have been enabled in the document

Others

Document also provides other functions:

• ParameterBindings Property - Mapping between parameter definitions and categories. For more details, see Shared Parameter.

• ReactionsAreUpToDate Property - Reports whether the reactionary loads changed. For more details, see Loads in the Revit Structure
section.

UIDocument

The UIDocument class represents an Autodesk Revit project opened in the Revit user interface.

Element Retrieval

Retrieve selected elements using the Selection property in UIDocument. This property returns an object representing the active selection
containing the selected project elements. It also provides UI interaction methods to pick objects in the Revit model.

For more details, see Elements Essential.

Element Display

The ShowElements() method uses zoom to fit to focus in on one more elements.

View Management

The UIDocument class can be used to refresh the active view in the active document by calling the RefreshActiveView() method. The
ActiveView property can be used to retrieve or set the active view for the document. Changing the active view has some restrictions. It can
only be used in an active document, which must not be in read-only state and must not be inside a transaction. Additionally, the active view
may not be changed during the ViewActivating or ViewActivated event, or during any pre-action event, such as DocumentSaving,
DocumentClosing, or other similar events.

The UIDocument can also be used to get a list of all open view windows in the Revit user interface. The GetOpenUIViews method returns a
list of UIViews which contain data about the view windows in the Revit user interface.
Document and File Management
Document and file management make it easy to create and find your documents.

Document Retrieval

The Application class maintains all documents. As previously mentioned, you can open more than one document in a session. The active
document is retrieved using the UIApplication class property, ActiveUIDocument.

All open documents, including the active document, are retrieved using the Application class Documents property. The property returns a set
containing all open documents in the Revit session.

Document File Information

The Document class provides two properties for each corresponding file, PathName, and Title.

• PathName returns the document's fully qualified file path. The PathName returns an empty string if the project has not been saved
since it was created.

• Title is the project title, which is usually derived from the project filename. The returned value varies based on your system settings.
Open a Document

The Application class provides an overloaded method to open an existing project file:

Table 3: Open Document in API

Method Event

Document OpenDocumentFile(string filename ) DocumentOpened


Document OpenDocumentFile(ModelPath modelPath, OpenOptions openOptions)

When you specify a string with a fully qualified file path, Revit opens the file and creates a Document instance. Use this method to open a file
on other computers by assigning the files Universal Naming Conversion (UNC) name to this method.

The file can be a project file with the extension .rvt, a family file with the extension .rfa, or a template file with the extension .rte.

The second overload takes a path to the model as a ModelPath rather than a string and the OpenOptions parameter offers options for
opening the file, such as the ability to detach the opened document from central if applicable, as well as options related to worksharing. For
more information about opening a workshared document, see Opening a Workshared Document.

These methods throw specific documented exceptions in the event of a failure. Exceptions fall into 4 main categories.

Table 4: Types of exceptions thrown

Type Example

Disk errors File does not exist or is wrong version

Resource errors Not enough memory or disk space to open file

Central model file errors File is locked or corrupt

Central model/server errors Network communication error with server

If the document is opened successfully, the DocumentOpened event is raised.


Create a Document

Create new documents using the Application methods in the following table.

Table 5: Create Document in the API

Method Event

Document NewProjectDocument(string templateFileName); DocumentCreated

Document NewFamilyDocument(string templateFileName); DocumentCreated

Document NewProjectTemplateDocument(string templateFilename); DocumentCreated


Each method requires a template file name as the parameter. The created document is returned based on the template file.

Save and Close a Document

The Document class provides methods to save or close instances.

Table 6: Save and Close Document in API

Method Event

Save() DocumentSaved

SaveAs() DocumentSavedAs

Close() DocumentClosed

Save() has 2 overloads, one with no arguments and one with a SaveOptions argument that can specify whether to force the OS to delete all
dead data from the file on disk. If the file has not been previously saved, SaveAs() must be called instead.

SaveAs() has 3 overloads. One overload takes only the filename as an argument and an exception will be thrown if another file exists with
the given filename. The other 2 overloads takes a filename as an argument (in the form of a ModelPath in one case) as well as a second
SaveAsOptions argument that specifies whether to rename the file and/or whether to overwrite and existing file, if it exists. SaveAsOptions
can also be used to specify other relevant options such as whether to remove dead data on disk related to the file and worksharing options.

Save() and SaveAs() throw specific documented exceptions in the same 4 categories as when opening a document and listed in Table 4
above.

Close() has two overloads. One takes a Boolean argument that indicates whether to save the file before closing it. The second overload takes
no arguments and if the document was modified, the user will be asked if they want to save the file before closing. This method will throw an
exception if the document's path name is not already set or if the saving target file is read-only.

Note

The Close() method does not affect the active document or raise the DocumentClosed event, because the document is used by an external
application. You can only call this method on non-active documents.

The UIDocument class also provides methods to save and close instances.

Table 7: Save and Close UIDocument in API

Method Event

SaveAndClose() DocumentSaved, DocumentClosed

SaveAs() DocumentSavedAs

SaveAndClose() closes the document after saving it. If the document's path name has not been set the "Save As" dialog will be shown to the
Revit user to set its name and location.

The SaveAs() method saves the document to a file name and path obtained from the Revit user via the "Save As" dialog.

Document Preview

The DocumentPreviewSettings class can be obtained from the Document and contains the settings related to the saving of preview images
for a given document.
Code Region: Document Preview
1. public void SaveActiveViewWithPreview(UIApplication application)
2. {
3. // Get the handle of current document.
4. Autodesk.Revit.DB.Document document = application.ActiveUIDocument.Document;
5.
6. // Get the document's preview settings
7. DocumentPreviewSettings settings = document.GetDocumentPreviewSettings();
8.
9. // Find a candidate 3D view
10. FilteredElementCollector collector = new FilteredElementCollector(document);
11. collector.OfClass(typeof(View3D));
12.
13. Func<View3D, bool> isValidForPreview = v => settings.IsViewIdValidForPreview(v.Id);
14.
15. View3D viewForPreview = collector.OfType<View3D>().First<View3D>(isValidForPreview);
16.
17. // Set the preview settings
18. Transaction setTransaction = new Transaction(document, "Set preview view id");
19. setTransaction.Start();
20. settings.PreviewViewId = viewForPreview.Id;
21. setTransaction.Commit();
22.
23. // Save the document
24. document.Save();
25. }

Load Family

The Document class provides you with the ability to load an entire family and all of its symbols into the project. Because loading an entire
family can take a long time and a lot of memory, the Document class provides a similar method, LoadFamilySymbol() to load only specified
symbols.

For more details, see Loading Families.


Settings
The following table identifies the commands in the Revit Platform UI Manage tab, and corresponding APIs.

Table 7: Settings in API and UI

UI command Associated API Reference

Settings Project Information Document.ProjectInformation See the following note

Settings Project Parameters Document.ParameterBindings (Only for Shared Parameter) See Shared Parameter

Project Location panel Document.ProjectLocations See Place and Locations


Document.ActiveProjectLocation

Settings Additional Settings Fill Patterns FilteredElementCollector filtering on class FillPatternElement See the following note

Settings Materials Document.Settings.Materials See Materials Management

Settings Object Styles Document.Settings.Categories See the following note

Phasing Phases Document.Phases See the following note

Settings Structural Settings Load related structural settings are available in the API See Revit Structure

Settings Project Units Document.GetUnits() See Units

Area and Volume Calculations (on the Room & Area panel) Document.Settings.VoumeCalculationSetting See the following note
Note

• Project Information - The API provides the ProjectInfo class which is retrieved using Document.ProjectInformation to represent
project information in the Revit project. The following table identifies the corresponding APIs for the Project Information parameters.
Table 8: ProjectInformation

Parameters Corresponding API Built-in Parameters

Project Issue Date ProjectInfo.IssueDate PROJECT_ISSUE_DATE

Project Status ProjectInfo.Status PROJECT_STATUS

Client Name ProjectInfo.ClientName CLIENT_NAME

Project Address ProjectInfo.Address PROJECT_ADDRESS

Project Name ProjectInfo.Name PROJECT_NAME

Project Number ProjectInfo.Number PROJECT_NUMBER

Use the properties exposed by ProjectInfo to retrieve and set all strings. These properties are implemented by the corresponding
built-in parameters. You can get or set the values through built-in parameters directly. For more information about how to gain
access to these parameters through the built-in parameters, see Parameter in the Elements Essential section. The recommended
way to get project information is to use the ProjectInfo properties.

• Fill Patterns - Retrieve all Fill Patterns in the current document using a FilteredElementCollector filtering on class FillPatternElement.
Specific FillPatterns can be retrieved using the static methods FillPatternElement.GetFillPattern(Document, ElementId) or
FillPatternElement.GetFillPatternByName (Document, string).

• Object Styles - Use Settings.Categories to retrieve all information in Category objects except for Line Style. For more details, see
Categories in the Elements Essentialand Material sections.

• Phases - Revit maintains the element lifetime by phases, which are distinct time periods in the project lifecycle. All phases in a
document are retrieved using the Document.Phases property. The property returns an array containing Phase class instances.
However, the Revit API does not expose functions from the Phase class.

• Options - The Options command configures project global settings. You can retrieve an Options.Application instance using the
Application.Options property. Currently, the Options.Application class only supports access to library paths and shared parameters
file.

• Area and Volume Calculations - The Document.Settings.VolumeCalculationSetting allows you to enable or disable volume calculations,
and to change the room boundary location.
Units
The two main classes in the Revit API for working with units are Units and FormatOptions. The Units class represents a document's default
settings for formatting numbers with units as strings. It contains a FormatOptions object for each unit type as well as settings related to
decimal symbol and digit grouping.

The Units class stores a FormatOptions object for every valid unit type, but not all of them can be directly modified. Some, like UT_Number
and UT_SiteAngle, have fixed definitions. Others have definitions which are automatically derived from other unit types. For example,
UT_SheetLength is derived from UT_Length and UT_ForceScale is derived from UT_Force.

The FormatOptions class contains settings that control how to format numbers with units as strings. It contains those settings that are
typically chosen by an end-user in the Format dialog and stored in the document, such as rounding, accuracy, display units, and whether to
suppress spaces or leading or trailing zeros.

The FormatOptions class is used in two different ways. A FormatOptions object in the Units class represents the default settings for the
document. A FormatOptions object used elsewhere represents settings that may optionally override the default settings.

The UseDefault property controls whether a FormatOptions object represents default or custom formatting. If UseDefault is true, formatting
will be according to the default settings in the Units class, and none of the other settings in the object are meaningful. If UseDefault is false,
the object contains custom settings that override the default settings in the Units class. UseDefault is always false for FormatOptions objects
in the Units class.

Important unit-related enumerations in the Revit API include:

• UnitType - type of physical quantity to be measured, for example length or force (UT_Length or UT_Force)

• DisplayUnitType - units and display format used to format numbers as strings or convert units (i.e. DUT_METERS)

• UnitSymbolType - unit symbol displayed in the formatted string representation of a number to indicate the units of the value (i.e.
UST_M)

Unit Conversion

The Revit API provides utility classes to facilitate working with quantities in Revit. The UnitUtils class makes it easy to convert unit data to
and from Revit's internal units.

Revit has seven base quantities, each with its own internal unit. These internal units are identified in the following table.

Table 9: 7 Base Units in Revit Unit System

Base Unit Unit In Revit Unit System

Length Feet (ft) Imperial

Angle Radian Metric

Mass Kilogram (kg) Metric

Time Seconds (s) Metric

Electric Current Ampere (A) Metric

Temperature Kelvin (K) Metric

Luminous Intensity Candela (cd) Metric


Note: Since Revit stores lengths in feet and other basic quantities in metric units, a derived unit involving length will be a non-standard unit
based on both the Imperial and the Metric systems. For example, since a force is measured in "mass-length per time squared", it is stored in
kg-ft / s2.

The following example uses the UnitUtils.ConvertFromInternalUnits() method to get the minimum yield stress for a material in kips per
square inch.
Code Region: Converting from Revit's internal units
1. double GetYieldStressInKsi(Material material)
2. {
3. double dMinYieldStress = 0;
4. // Get the structural asset for the material
5. ElementId strucAssetId = material.StructuralAssetId;
6. if (strucAssetId != ElementId.InvalidElementId)
7. {
8. PropertySetElement pse = material.Document.GetElement(strucAssetId) as PropertySetElement;
9. if (pse != null)
10. {
11. StructuralAsset asset = pse.GetStructuralAsset();
12.
13. // Get the min yield stress and convert to ksi
14. dMinYieldStress = asset.MinimumYieldStress;
15. dMinYieldStress = UnitUtils.ConvertFromInternalUnits(dMinYieldStress,
16. DisplayUnitType.DUT_KIPS_PER_SQUARE_INCH);
17. }
18. }
19.
20. return dMinYieldStress;
21. }

The UnitUtils can also be used to convert a value from one unit type to another, such as square feet to square meters. In the following
example, a wall's top offset value that was entered in inches is converted to feet, the expected unit for setting that value.

Code Region: Converting between units


1. void SetTopOffset(Wall wall, double dOffsetInches)
2. {
3. // convert user-defined offset value to feet from inches prior to setting
4. double dOffsetFeet = UnitUtils.Convert(dOffsetInches,
5. DisplayUnitType.DUT_DECIMAL_INCHES,
6. DisplayUnitType.DUT_DECIMAL_FEET);
7.
8. Parameter paramTopOffset = wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET);
9. paramTopOffset.Set(dOffsetFeet);
10. }

Unit formatting and parsing

Another utility class, UnitFormatUtils, can format data or parse formatted unit data.

The overloaded method FormatValueToString() can be used to format a value into a string based on formatting options as the following
example demonstrates. The material density is retrieved and then the value is then converted to a user-friendly value with unit using the
FormatValueToString() method.

Code Region: Format value to string


1. void DisplayDensityOfMaterial(Material material)
2. {
3. double dDensity = 0;
4. // get structural asset of material in order to get the density
5. ElementId strucAssetId = material.StructuralAssetId;
6. if (strucAssetId != ElementId.InvalidElementId)
7. {
8. PropertySetElement pse = material.Document.GetElement(strucAssetId) as PropertySetElement;
9. if (pse != null)
10. {
11. StructuralAsset asset = pse.GetStructuralAsset();
12.
13. dDensity = asset.Density;
14. // convert the density value to a user readable string that includes the units
15. Units units = material.Document.GetUnits();
16. string strDensity = UnitFormatUtils.FormatValueToString(units, UnitType.UT_UnitWeight, dDensity, false, false);
17. string msg = string.Format("Raw Value: {0}\r\nFormatted Value: {1}", dDensity, strDensity);
18. TaskDialog.Show("Material Density", msg);
19. }
20. }
21. }

The overloaded UnitFormatUtils.TryParse() method parses a formatted string, including units, into a value if possible, using the Revit internal
units of the specified unit type. The following example takes a user entered length value, assumed to be a number and length unit, and
attempts to parse it into a length value. The result is compared with the input string in a TaskDialog for demonstration purposes.
Code Region: Parse string
1. double GetLengthInput(Document document, String userInputLength)
2. {
3. double dParsedLength = 0;
4. Units units = document.GetUnits();
5. // try to parse a user entered string (i.e. 100 mm, 1'6")
6. bool parsed = UnitFormatUtils.TryParse(units, UnitType.UT_Length, userInputLength, out dParsedLength);
7. if (parsed == true)
8. {
9. string msg = string.Format("User Input: {0}\r\nParsed value: {1}", userInputLength, dParsedLength);
10. TaskDialog.Show("Parsed Data", msg);
11. }
12.
13. return dParsedLength;
Elements Essentials
An Element corresponds to a single building or drawing component, such as a door, a wall, or a dimension. In addition, an Element can be a
door type, a view, or a material definition.

Element Classification
Revit Elements are divided into six groups: Model, Sketch, View, Group, Annotation and Information. Each group contains related Elements
and their corresponding symbols.

Model Elements

Model Elements represent physical items that exist in a building project. Elements in the Model Elements group can be subdivided into the
following:

• Family Instances - Family Instances contain family instance objects. You can load family objects into your project or create them from
family templates. For more information, see Family Instances.

• Host Elements - Host Elements contain system family objects that can contain other model elements, such as wall, roof, ceiling, and
floor. For more information about Host Elements, see Walls, Floors, Roofs and Openings.

• Structure Elements. - Structure Elements contain elements that are only used in Revit Structure. For more information about
Structure Elements, see Revit Structure.
View Elements

View Elements represent the way you view and interact with other objects in Revit. For more information, see Views.

Group Elements

Group Elements represent the assistant Elements such as Array and Group objects in Revit. For more information, see Editing Elements.

Annotation and Datum Elements

Annotation and Datum Elements contain non-physical items that are visible.

• Annotation Elements represent 2D components that maintain scale on paper and are only visible in one view. For more information
about Annotation Elements, see Annotation Elements.

Note Annotation Elements representing 2D components do not exist only in 2D views. For example, dimensions can be drawn in 3D view
while the shape they refer to only exists in a 2D planar face.

• Datum Elements represent non-physical items that are used to establish project context. These elements can exist in views. Datum
Elements are further divided into the following:

• Common Datum Elements - Common Datum Elements represent non-physical visible items used to store data for modeling.

• Datum FamilyInstance - Datum FamilyInstance represents non-physical visible items loaded into your project or created from family
templates.

NoteFor more information about Common Datum Elements and Datum FamilyInstance, see Datum and Information Elements; for
ModelCurve related contents, see Sketching.

• Structural Datum Elements - Structural Datum Elements represent non-physical visible items used to store data for structure
modeling. For more information about Structural Datum Elements, see Revit Structure.
Sketch Elements

Sketch Elements represent temporary items used to sketch 2D/3D form. This group contains the following objects used in family modeling
and massing:

• SketchPlane

• Sketch

• Path3D

• GenericForm.

For Sketch details, see Sketching.


Information Elements

Information Elements contain non-physical invisible items used to store project and application data. Information Elements are further
separated into the following:

• Project Datum Elements

• Project Datum Elements (Unique).

For more information about Datum Elements, see Datum and Information Elements.

Other Classifications
Elements are also classified by the following:

• Category

• Family

• Symbol

• Instance

There are some relationships between the classifications. For example:

• You can distinguish different kinds of FamilyInstances by the category. Items such as structural columns are in the Structural
Columns category, beams and braces are in the Structural Framing category, and so on.

• You can differentiate structural FamilyInstance Elements by their symbol.


Category

The Element.Category property represents the category or subcategory to which an Element belongs. It is used to identify the Element type.
For example, anything in the walls Category is considered a wall. Other categories include doors and rooms.

Categories are the most general class. The Document.Settings.Categories property is a map that contains all Category objects in the
document and is subdivided into the following:

• Model Categories - Model Categories include beams, columns, doors, windows, and walls.

• Annotation Categories. Annotation Categories include dimensions, grids, levels, and textnotes.

Figure 20: Categories


Note

The following guidelines apply to categories:

• In general, the following rules apply to categories:

o Each family object belongs to a category

o Non-family objects, like materials and views, do not belong to a category

o There are exceptions such as ProjectInfo, which belongs to the Project Information category.

• An element and its corresponding symbols are usually in the same category. For example, a basic wall and its wall type Generic - 8"
are all in the Walls category.

• The same type of Elements can be in different categories. For example, SpotDimensions has the SpotDimensionType, but it can
belong to two different categories: Spot Elevations and Spot Coordinates.

• Different Elements can be in the same category because of their similarity or for architectural reasons. ModelLine and DetailLine are
in the Lines category.

To gain access to the categories in a document' Setting class (for example, to insert a new category set), use one of the following
techniques:

• Get the Categories from the document properties.

• Get a specific category quickly from the categories map using the BuiltInCategory enumerated type.
Code Region 5-1: Getting categories from document settings
// Get settings of current document
Settings documentSettings = document.Settings;

// Get all categories of current document


Categories groups = documentSettings.Categories;

// Show the number of all the categories to the user


String prompt = "Number of all categories in current Revit document:" + groups.Size;

// get Floor category according to OST_Floors and show its name


Category floorCategory = groups.get_Item(BuiltInCategory.OST_Floors);
prompt += floorCategory.Name;

// Give the user some information


MessageBox.Show(prompt, "Revit", MessageBoxButtons.OK);

Category is used in the following manner:

• Category is used to classify elements. The element category determines certain behaviors. For example, all elements in the same
category can be included in the same schedule.

• Elements have parameters based on their categories.

• Categories are also used for controlling visibility and graphical appearance in Revit.
Figure 21: Visibility by Category

An element's category is determined by the Category ID.

• Category IDs are represented by the ElementId class.

• Imported Category IDs correspond to elements in the document.

• Most categories are built-in and their IDs are constants stored in ElementIds.

• Each built-in category ID has a corresponding value in the BuiltInCategory Enumeration. They can be converted to corresponding
BuiltInCategory enumerated types.

• If the category is not built-in, the ID is converted to a null value.


Code Region 5-2: Getting element category
Element selectedElement = null;
foreach (Element e in document.Selection.Elements)
{
selectedElement = e;
break; // just get one selected element
}

// Get the category instance from the Category property


Category category = selectedElement.Category;

BuiltInCategory enumCategory = (BuiltInCategory)category.Id.Value;


NoteTo avoid Globalization problems when using Category.Name, BuiltInCategory is a better choice. Category.Name can be different in
different languages.

Family

Families are classes of Elements within a category. Families can group Elements by the following:

• A common set of parameters (properties).

• Identical use.

• Similar graphical representation.

Most families are component Family files, meaning that you can load them into your project or create them from Family templates. You
determine the property set and the Family graphical representation.

Another family type is the system Family. System Families are not available for loading or creating. Revit predefines the system Family
properties and graphical representation; they include walls, dimensions, roofs, floors (or slabs), and levels.

Figure 22: Families

In addition to functioning as an Element class, Family is also a template used to generate new items that belong to the Family.

Family in the Revit Platform API

In the Revit Platform API, both the Family class and FamilyInstance belong to the Component Family. Other Elements include System Family.

Families in the Revit Platform API are represented by three objects:

• Family

• FamilySymbol

• FamilyInstance.

Each object plays a significant role in the Family structure.

The Family object has the following characteristics:

• Represents an entire family such as a beam.

• Represents the entire family file on a disk.

• Contains a number of FamilySymbols.

The FamilySymbol object represents a specific set of family settings in the Family such as the Type, Concrete-Rectangular Beam: 16×32.

The FamilyInstance object is a FamilySymbol instance representing a single instance in the Revit project. For example, the FamilyInstance
can be a single instance of a 16×32 Concrete-Rectangular Beam in the project.

NoteRemember that the FamilyInstance exists in FamilyInstance Elements, Datum Elements, and Annotation Elements.

Consequently, the following rules apply:

• Each FamilyInstance has one FamilySymbol.

• Each FamilySymbol belongs to one Family.


• Each Family contains one or more FamilySymbols.

For more detailed information, see Family Instances.

ElementType

In the Revit Platform API, Symbols are usually non-visible elements used to define instances. Symbols are called Types in the user interface.

• A type can be a specific size in a family, such as a 1730 × 2032 door, or an 8×4×1/2 angle.

• A type can be a style, such as default linear or default angular style for dimensions.

Symbols represent Elements that contain shared data for a set of similar elements. In some cases, Symbols represent building components
that you can get from a warehouse, such as doors or windows, and can be placed many times in the same building. In other cases, Symbols
contain host object parameters or other elements. For example, a WallType Symbol contains the thickness, number of layers, material for
each layer, and other properties for a particular wall type.

FamilySymbol is a symbol in the API. It is also called Family Type in the Revit user interface. FamilySymbol is a class of elements in a family
with the exact same values for all properties. For example, all 32×78 six-panel doors belong to one type, while all 24×80 six-panel doors
belong to another type. Like a Family, a FamilySymbol is also a template. The FamilySymbol object is derived from the ElementType object
and the Element object.

Instance

Instances are items with specific locations in the building (model instances) or on a drawing sheet (annotation instances). Instance
represents transformed identical copies of an ElementType. For example, if a building contains 20 windows of a particular type, there is one
ElementType with 20 Instances. Instances are called Components in the user interface.

Note

For FamilyInstance, the Symbol property can be used instead of the GetTypeId() method to get the corresponding FamilySymbol. It is
convenient and safe since you do not need to do a type conversion.
Element Retrieval
Elements in Revit are very common. Retrieving the elements that you want from Revit is necessary before using the API for any Element
command. There are several ways to retrieve elements with the Revit API:

• ElementId - If the ElementId of the element is known, the element can be retrieved from the document.

• Element filtering and iteration - this is a good way to retrieve a set of related elements in the document.

• Selected elements - retrieves the set of elements that the user has selected

• Specific elements - some elements are available as properties of the document

Each of these methods of element retrieval is discussed in more details in the following sections.

Getting an Element by ID

When the ElementId of the desired element is known, use the Document.Element property to get the element.

Filtering the Elements Collection

The most common way to get elements in the document is to use filtering to retrieve a collection of elements. The Revit API provides the
FilteredElementCollector class, and supporting classes, to create filtered collections of element which can then be iterated. See Filtering for
more information.

Selection

Rather than getting a filtered collection of all of the elements in the model, you can access just the elements that have been selected. You
can get the selected objects from the current active document using the UIDocument.Selection.Elements property. For more information on
using the active selection, see Selection.

Accessing Specific Elements from Document

In addition to using the general way to access Elements, the Revit Platform API has properties in the Document class to get the specified
Elements from the current active document without iterating all Elements. The specified Elements you can retrieve are listed in the following
table.

Table 11: Retrieving Elements from document properties

Element Access in property of Document

ProjectInfo Document.ProjectInformation

ProjectLocation Document.ProjectLocations
Document.ActiveProjectLocation

SiteLocation Document.SiteLocation

Phase Document.Phases

Material Document.Settings.Materials

FamilySymbol relative to the deck Document.DeckProfiles


profile of the layer within a structure

FamilySymbol in the Title Block Document.TitleBlocks


category

All Element types Document.AnnotationSymbolTypes / BeamSystemTypes / ContFootingTypes / DimensionTypes / FloorTypes /


GridTypes / LevelTypes / RebarBarTypes / RebarHookTypes / RoomTagTypes / SpotDimensionTypes / WallTypes /
TextNoteTypes
General Properties
The following properties are common to each Element created using Revit.

ElementId

Every element in an active document has a unique identifier represented by the ElementId storage type. ElementId objects are project wide.
It is a unique number that is never changed in the element model, which allows it to be stored externally to retrieve the element when
needed.

To view an element ID in Revit, complete the following steps:

1. From the Modify tab, on the Inquiry panel, select Element ID. The Element ID drop down menu appears.

Select IDs of Selection to get the ID number for one element.

Figure 23: ElementId

In the Revit Platform API, you can create an ElementId directly, and then associate a unique integer value to the new ElementId. The new
ElementId value is 0 by default.

Code Region 5-3: Setting ElementId


// Get the id of the element
Autodesk.Revit.DB.ElementId selectedId = element.Id;
int idInteger = selectedId.IntegerValue;

// create a new id and set the value


Autodesk.Revit.DB.ElementId id = new Autodesk.Revit.DB.ElementId(idInteger);

ElementId has the following uses:

• Use ElementId to retrieve a specific element from Revit. From the Revit Application class, gain access to the active document, and
then get the specified element using the Document.GetElement(ElementId) method.

Code Region 5-4: Using ElementId


// Get the id of the element
Autodesk.Revit.DB.ElementId selectedId = element.Id;
int idInteger = selectedId.IntegerValue;

// create a new id and set the value


Autodesk.Revit.DB.ElementId id = new Autodesk.Revit.DB.ElementId(idInteger);

// Get the element


Autodesk.Revit.DB.Element first = document.GetElement(id);

If the ID number does not exist in the project, the element you retrieve is null.

• Use ElementId to check whether two Elements in one project are equal or not. It is not recommended to use the Object.Equal()
method.
UniqueId

Every element has a UniqueId, represented by the String storage type. The UniqueId corresponds to the ElementId. However, unlike
ElementId, UniqueId functions like a GUID (Globally Unique Identifier), which is unique across separate Revit projects. UniqueId can help
you to track elements when you export Revit project files to other formats.
Code Region 5-5: UniqueId
String uniqueId = element.UniqueId;
NoteThe ElementId is only unique in the current project. It is not unique across separate Revit projects. UniqueId is always unique across
separate projects.

Location

The location of an object is important in the building modeling process. In Revit, some objects have a point location. For example a table has
a point location. Other objects have a line location, representing a location curve or no location at all. A wall is an element that has a line
location.

The Revit Platform API provides the Location class and location functionality for most elements. For example, it has the Move() and Rotate()
methods to translate and rotate the elements. However, the Location class has no property from which you can get information such as a
coordinate. In this situation, downcast the Location object to its subclass-like LocationPoint or LocationCurve-for more detailed location
information and control using object derivatives.

Retrieving an element's physical location in a project is useful when you get the geometry of an object. The following rules apply when you
retrieve a location:

• Wall, Beam, and Brace are curve-driven using LocationCurve.

• Room, RoomTag, SpotDimension, Group, FamilyInstances that are not curve-driven, and all In-Place-FamilyInstances use
LocationPoint.

In the Revit Platform API, curve-driven means that the geometry or location of an element is determined by one or more associated curves.
Almost all analytical model elements are curve-driven - linear and area loads, walls, framing elements, and so on.

Other Elements cannot retrieve a LocationCurve or LocationPoint. They return Location with no information.

Table 12: Elements Location Information

Location Information Elements

LocationCurve Wall, Beam, Brace, Structural Truss, LineLoad(without host)

LocationPoint Room, RoomTag, SpotDimension, Group, Column, Mass

Only Location Level, Floor, some Tags, BeamSystem, Rebar, Reinforcement, PointLoad, AreaLoad(without Host), Span Direction(IndependentTag)

No Location View, LineLoad(with host), AreaLoad(with Host), BoundaryCondition


NoteThere are other Elements without Location information. For example a LineLoad (with host) or an AreaLoad (with host) have no
Location.

Some FamilyInstance LocationPoints, such as all in-place-FamilyInstances and masses, are specified to point (0, 0, 0) when they are
created. The LocationPoint coordinate is changed if you transform or move the instance.

To change a Group-s LocationPoint, do one of the following:

• Drag the Group origin in the Revit UI to change the LocationPoint coordinate. In this situation, the Group LocationPoint is changed
while the Group-s location is not changed.

• Move the Group using the ElementTransformUtils.MoveElement() method to change the LocationPoint. This changes both the Group
location and the LocationPoint.

For more information about LocationCurve and LocationPoint, see Move.

Level

Levels are finite horizontal planes that act as a reference for level-hosted or level-based elements, such as roofs, floors, and ceilings. The
Revit Platform API provides a Level class to represent level lines in Revit. Get the Level object to which the element is assigned using the API
if the element is level-based.

Code Region 5-6: Assigning Level


// Get the level object to which the element is assigned.
Level level = element.Level;
A number of elements, such as a column, use a level as a basic reference. When you get the column level, the level you retrieve is the Base
Level.

Figure 24: Column Base Level parameter

Note

Get the Beam or Brace level using the Reference Level parameter. From the Level property, you only get null instead of the reference level
information.

Level is the most commonly used element in Revit. In the Revit Platform API, all levels in the project are located by iterating over the entire
project and searching for Elements.Level objects.

For more Level details, see Datum and Information Elements.

Parameter

Every element has a set of parameters that users can view and edit in Revit. The parameters are visible in the Element Properties dialog box
(select any element and click the Properties button next to the type selector). For example, the following image shows Room parameters.

Figure 25: Room parameters

In the Revit Platform API, each Element object has a Parameters property, which is a collection of all the properties attached to the Element.
You can change the property values in the collection. For example, you can get the area of a room from the room object parameters;
additionally, you can set the room number using the room object parameters. The Parameter is another way to provide access to property
information not exposed in the element object.

In general, every element parameter has an associated parameter ID. Parameter IDs are represented by the ElementId class. For user-
created parameters, the IDs correspond to real elements in the document. However, most parameters are built-in and their IDs are
constants stored in ElementIds.

Parameter is a generic form of data storage in elements. In the Revit Platform API, it is best to use the built-in parameter ID to get the
parameter. Revit has a large number of built-in parameters available using the BuiltInParameter enumerated type.

For more details, see Parameter.


Basic Interaction with Revit Elements
Filtering
The Revit API provides a mechanism for filtering and iterating elements in a Revit document. This is the best way to get a set of related
elements, such as all walls or doors in the document. Filters can also be used to find a very specific set of elements, such as all beams of a
specific size.

The basic steps to get elements passing a specified filter are as follows:

1. Create a new FilteredElementCollector

2. Apply one or more filters to it

3. Get filtered elements or element ids (using one of several methods)

The following sample covers the basic steps to filtering and iterating elements in the document.

Code Region 6-1: Use element filtering to get all wall instances in document
// Find all Wall instances in the document by using category filter
ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_Walls);

// Apply the filter to the elements in the active document


// Use shortcut WhereElementIsNotElementType() to find wall instances only
FilteredElementCollector collector = new FilteredElementCollector(document);
IList<Element> walls =
collector.WherePasses(filter).WhereElementIsNotElementType().ToElements();
String prompt = "The walls in the current document are:\n";
foreach (Element e in walls)
{
prompt += e.Name + "\n";
}
TaskDialog.Show("Revit", prompt);

Create a FilteredElementCollector
The main class used for element iteration and filtering is called FilteredElementCollector. It is constructed in one of three ways:

1. From a document - will search and filter the set of elements in a document

2. From a document and set of ElementIds - will search and filter a specified set of elements

3. From a document and a view - will search and filter the visible elements in a view
NoteAlways check that a view is valid for element iteration when filtering elements in a specified view by using the static
FilteredElementCollector.IsViewValidForElementIteration().

When the object is first created, there are no filters applied. This class requires that at least one condition be set before making at attempt
to access the elements, otherwise an exception will be thrown.

Applying Filters
Filters can be applied to a FilteredElementCollector using ElementFilters. An ElementFilter is a class that examines an element to see if it
meets a certain criteria. The ElementFilter base class has three derived classes that divide element filters into three categories.

• ElementQuickFilter - Quick filters operate only on the ElementRecord, a low-memory class which has a limited interface to read
element properties. Elements which are rejected by a quick filter will not be expanded in memory.

• ElementSlowFilter - Slow filters require that the Element be obtained and expanded in memory first. Thus it is preferable to couple
slow filters with at least one ElementQuickFilter, which should minimize the number of Elements that are expanded in order to
evaluate against the criteria set by this filter.

• ElementLogicalFilter - Logical filters combine two or more filters logically. The component filters may be reordered by Revit to
cause the quickest acting filters to be evaluated first.

Most filters may be inverted using an overload constructor that takes a Boolean argument indicating to invert the filter so that elements that
would normally be accepted by the filter will be rejected, and elements that would normally be rejected will be accepted. Filters that cannot
be inverted are noted in their corresponding sections below.
There is a set of predefined filters available for common uses. Many of these built-in filters provide the basis for the FilteredElementCollector
shortcut methods mentioned in the FilteredElementCollector section above. The next three sections provide more information on the built-in
filters.

Once a filter is created, it needs to be applied to the FilteredElementCollector. The generic method WherePasses() is used to apply a single
ElementFilter to the FilteredElementCollector.

Filters can also be applied using a number of shortcut methods provided by FilteredElementCollector. Some apply a specific filter without
further input, such as WhereElementIsCurveDriven(), while others apply a specific filter with a simple piece of input, such as the
OfCategory() method which takes a BuiltInCategory as a parameter. And lastly there are methods such as UnionWith() that join filters
together. All of these methods return the same collector allowing filters to be easily chained together.

Quick filters

Quick filters operate only on the ElementRecord, a low-memory class which has a limited interface to read element properties. Elements
which are rejected by a quick filter will not be expanded in memory. The following table summarizes the built-in quick filters, and some
examples follow for a few of the filters.

Table 13: Built-in Quick Filters

Built-in Filter What it passes Shortcut Method(s)

BoundingBoxContainsPointFilter Elements which have a bounding box that contains a given None
point

BoundingBoxIntersectsFilter Elements which have a bounding box which intersects a None


given outline

BoundingBoxIsInsideFilter Elements which have a bounding box inside a given None


outline

ElementCategoryFilter Elements matching the input category id OfCategoryId()

ElementClassFilter Elements matching the input runtime class (or derived OfClass()
classes)

ElementDesignOptionFilter Elements in a particular design option ContainedInDesignOption()

ElementIsCurveDrivenFilter Elements which are curve driven WhereElementIsCurveDriven()

ElementIsElementTypeFilter Elements which are "Element types" WhereElementIsElementType()


WhereElementIsNotElementType()

ElementMulticategoryFilter Elements matching any of a given set of categories None

ElementMulticlassFilter Elements matching a given set of classes (or derived None


classes)

ElementOwnerViewFilter Elements which are view-specific OwnedByView() WhereElementIsViewIndependent()

ElementStructuralTypeFilter Elements matching a given structural type None

ExclusionFilter All elements except the element ids input to the filter Excluding()

FamilySymbolFilter Symbols of a particular family

Note The FamilySymbolFilter cannot be inverted.

Note The bounding box filters exclude all objects derived from View and objects derived from ElementType.

The following example creates an outline in the document and then uses a BoundingBoxIntersectsFilter to find the elements in the document
with a bounding box that intersects that outline. It then shows how to use an inverted filter to find all walls whose bounding box do not
intersect the given outline. Note that the use of the OfClass() method applies an ElementClassFilter to the collection as well.

Code Region 6-2: BoundingBoxIntersectsFilter example


// Use BoundingBoxIntersects filter to find elements with a bounding box that intersects the
// given Outline in the document.

// Create a Outline, uses a minimum and maximum XYZ point to initialize the outline.
Outline myOutLn = new Outline(new XYZ(0, 0, 0), new XYZ(100, 100, 100));

// Create a BoundingBoxIntersects filter with this Outline


BoundingBoxIntersectsFilter filter = new BoundingBoxIntersectsFilter(myOutLn);

// Apply the filter to the elements in the active document


// This filter excludes all objects derived from View and objects derived from ElementType
FilteredElementCollector collector = new FilteredElementCollector(document);
IList<Element> elements = collector.WherePasses(filter).ToElements();

// Find all walls which don't intersect with BoundingBox: use an inverted filter
// to match elements
// Use shortcut command OfClass() to find walls only
BoundingBoxIntersectsFilter invertFilter = new BoundingBoxIntersectsFilter(myOutLn, true);
collector = new FilteredElementCollector(document);
IList<Element> notIntersectWalls = collector.OfClass(typeof(Wall)).WherePasses(invertFilter).ToElements();

The next example uses an exclusion filter to find all walls that are not currently selected in the document.

Code Region 6-3: Creating an exclusion filter


// Find all walls that are not currently selected,
// Get all element ids which are current selected by users, exclude these ids when filtering
ICollection<ElementId> excludes = new List<ElementId>();
ElementSetIterator elemIter = uiDocument.Selection.Elements.ForwardIterator();
elemIter.Reset();
while (elemIter.MoveNext())
{
Element curElem = elemIter.Current as Element;
excludes.Add(curElem.Id);
}

// Create filter to exclude all selected element ids


ExclusionFilter filter = new ExclusionFilter(excludes);

// Apply the filter to the elements in the active document,


// Use shortcut method OfClass() to find Walls only
FilteredElementCollector collector = new FilteredElementCollector(uiDocument.Document);
IList<Element> walls = collector.WherePasses(filter).OfClass(typeof(Wall)).ToElements();

Note that the ElementClassFilter will match elements whose class is an exact match to the input class, or elements whose class is derived
from the input class. The following example uses an ElementClassFilter to get all loads in the document.

Code Region 6-4: Using an ElementClassFilter to get loads


// Use ElementClassFilter to find all loads in the document
// Using typeof(LoadBase) will yield all AreaLoad, LineLoad and PointLoad
ElementClassFilter filter = new ElementClassFilter(typeof(LoadBase));

// Apply the filter to the elements in the active document


FilteredElementCollector collector = new FilteredElementCollector(document);
ICollection<Element> allLoads = collector.WherePasses(filter).ToElements();

There is a small subset of Element subclasses in the API which are not supported by the element class filter. These types exist in the API,
but not in Revit's native object model, which means that this filter doesn't support them. In order to use a class filter to find elements of
these types, it is necessary to use a higher level class and then process the results further to find elements matching only the subtype. Note
that dedicated filters exist for some of these types. The following types are affected by this restriction:
Type Dedicated Filter

Subclasses of Autodesk.Revit.DB.Material None

Subclasses of Autodesk.Revit.DB.CurveElement CurveElementFilter

Subclasses of Autodesk.Revit.DB.ConnectorElement None

Subclasses of Autodesk.Revit.DB.HostedSweep None

Autodesk.Revit.DB.Architecture.Room RoomFilter

Autodesk.Revit.DB.Mechanical.Space SpaceFilter

Autodesk.Revit.DB.Area AreaFilter

Autodesk.Revit.DB.Architecture.RoomTag RoomTagFilter

Autodesk.Revit.DB.Mechanical.SpaceTag SpaceTagFilter

Autodesk.Revit.DB.AreaTag AreaTagFilter

Autodesk.Revit.DB.CombinableElement None

Autodesk.Revit.DB.Mullion None

Autodesk.Revit.DB.Panel None

Autodesk.Revit.DB.AnnotationSymbol None

Autodesk.Revit.DB.Structure.AreaReinforcementType None

Autodesk.Revit.DB.Structure.PathReinforcementType None

Autodesk.Revit.DB.AnnotationSymbolType None

Autodesk.Revit.DB.Architecture.RoomTagType None

Autodesk.Revit.DB.Mechanical.SpaceTagType None

Autodesk.Revit.DB.AreaTagType None

Autodesk.Revit.DB.Structure.TrussType None
Slow Filters

Slow filters require that the Element be obtained and expanded in memory first. Thus it is preferable to couple slow filters with at least one
ElementQuickFilter, which should minimize the number of Elements that are expanded in order to evaluate against the criteria set by this
filter. The following table summarizes the built-in slow filters, while a few examples follow to provide an in-depth look at some of the filters.
Table 14: Built-in Slow Filters

Built-in Filter What it passes Shortcut Method(s)

AreaFilter Areas None

AreaTagFilter Area tags None

CurveElementFilter CurveElements None

ElementLevelFilter Elements associated with a given level id None

ElementParameterFilter Elements passing one or more parameter filter rules None

ElementPhaseStatusFilter Elements with a given phase status on a given phase None

FamilyInstanceFilter Instances of a particular family instance None

FamilyStructuralMaterialTypeFilter Family elements of given structural material type None

PrimaryDesignOptionMemberFilter Elements owned by any primary design option None

RoomFilter Rooms None

RoomTagFilter Room tags None

SpaceFilter Spaces None

SpaceTagFilter Space tags None

StructuralInstanceUsageFilter FamilyInstances of given structural usage None

StructuralMaterialTypeFilter FamilyInstances of given structural material type None

StructuralWallUsageFilter Walls of given structural wall usage None

ElementIntersectsElementFilter Elements that intersect the solid geometry of a given element None

ElementIntersectsSolidFilter Elements that intersect the given solid geometry None

The following slow filters cannot be inverted:

• RoomFilter

• RoomTagFilter

• AreaFilter

• AreaTagFilter

• SpaceFilter

• SpaceTagFilter

• FamilyInstanceFilter

As mentioned in the quick filters section, some classes do not work with the ElementClassFilter. Some of those classes, such as Room and
RoomTag have their own dedicated filters.

Code Region 6-5: Using the Room filter


// Use a RoomFilter to find all room elements in the document. It is necessary to use the
// RoomFilter and not an ElementClassFilter or the shortcut method OfClass() because the Room
// class is not supported by those methods.
RoomFilter filter = new RoomFilter();

// Apply the filter to the elements in the active document


FilteredElementCollector collector = new FilteredElementCollector(document);
IList<Element> rooms = collector.WherePasses(filter).ToElements();

The ElementParameterFilter is a powerful filter that can find elements based on values of parameters they may have. It can find elements
whose parameter values match a specific value or are greater or less than some value. ElementParameterFilter can also be used to find
elements that support a specific shared parameter.
The example below uses an ElementParameterFilter to find rooms whose size is more than 100 square feet and rooms with less than 100
square feet.

Code Region 6-6: Using a parameter filter


// Creates an ElementParameter filter to find rooms whose area is
// greater than specified value
// Create filter by provider and evaluator
BuiltInParameter areaParam = BuiltInParameter.ROOM_AREA;
// provider
ParameterValueProvider pvp = new ParameterValueProvider(new ElementId((int)areaParam));
// evaluator
FilterNumericRuleEvaluator fnrv = new FilterNumericGreater();
// rule value
double ruleValue = 100.0f; // filter room whose area is greater than 100 SF
// rule
FilterRule fRule = new FilterDoubleRule(pvp, fnrv, ruleValue, 1E-6);

// Create an ElementParameter filter


ElementParameterFilter filter = new ElementParameterFilter(fRule);

// Apply the filter to the elements in the active document


FilteredElementCollector collector = new FilteredElementCollector(document);
IList<Element> rooms = collector.WherePasses(filter).ToElements();

// Find rooms whose area is less than or equal to 100:


// Use inverted filter to match elements
ElementParameterFilter lessOrEqualFilter = new ElementParameterFilter(fRule, true);
collector = new FilteredElementCollector(document);
IList<Element> lessOrEqualFounds = collector.WherePasses(lessOrEqualFilter).ToElements();

The following example shows how to use the FamilyStructuralMaterialTypeFilter to find all families whose material type is wood. It also
shows how to use an inverted filter to find all families whose material type is not wood.

Code Region 6-7: Find all families with wood material


// Use FamilyStructuralMaterialType filter to find families whose material type is Wood
FamilyStructuralMaterialTypeFilter filter = new FamilyStructuralMaterialTypeFilter(StructuralMaterialType.Wood);

// Apply the filter to the elements in the active document


FilteredElementCollector collector = new FilteredElementCollector(document);
ICollection<Element> woodFamiles = collector.WherePasses(filter).ToElements();

// Find families are not Wood: Use inverted filter to match families
FamilyStructuralMaterialTypeFilter notWoodFilter =
new FamilyStructuralMaterialTypeFilter(StructuralMaterialType.Wood, true);
collector = new FilteredElementCollector(document);
ICollection<Element> notWoodFamilies = collector.WherePasses(notWoodFilter).ToElements();
The last two slow filters derive from ElementIntersectsFilter which is a base class for filters used to match elements which intersect with
geometry. See Code Region: Find Nearby Walls in the section Geometry Utility Classes for an example of the use of this type of filter.

Logical filters

Logical filters combine two or more filters logically. The following table summarizes the built-in logical filters.

Table 15: Built-in Logical Filters

Built-in Filter What it passes Shortcut Method(s)

LogicalAndFilter Elements that pass 2 or more filters WherePasses()- adds one additional filter
IntersectWith() - joins two sets of independent filters

LogicalOrFilter Elements that pass at least one of 2 or more filters UnionWith() - joins two sets of independent filters
In the example below, two quick filters are combined using a logical filter to get all door FamilyInstance elements in the document.

Code Region 6-8: Using LogicalAndFilter to find all door instances


// Find all door instances in the project by finding all elements that both belong to the
// door category and are family instances.
ElementClassFilter familyInstanceFilter = new ElementClassFilter(typeof(FamilyInstance));

// Create a category filter for Doors


ElementCategoryFilter doorsCategoryfilter =
new ElementCategoryFilter(BuiltInCategory.OST_Doors);

// Create a logic And filter for all Door FamilyInstances


LogicalAndFilter doorInstancesFilter = new LogicalAndFilter(familyInstanceFilter,
doorsCategoryfilter);

// Apply the filter to the elements in the active document


FilteredElementCollector collector = new FilteredElementCollector(document);
IList<Element> doors = collector.WherePasses(doorInstancesFilter).ToElements();

Getting filtered elements or element ids


Once one or more filters have been applied to the FilteredElementCollector, the filtered set of elements can be retrieved in one of three
ways:

1. Obtain a collection of Elements or ElementIds.

o ToElements() - returns all elements that pass all applied filters

o ToElementIds() - returns ElementIds of all elements which pass all applied filters

2. Obtain the first Element or ElementId that matches the filter.

o FirstElement() - returns first element to pass all applied filters

o FirstElementId() - returns id of first element to pass all applied filters

3. Obtain an ElementId or Element iterator.

o GetElementIdIterator() - returns FilteredElementIdIterator to the element ids passing the filters

o GetElementIterator() - returns FilteredElementIterator to the elements passing the filters

o GetEnumerator() - returns an IEnumerator<Element> that iterates through collection of passing elements

You should only use one of the methods from these groups at a time; the collector will reset if you call another method to extract elements.
Thus, if you have previously obtained an iterator, it will be stopped and traverse no more elements if you call another method to extract
elements.

Which method is best depends on the application. If just one matching element is required, FirstElement() or FirstElementId() is the best
choice. If all the matching elements are required, use ToElements(). If a variable number are needed, use an iterator.

If the application will be deleting elements or making significant changes to elements in the filtered list, ToElementIds() or an element id
iterator are the best options. This is because deleting elements or making significant changes to an element can invalidate an element
handle. With element ids, the call to Document.GetElement() with the ElementId will always return a valid Element (or a null reference if the
element has been deleted).
Using the ToElements() method to get the filter results as a collection of elements allows for the use of foreach to examine each element in
the set, as is shown below:

Code Region 6-9: Using ToElements() to get filter results


1. // Use ElementClassFilter to find all loads in the document
2. // Using typeof(LoadBase) will yield all AreaLoad, LineLoad and PointLoad
3. ElementClassFilter filter = new ElementClassFilter(typeof(LoadBase));
4.
5. // Apply the filter to the elements in the active document
6. FilteredElementCollector collector = new FilteredElementCollector(document);
7. collector.WherePasses(filter);
8. ICollection<Element> allLoads = collector.ToElements();
9.
10. String prompt = "The loads in the current document are:\n";
11. foreach (Element loadElem in allLoads)
12. {
13. LoadBase load = loadElem as LoadBase;
14. prompt += load.GetType().Name + ": " +
15. load.Name + "\n";
16. }
17.
18. TaskDialog.Show("Revit", prompt);

When just one passing element is needed, use FirstElement():

Code Region 6-10: Get the first passing element


1. // Create a filter to find all columns
2. StructuralInstanceUsageFilter columnFilter =
3. new StructuralInstanceUsageFilter(StructuralInstanceUsage.Column);
4.
5. // Apply the filter to the elements in the active document
6. FilteredElementCollector collector = new FilteredElementCollector(document);
7. collector.WherePasses(columnFilter);
8.
9. // Get the first column from the filtered results
10. // Element will be a FamilyInstance
11. FamilyInstance column = collector.FirstElement() as FamilyInstance;

In some cases, FirstElement() is not sufficient. This next example shows how to use extension methods to get the first non-template 3D view
(which is useful for input to the ReferenceIntersector constructors).

Code Region 6-11: Get first passing element using extension methods
1. // Use filter to find a non-template 3D view
2. // This example does not use FirstElement() since first filterd view3D might be a template
3. FilteredElementCollector collector = new FilteredElementCollector(document);
4. Func<View3D, bool> isNotTemplate = v3 => !(v3.IsTemplate);
5.
6. // apply ElementClassFilter
7. collector.OfClass(typeof(View3D));
8.
9. // use extension methods to get first non-template View3D
10. View3D view3D = collector.Cast<View3D>().First<View3D>(isNotTemplate);
The following example demonstrates the use of the FirstElementId() method to get one passing element (a 3d view in this case) and the use
of ToElementIds() to get the filter results as a collection of element ids (in order to delete a set of elements in this case).

Code Region 6-12: Using Getting filter results as element ids


1. FilteredElementCollector collector = new FilteredElementCollector(document);
2.
3. // Use shortcut OfClass to get View elements
4. collector.OfClass(typeof(View3D));
5.
6. // Get the Id of the first view
7. ElementId viewId = collector.FirstElementId();
8.
9. // Test if the view is valid for element filtering
10. if (FilteredElementCollector.IsViewValidForElementIteration(document, viewId))
11. {
12. FilteredElementCollector viewCollector = new FilteredElementCollector(document, viewId);
13.
14. // Get all FamilyInstance items in the view
15. viewCollector.OfClass(typeof(FamilyInstance));
16. ICollection<ElementId> familyInstanceIds = viewCollector.ToElementIds();
17.
18. document.Delete(familyInstanceIds);
19. }

The GetElementIterator() method is used in the following example that iterates through the filtered elements to check the flow state of some
pipes.

Code Region 6-13: Getting the results as an element iterator


1. FilteredElementCollector collector = new FilteredElementCollector(document);
2.
3. // Apply a filter to get all pipes in the document
4. collector.OfClass(typeof(Autodesk.Revit.DB.Plumbing.Pipe));
5.
6. // Get results as an element iterator and look for a pipe with
7. // a specific flow state
8. FilteredElementIterator elemItr = collector.GetElementIterator();
9. elemItr.Reset();
10. while (elemItr.MoveNext())
11. {
12. Pipe pipe = elemItr.Current as Pipe;
13. if (pipe.FlowState == PipeFlowState.LaminarState)
14. {
15. TaskDialog.Show("Revit", "Model has at least one pipe with Laminar flow state.");
16. break;
17. }
18. }

Alternatively, the filter results can be returned as an element id iterator:

Code Region 6-14: Getting the results as an element id iterator


1. // Use a RoomFilter to find all room elements in the document.
2. RoomFilter filter = new RoomFilter();
3.
4. // Apply the filter to the elements in the active document
5. FilteredElementCollector collector = new FilteredElementCollector(document);
6. collector.WherePasses(filter);
7.
8. // Get results as ElementId iterator
9. FilteredElementIdIterator roomIdItr = collector.GetElementIdIterator();
10. roomIdItr.Reset();
11. while (roomIdItr.MoveNext())
12. {
13. ElementId roomId = roomIdItr.Current;
14. // Warn rooms smaller than 50 SF
15. Room room = document.GetElement(roomId) as Room;
16. if (room.Area < 50.0)
17. {
18. String prompt = "Room is too small: id = " + roomId.ToString();
19. TaskDialog.Show("Revit", prompt);
20. break;
21. }
22. }
In some cases, it may be useful to test a single element against a given filter, rather than getting all elements that pass the filter. There are
two overloads for ElementFilter.PassesFilter() that test a given Element, or ElementId, against the filter, returning true if the element passes
the filter.

LINQ Queries
In .NET, the FilteredElementCollector class supports the IEnumerable interface for Elements. You can use this class with LINQ queries and
operations to process lists of elements. Note that because the ElementFilters and the shortcut methods offered by this class process
elements in native code before their managed wrappers are generated, better performance will be obtained by using as many native filters
as possible on the collector before attempting to process the results using LINQ queries.

The following example uses an ElementClassFilter to get all FamilyInstance elements in the document, and then uses a LINQ query to narrow
down the results to those FamilyInstances with a specific name.

Code Region 6-15: Using LINQ query


// Use ElementClassFilter to find family instances whose name is 60" x 30" Student
ElementClassFilter filter = new ElementClassFilter(typeof(FamilyInstance));

// Apply the filter to the elements in the active document


FilteredElementCollector collector = new FilteredElementCollector(document);
collector.WherePasses(filter);

// Use Linq query to find family instances whose name is 60" x 30" Student
var query = from element in collector
where element.Name == "60\" x 30\" Student"
select element;

// Cast found elements to family instances,


// this cast to FamilyInstance is safe because ElementClassFilter for FamilyInstance was used
List<FamilyInstance> familyInstances = query.Cast<FamilyInstance>().ToList<FamilyInstance>();

Bounding Box filters


The BoundingBox filters:

BoundingBoxIsInsideFilter

BoundingBoxIntersectsFilter

BoundingBoxContainsPointFilter

help you find elements whose bounding boxes meet a certain criteria. You can check if each element’s bounding box is inside a given volume, intersects a
given volume, or contains a given point. You can also reverse this check to find elements which do not intersect a volume or contain a given point.

BoundingBox filters use Outline as their inputs. Outline is a class representing a right rectangular prism whose axes are aligned to the Revit world coordinate
system.

These filters work best for shapes whose actual geometry matches closely the geometry of its bounding box. Examples might include linear walls whose curve
aligns with the X or Y direction, rectangular rooms formed by such walls, floors or roofs aligned to such walls, or reasonably rectangular families. Otherwise,
there is the potential for false positives as the bounding box of the element may be much bigger than the actual geometry. (In these cases, you can use the
actual element’s geometry to determine if the element really meets the criteria).

Element Intersection Filters


The element filters:

• ElementIntersectsElementFilter
• ElementIntersectsSolidFilter

pass elements whose actual 3D geometry intersects the 3D geometry of the target object.

With ElementIntersectsElementFilter, the target object is another element. The intersection is determined with the same logic used by Revit to determine if an
interference exists during generation of an Interference Report. (This means that some combinations of elements will never pass this filter, such as concrete
members which are automatically joined at their intersections). Also, elements which have no solid geometry, such as Rebar, will not pass this filter.
With ElementIntersectsSolidFilter, the target object is any solid. This solid could have been obtained from an existing element, created from scratch using the
routines in GeometryCreationUtilities, or the result of a secondary operation such as a Boolean operation. Similar to the ElementIntersectsElementFilter, this
filter will not pass elements which lack solid geometry.

Both filters can be inverted to match elements outside the target object volume.

Both filters are slow filters, and thus are best combined with one or more quick filters such as class or category filters.

Code region: using ElementIntersectsSolidFilter to match elements which block disabled egress to doors
1. /// <summary>
2. /// Finds any Revit physical elements which interfere with the target
3. /// solid region surrounding a door.</summary>
4. /// <remarks>This routine is useful for detecting interferences which are
5. /// violations of the Americans with Disabilities Act or other local disabled
6. /// access codes.</remarks>
7. /// <param name="doorInstance">The door instance.</param>
8. /// <param name="doorAccessibilityRegion">The accessibility region calculated
9. /// to surround the approach of the door.
10. /// Because the geometric parameters of this region are code- and
11. /// door-specific, calculation of the geometry of the region is not
12. /// demonstrated in this example.</param>
13. /// <returns>A collection of interfering element ids.</returns>
14. private ICollection<ElementId> FindElementsInterferingWithDoor(FamilyInstance doorInstance, Solid doorAccessibilityRegion)
15. {
16. // Setup the filtered element collector for all document elements.
17. FilteredElementCollector interferingCollector =
18. new FilteredElementCollector(doorInstance.Document);
19.
20. // Only accept element instances
21. interferingCollector.WhereElementIsNotElementType();
22.
23. // Exclude intersections with the door itself or the host wall for the door.
24. List<ElementId> excludedElements = new List<ElementId>();
25. excludedElements.Add(doorInstance.Id);
26. excludedElements.Add(doorInstance.Host.Id);
27. ExclusionFilter exclusionFilter = new ExclusionFilter(excludedElements);
28. interferingCollector.WherePasses(exclusionFilter);
29.
30. // Set up a filter which matches elements whose solid geometry intersects
31. // with the accessibility region
32. ElementIntersectsSolidFilter intersectionFilter =
33. new ElementIntersectsSolidFilter(doorAccessibilityRegion);
34. interferingCollector.WherePasses(intersectionFilter);
35.
36. // Return all elements passing the collector
37. return interferingCollector.ToElementIds();
38. }
Selection
You can get the selected objects from the current active document using the UIDocument.Selection.Elements property. The selected objects
are in an ElementSet in Revit. From this Element set, all selected Elements are retrieved. The Selection object can also be used to change
the current selection programmatically.

Alternatively, the Selection.GetElementIds() method retrieves the same set of elements as the Selection.Elements property. The collection
returned by this method can be used directly with FilteredElementCollector to filter the selected elements.

Changing the Selection


To modify the Selection.Elements:

1. Create a new SelElementSet.

2. Put Elements in it.

3. Set the Selection.Elements to the new SelElementSet instance.

The following example illustrates how to change the selected Elements.

Code Region 7-1: Changing selected elements


1. private void ChangeSelection(Document document)
2. {
3. // Get selected elements form current document.
4. UIDocument uidoc = new UIDocument(document);
5. Autodesk.Revit.UI.Selection.SelElementSet collection = uidoc.Selection.Elements;
6.
7. // Display current number of selected elements
8. TaskDialog.Show("Revit","Number of selected elements: " + collection.Size.ToString());
9.
10. //Create a new SelElementSet
11. SelElementSet newSelectedElementSet = SelElementSet.Create();
12.
13. // Add wall into the created element set.
14. foreach (Autodesk.Revit.DB.Element elements in collection)
15. {
16. if (elements is Wall)
17. {
18. newSelectedElementSet.Add(elements);
19. }
20. }
21.
22. // Set the created element set as current select element set.
23. uidoc.Selection.Elements = newSelectedElementSet;
24.
25. // Give the user some information.
26. if (0 != newSelectedElementSet.Size)
27. {
28. TaskDialog.Show("Revit",uidoc.Selection.Elements.Size.ToString() +
29. " Walls are selected!");
30. }
31. else
32. {
33. TaskDialog.Show("Revit","No Walls have been selected!");
34. }
35. }

User Selection
The Selection class also has methods for allowing the user to select new objects, or even a point on screen. This allows the user to select one
or more Elements (or other objects, such as an edge or a face) using the cursor and then returns control to your application. These functions
do not automatically add the new selection to the active selection collection.

• The PickObject() method prompts the user to select an object in the Revit model.

• The PickObjects() method prompts the user to select multiple objects in the Revit model.

• The PickElementsByRectangle() method prompts the user to select multiple elements using a rectangle.

• The PickPoint() method prompts the user to pick a point in the active sketch plane.

• The PickBox() method invokes a general purpose two-click editor that lets the user to specify a rectangular area on the screen.

The type of object to be selected is specified when calling PickObject() or PickObjects. Types of objects that can be specified are: Element,
PointOnElement, Edge or Face.
The StatusbarTip property shows a message in the status bar when your application prompts the user to pick objects or elements. Each of
the Pick functions has an overload that has a String parameter in which a custom status message can be provided.

Code Region 7-2: Adding selected elements with PickObject() and PickElementsByRectangle()
1. UIDocument uidoc = new UIDocument(document);
2. Selection choices = uidoc.Selection;
3. // Pick one object from Revit.
4. Reference hasPickOne = choices.PickObject(ObjectType.Element);
5. if (hasPickOne != null)
6. {
7. TaskDialog.Show("Revit", "One element added to Selection.");
8. }
9.
10. int selectionCount = choices.Elements.Size;
11. // Choose objects from Revit.
12. IList<Element> hasPickSome = choices.PickElementsByRectangle("Select by rectangle");
13. if (hasPickSome.Count > 0)
14. {
15. int newSelectionCount = choices.Elements.Size;
16. string prompt = string.Format("{0} elements added to Selection.",
17. newSelectionCount - selectionCount);
18. TaskDialog.Show("Revit", prompt);
19. }

The PickPoint() method has 2 overloads with an ObjectSnapTypes parameter which is used to specify the type of snap types used for the
selection. More than one can be specified, as shown in the next example.

Code Region 7-3: Snap points


1. public void PickPoint(UIDocument uidoc)
2. {
3.
4. ObjectSnapTypes snapTypes = ObjectSnapTypes.Endpoints | ObjectSnapTypes.Intersections;
5. XYZ point = uidoc.Selection.PickPoint(snapTypes, "Select an end point or intersection");
6.
7. string strCoords = "Selected point is " + point.ToString();
8.
9. TaskDialog.Show("Revit", strCoords);
10. }

The PickBox() method takes a PickBoxStyle enumerator. The options are Crossing, the style used when selecting objects completely or
partially inside the box, Enclosing, the style used selecting objects that are completely enclosed by the box, and Directional, in which the
style of the box depends on the direction in which the box is being drawn. It uses the Crossing style if it is being drawn from right to left, or
the Enclosing style when drawn in the opposite direction.
PickBox() returns a PickedBox which contains the Min and Max points selected. The following example demonstrates the use of PickBox() in
Point Cloud selection.

Code Region: PickBox


1. public void PromptForPointCloudSelection(UIDocument uiDoc, PointCloudInstance pcInstance)
2. {
3. Application app = uiDoc.Application.Application;
4. Selection currentSel = uiDoc.Selection;
5.
6. PickedBox pickedBox = currentSel.PickBox(PickBoxStyle.Enclosing, "Select region of cloud for highlighting");
7.
8. XYZ min = pickedBox.Min;
9. XYZ max = pickedBox.Max;
10.
11. //Transform points into filter
12. View view = uiDoc.ActiveView;
13. XYZ right = view.RightDirection;
14. XYZ up = view.UpDirection;
15.
16. List<Plane> planes = new List<Plane>();
17.
18. // X boundaries
19. bool directionCorrect = IsPointAbovePlane(right, min, max);
20. planes.Add(app.Create.NewPlane(right, directionCorrect ? min : max));
21. planes.Add(app.Create.NewPlane(-right, directionCorrect ? max : min));
22.
23. // Y boundaries
24. directionCorrect = IsPointAbovePlane(up, min, max);
25. planes.Add(app.Create.NewPlane(up, directionCorrect ? min : max));
26. planes.Add(app.Create.NewPlane(-up, directionCorrect ? max : min));
27.
28. // Create filter
29. PointCloudFilter filter = PointCloudFilterFactory.CreateMultiPlaneFilter(planes);
30. Transaction t = new Transaction(uiDoc.Document, "Highlight");
31. t.Start();
32. pcInstance.SetSelectionFilter(filter);
33. pcInstance.FilterAction = SelectionFilterAction.Highlight;
34. t.Commit();
35. uiDoc.RefreshActiveView();
36. }
37.
38. private static bool IsPointAbovePlane(XYZ normal, XYZ planePoint, XYZ point)
39. {
40. XYZ difference = point - planePoint;
41. difference = difference.Normalize();
42. double dotProduct = difference.DotProduct(normal);
43. return dotProduct > 0;

Filtered User Selection


PickObject(), PickObjects() and PickElementsByRectangle() all have overloads that take an ISelectionFilter as a parameter. ISelectionFilter is
an interface that can be implemented to filter objects during a selection operation. It has two methods that can be overridden:
AllowElement() which is used to specify if an element is allowed to be selected, and AllowReference() which is used to specify if a reference
to a piece of geometry is allowed to be selected.
The following example illustrates how to use an ISelectionFilter interface to limit the user's selection to elements in the Mass category. It
does not allow any references to geometry to be selected.

Code Region 7-4: Using ISelectionFilter to limit element selection


public static IList<Element> GetManyRefByRectangle(UIDocument doc)
{
ReferenceArray ra = new ReferenceArray();
ISelectionFilter selFilter = new MassSelectionFilter();
IList<Element> eList = doc.Selection.PickElementsByRectangle(selFilter,
"Select multiple faces") as IList<Element>;
return eList;
}

public class MassSelectionFilter : ISelectionFilter


{
public bool AllowElement(Element element)
{
if (element.Category.Name == "Mass")
{
return true;
}
return false;
}

public bool AllowReference(Reference refer, XYZ point)


{
return false;
}
}

The next example demonstrates the use of ISelectionFilter to allow only planar faces to be selected.

Code Region 7-5: Using ISelectionFilter to limit geometry selection


public void SelectPlanarFaces(Autodesk.Revit.DB.Document document)
{
UIDocument uidoc = new UIDocument(document);
ISelectionFilter selFilter = new PlanarFacesSelectionFilter(document);
IList<Reference> faces = uidoc.Selection.PickObjects(ObjectType.Face,
selFilter, "Select multiple planar faces");
}

public class PlanarFacesSelectionFilter : ISelectionFilter


{
Document doc = null;
public PlanarFacesSelectionFilter(Document document)
{
doc = document;
}

public bool AllowElement(Element element)


{
return true;
}

public bool AllowReference(Reference refer, XYZ point)


{
if (doc.GetElement(refer).GetGeometryObjectFromReference(refer) is PlanarFace)
{
// Only return true for planar faces. Non-planar faces will not be selectable
return true;
}
return false;
}
}

For more information about retrieving Elements from selected Elements, see Walkthrough: Retrieve Selected Elements in the Getting Started
section.
Parameters
Revit provides a general mechanism for giving each element a set of parameters that you can edit. In the Revit UI, parameters are visible in
the Element Properties dialog box. This chapter describes how to get and use built-in parameters using the Revit Platform API. For more
information about user-defined shared parameters, see Shared Parameters.

In the Revit Platform API, Parameters are managed in the Element class. You can access Parameters in these ways:

• By iterating through the Element.Parameters collection of all parameters for an Element (for an example, see the sample code in
Walkthrough Get Selected Element Parameters).

• By accessing the parameter directly through the overloaded Element.Parameter property. If the Parameter doesn't exist, the property
returns null.

• By accessing a parameter by name via the Element.ParametersMap collection.

You can retrieve the Parameter object from an Element if you know the name string, built-in ID, definition, or GUID. The Parameter[String]
property overload gets a parameter based on its localized name, so your code should handle different languages if it's going to look up
parameters by name and needs to run in more than one locale.

The Parameter[GUID] property overload gets a shared parameter based on its Global Unique ID (GUID), which is assigned to the shared
parameter when it's created.

Walkthrough: Get Selected Element Parameters


The Element Parameters are retrieved by iterating through the Element ParameterSet. The following code sample illustrates how to retrieve
the Parameter from a selected element.

NoteThis example uses some Parameter members, such as AsValueString and StorageType, which are covered later in this chapter.
Code Region 8-1: Getting selected element parameters
void GetElementParameterInformation(Document document, Element element)
{
// Format the prompt information string
String prompt = "Show parameters in selected Element:";

StringBuilder st = new StringBuilder();


// iterate element's parameters
foreach (Parameter para in element.Parameters)
{
st.AppendLine(GetParameterInformation(para, document));
}

// Give the user some information


MessageBox.Show(prompt, "Revit", MessageBoxButtons.OK);
}

String GetParameterInformation(Parameter para, Document document)


{
string defName = para.Definition.Name + @"\t";
// Use different method to get parameter data according to the storage type
switch (para.StorageType)
{
case StorageType.Double:
//covert the number into Metric
defName += " : " + para.AsValueString();
break;
case StorageType.ElementId:
//find out the name of the element
ElementId id = para.AsElementId();
if (id.Value >= 0)
{
defName += " : " + document.GetElement(ref id).Name;
}
else
{
defName += " : " + id.Value.ToString();
}
break;
case StorageType.Integer:
if (ParameterType.YesNo == para.Definition.ParameterType)
{
if (para.AsInteger() == 0)
{
defName += " : " + "False";
}
else
{
defName += " : " + "True";
}
}
else
{
defName += " : " + para.AsInteger().ToString();
}
break;
case StorageType.String:
defName += " : " + para.AsString();
break;
default:
defName = "Unexposed parameter.";
break;
}

return defName;
}
Figure 26: Get wall parameters result

NoteIn Revit, some parameters have values in the drop-down list in the Element Properties dialog box. You can get the numeric values
corresponding to the enumerated type for the Parameter using the Revit Platform API, but you cannot get the string representation for the
values using the Parameter.AsValueString() method.

Definition
The Definition object describes the data type, name, and other Parameter details. There are two kinds of definition objects derived from this
object.

• InternalDefinition represents all kinds of definitions existing entirely in the Revit database.

• ExternalDefinition represents definitions stored on disk in a shared parameter file.

You should write the code to use the Definition base class so that the code is applicable to both internal and external parameter Definitions.
The following code sample shows how to find a specific parameter using the definition type.

Code Region 8-2: Finding a parameter based on definition type


1. //Find parameter using the Parameter's definition type.
2. public Parameter FindParameter(Element element)
3. {
4. Parameter foundParameter = null;
5. // This will find the first parameter that measures length
6. foreach (Parameter parameter in element.Parameters)
7. {
8. if (parameter.Definition.ParameterType == ParameterType.Length)
9. {
10. foundParameter = parameter;
11. break;
12. }
13. }
14. return foundParameter;
15. }

ParameterType

This property returns parameter data type, which affects how the parameter is displayed in the Revit UI. The ParameterType enumeration
members are:

Member name Description

Number The parameter data should be interpreted as a real number, possibly including decimal points.

Moment The data value will be represented as a moment.

AreaForce The data value will be represented as an area force.

LinearForce The data value will be represented as a linear force.

Force The data value will be represented as a force.


YesNo A boolean value that will be represented as Yes or No.

Material The value of this property is considered to be a material.

URL A text string that represents a web address.

Angle The parameter data represents an angle. The internal representation will be in radians. The user visible representation will be in
the units that the user has chosen.

Volume The parameter data represents a volume. The internal representation will be in decimal cubic feet. The user visible
representation will be in the units that the user has chosen.

Area The parameter data represents an area. The internal representation will be in decimal square feet. The user visible
representation will be in the units that the user has chosen.

Integer The parameter data should be interpreted as a whole number, positive or negative.

Invalid The parameter type is invalid. This value should not be used.

Length The parameter data represents a length. The internal representation will be in decimal feet. The user visible representation will
be in the units system that the user has chosen.

Text The parameter data should be interpreted as a string of text.

For more details about ParameterType.Material, see Material.

ParameterGroup

The Definition class ParameterGroup property returns the parameter definition group ID. The BuiltInParameterGroup is an enumerated type
listing all built-in parameter groups supported by Revit. Parameter groups are used to sort parameters in the Element Properties dialog box.

VariesAcrossGroups

This property, which is specific to the InternalDefinition child class, and the corresponding SetAllowVaryBetweenGroups() method determine
whether the values of this parameter can vary across the related members of group instances. If False, the values will be consistent across
the related members in group instances. This can only be set for non-built-in parameters.

BuiltInParameter
The Revit Platform API has a large number of built-in parameters, defined in the Autodesk.Revit.Parameters.BuiltInParameter enumeration
(see the RevitAPI Help.chm file for the definition of this enumeration). This enumeration has generated documentation visible from Visual
Studio intellisense as shown below. The documentation for each id includes the parameter name, as found in the Element Properties dialog in
the English version of Autodesk Revit. Note that multiple distinct parameter ids may map to the same English name; in those cases you
must examine the parameters associated with a specific element to determine which parameter id to use.

The parameter ID is used to retrieve the specific parameter from an element, if it exists, using the Element.Parameter property. However,
not all parameters can be retrieved using the ID. For example, family parameters are not exposed in the Revit Platform API, therefore, you
cannot get them using the built-in parameter ID.

The following code sample shows how to get the specific parameter using the BuiltInParameter Id:

Code Region 8-3: Getting a parameter based on BuiltInParameter


1. public Parameter FindWithBuiltinParameterID(Wall wall)
2. {
3. // Use the WALL_BASE_OFFSET paramametId
4. // to get the base offset parameter of the wall.
5. BuiltInParameter paraIndex = BuiltInParameter.WALL_BASE_OFFSET;
6. Parameter parameter = wall.get_Parameter(paraIndex);
7.
8. return parameter;
9. }

Note With the Parameter overload, you can use an Enumerated type BuiltInParameter as the method parameter. For example, use
BuiltInParameter.GENERIC_WIDTH.
If you do not know the exact BuiltInParameter ID, get the parameter by iterating the ParameterSet collection. Another approach for testing
or identification purposes is to test each BuiltInParameter using the get_Parameter() method. When you use this method, it is possible that
the ParameterSet collection may not contain all parameters returned from the get_Parameter() method, though this is infrequent.

StorageType
StorageType describes the type of parameter values stored internally.

Based on the property value, use the corresponding get and set methods to retrieve and set the parameter data value.

The StorageType is an enumerated type that lists all internal parameter data storage types supported by Revit:

Table 16: Storage Type

Member Name Description

String Internal data is stored as a string of characters.

ElementId Data type represents an element and is stored as an Element ID.

Double Data is stored internally as an 8-byte floating point number.

Integer Internal data is stored as a signed 32-bit integer.

None None represents an invalid storage type. For internal use only.

In most cases, the ElementId value is a positive number. However, it can be a negative number. When the ElementId value is negative, it
does not represent an Element but has another meaning. For example, the storage type parameter for a beam's Vertical Projection is
ElementId. When the parameter value is Level 1 or Level 2, the ElementId value is positive and corresponds to the ElementId of that level.
However, when the parameter value is set to Auto-detect, Center of Beam or Top of Beam, the ElementId value is negative.

Figure 27: Storage type sample

The following code sample shows how to check whether a parameter's value can be set to a double value, based on its StorageType:

Code Region 8-4: Checking a parameter's StorageType


public bool SetParameter(Parameter parameter, double value)
{
bool result = false;
//if the parameter is readonly, you can't change the value of it
if (null != parameter && !parameter.IsReadOnly)
{
StorageType parameterType = parameter.StorageType;
if (StorageType.Double != parameterType)
{
throw new Exception("The storagetypes of value and parameter are different!");
}

//If successful, the result is true


result = parameter.Set(value);
}

return result;
}
The Set() method return value indicates that the Parameter value was changed. The Set() method returns true if the Parameter value was
changed, otherwise it returns false.

Not all Parameters are writable. An Exception is thrown if the Parameter is read-only.

AsValueString() and SetValueString()


AsValueString() and SetValueString() are Parameter class methods. The two methods are only applied to value type parameters, which are
double or integer parameters representing a measured quantity.

Use the AsValueString() method to get the parameter value as a string with the unit of measure. For example, the Base Offset value, a wall
parameter, is a Double value. Usually the value is shown as a string like -20'0" in the Element Properties dialog box:

Figure 28: AsValueString and SetValueString sample

Using the AsValueString() method, you get the -20'0" string value directly. Otherwise you get a double value like -20 without the units of
measure if you use the AsDouble() method.

Use the SetValueString() method to change the value of a value type parameter instead of using the Set() method. The following code
sample illustrates how to change the parameter value using the SetValueString() method:

Code Region 8-5: Using Parameter.SetValueString()


public bool SetWithValueString(Parameter foundParameter)
{
bool result = false;
if (!foundParameter.IsReadOnly)
{
//If successful, the result is true
result = foundParameter.SetValueString("-22\'3\"");
}
return result;
}

Parameter Relationships
There are relationships between Parameters where the value of one Parameter can affect:

• whether another Parameter can be set, or is read-only

• what parameters are valid for the element

• the computed value of another parameter

Additionally, some parameters are always read-only.


Some parameters are computed in Revit, such as wall Length and Area parameter. These parameters are always read-only because they
depend on the element's internal state.

Figure 29: Wall computed parameters

In this code sample, the Sill Height parameter for an opening is adjusted, which results in the Head Height parameter being re-computed:

Code Region 8-6: Parameter relationship example


// opening should be an opening such as a window or a door
public void ShowParameterRelationship(FamilyInstance opening)
{
// get the original Sill Height and Head Height parameters for the opening
Parameter sillPara = opening.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM);
Parameter headPara = opening.get_Parameter(BuiltInParameter.INSTANCE_HEAD_HEIGHT_PARAM);
double sillHeight = sillPara.AsDouble();
double origHeadHeight = headPara.AsDouble();

// Change the Sill Height only and notice that Head Height is recalculated
sillPara.Set(sillHeight + 2.0);
double newHeadHeight = headPara.AsDouble();
MessageBox.Show("Old head height: " + origHeadHeight + "; new head height: "
+ newHeadHeight);
}

Adding Parameters to Elements


In the Revit Platform API, you can use all of the defined parameters and you can add custom parameters that you define using the Revit
user interface and the Revit Platform API.

For more details, refer to Shared Parameter.

Collections
Most Revit Platform API properties and methods use .NET Framework collection classes when providing access to a group of related items.

The IEnumerable and IEnumerator interfaces implemented in Revit collection types are defined in the System.Collection namespace.

Interface
The following sections discuss interface-related collection types.

IEnumerable

The IEnumerable interface is in the System.Collections namespace. It exposes the enumerator, which supports a simple iteration over a non-
generic collection. The GetEnumerator() method gets an enumerator that implements this interface. The returned IEnumerator object is
iterated throughout the collection. The GetEnumerator() method is used implicitly by foreach loops in C#.

IEnumerator

The IEnumerator interface is in the System.Collections namespace. It supports a simple iteration over a non-generic collection. IEnumerator
is the base interface for all non-generic enumerators. The foreach statement in C# hides the enumerator's complexity.

NoteUsing foreach is recommended instead of directly manipulating the enumerator.

Enumerators are used to read the collection data, but they cannot be used to modify the underlying collection. Use IEnumerator as follows:
• Initially, the enumerator is positioned in front of the first element in the collection. However, it is a good idea to always call Reset()
when you first obtain the enumerator.

o The Reset() method moves the enumerator back to the original position. At this position, calling the Current property throws
an exception.

o Call the MoveNext() method to advance the enumerator to the collection's first element before reading the current iterator
value.

• The Current property returns the same object until either the MoveNext() method or Reset() method is called. The MoveNext()
method sets the current iterator to the next element.

• If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext
returns false.

o When the enumerator is in this position, subsequent calls to the MoveNext also return false.

o If the last call to the MoveNext returns false, calling the Current property throws an exception.

o To set the current iterator to the first element in the collection again, call the Reset() method followed by MoveNext().

• An enumerator remains valid as long as the collection remains unchanged.

o If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is invalidated and
the next call to the MoveNext() or the Reset() method throws an InvalidOperationException.

o If the collection is modified between the MoveNext and the current iterator, the Current property returns to the specified
element, even if the enumerator is already invalidated.
NoteAll calls to the Reset() method must result in the same state for the enumerator. The preferred implementation is to move the
enumerator to the collection beginning, before the first element. This invalidates the enumerator if the collection is modified after the
enumerator was created, which is consistent with the MoveNext() and the Current properties.

Collections and Iterators


In the Revit Platform API, Collections and Iterators are generic and type safe. For example, ElementSet always contains Element and can be
used as follows:

Code Region 9-1: Using ElementSet


1. UIDocument uidoc = new UIDocument(document);
2. ElementSet elems = uidoc.Selection.Elements;
3.
4. string info = "Selected elements:\n";
5. foreach (Autodesk.Revit.DB.Element elem in elems)
6. {
7. info += elem.Name + "\n";
8. }
9.
10. TaskDialog.Show("Revit",info);
11.
12. info = "Levels in document:\n";
13.
14. FilteredElementCollector collector = new FilteredElementCollector(document);
15. ICollection<Element> collection = collector.OfClass(typeof(BoundaryConditions)).ToElements();
16. foreach (Element elem in collection)
17. {
18. // you need not check null for elem
19. info += elem.Name + "\n";
20. }
21.
22. TaskDialog.Show("Revit",info);

All collections implement the IEnumerable interface and all relevant iterators implement the IEnumerator interface. As a result, all methods
and properties are implemented in the Revit Platform API and can play a role in the relevant collections.
Implementing all of the collections is similar. The following example uses ElementSet and ModelCurveArray to demonstrate how to use the
main collection properties:

Code Region 9-2: Using collections


1. UIDocument uidoc = new UIDocument(document);
2. SelElementSet selection = uidoc.Selection.Elements;
3. // Store the ModelLine references
4. ModelCurveArray lineArray = new ModelCurveArray();
5.
6. // … Store operation
7. Autodesk.Revit.DB.ElementId id = new Autodesk.Revit.DB.ElementId(131943); //assume 131943 is a model line element id
8. lineArray.Append(document.GetElement(id) as ModelLine);
9.
10. // use Size property of Array
11. TaskDialog.Show("Revit","Before Insert: " + lineArray.Size + " in lineArray.");
12.
13. // use IsEmpty property of Array
14. if (!lineArray.IsEmpty)
15. {
16. // use Item(int) property of Array
17. ModelCurve modelCurve = lineArray.get_Item(0) as ModelCurve;
18.
19. // erase the specific element from the set of elements
20. selection.Erase(modelCurve);
21.
22. // create a new model line and insert to array of model line
23. SketchPlane sketchPlane = modelCurve.SketchPlane;
24.
25. XYZ startPoint = new XYZ(0, 0, 0); // the start point of the line
26. XYZ endPoint = new XYZ(10, 10, 0); // the end point of the line
27. // create geometry line
28. Line geometryLine = Line.CreateBound(startPoint, endPoint);
29.
30. // create the ModelLine
31. ModelLine line =
32. document.Create.NewModelCurve(geometryLine, sketchPlane) as ModelLine;
33.
34. lineArray.Insert(line, lineArray.Size - 1);
35. }
36.
37. TaskDialog.Show("Revit","After Insert: " + lineArray.Size + " in lineArray.");
38.
39. // use the Clear() method to remove all elements in lineArray
40. lineArray.Clear();
41.
42. TaskDialog.Show("Revit

Editing Elements
In Revit, you can move, copy, rotate, align, delete, mirror, group, and array one element or a set of elements with the Revit Platform API.
Using the editing functionality in the API is similar to the commands in the Revit UI.

Moving Elements
The ElementTransformUtils class provides two static methods to move one or more elements from one place to another.

Table 19: Move Methods

Member Description

MoveElement( Document, ElementId, XYZ) Move an element in the document by a specified vector.

MoveElements(Document, ICollection<ElementId>, XYZ) Move several elements by a set of IDs in the document by a specified vector.
Note When you use the MoveElement() or MoveElements() methods, the following rules apply.

• The methods cannot move a level-based element up or down from the level. When the element is level-based, you cannot change the
Z coordinate value. However, you can place the element at any location in the same level. As well, some level based elements have
an offset instance parameter you can use to move them in the Z direction.
For example, if you create a new column at the original location (0, 0, 0) in Level1, and then move it to the new location (10, 20,
30), the column is placed at the location (10, 20, 0) instead of (10, 20, 30).
Code Region 10-1: Using MoveElement()
1. public void MoveColumn(Autodesk.Revit.DB.Document document, FamilyInstance column)
2. {
3. // get the column current location
4. LocationPoint columnLocation = column.Location as LocationPoint;
5.
6. XYZ oldPlace = columnLocation.Point;
7.
8. // Move the column to new location.
9. XYZ newPlace = new XYZ(10, 20, 30);
10. ElementTransformUtils.MoveElement(document, column.Id, newPlace);
11.
12. // now get the column's new location
13. columnLocation = column.Location as LocationPoint;
14. XYZ newActual = columnLocation.Point;
15.
16. string info = "Original Z location: " + oldPlace.Z +
17. "\nNew Z location: " + newActual.Z;
18.
19. TaskDialog.Show("Revit",info);
20. }

• When you move one or more elements, associated elements are moved. For example, if a wall with windows is moved, the windows
are also moved.

• Pinned elements cannot be moved.

Another way to move an element in Revit is to use Location and its derivative objects. In the Revit Platform API, the Location object provides
the ability to translate and rotate elements. More location information and control is available using the Location object derivatives such as
LocationPoint or LocationCurve. If the Location element is downcast to a LocationCurve object or a LocationPoint object, move the curve or
the point to a new place directly.

Code Region 10-2: Moving using Location


1. bool MoveUsingLocationCurve(Autodesk.Revit.ApplicationServices.Application application, Wall wall)
2. {
3. LocationCurve wallLine = wall.Location as LocationCurve;
4. XYZ translationVec = new XYZ(10, 20, 0);
5. return (wallLine.Move(translationVec));
6. }

When you move the element, note that the vector (10, 20, 0) is not the destination but the offset. The following picture illustrates the wall
position before and after moving.

Figure 30: Move a wall using the LocationCurve

In addition, you can use the LocationCurve Curve property or the LocationPoint Point property to move one element in Revit.

Use the Curve property to move a curve-driven element to any specified position. Many elements are curve-driven, such as walls, beams,
and braces. Also use the property to resize the length of the element.
Code Region 10-3: Moving using Curve
1. void MoveUsingCurveParam(Autodesk.Revit.ApplicationServices.Application application, Wall wall)
2. {
3. LocationCurve wallLine = wall.Location as LocationCurve;
4. XYZ p1 = XYZ.Zero;
5. XYZ p2 = new XYZ(10, 20, 0);
6. Line newWallLine = Line.CreateBound(p1, p2);
7.
8. // Change the wall line to a new line.
9. wallLine.Curve = newWallLine;
10. }

You can also get or set a curve-based element's join properties with the LocationCurve.JoinType property.

Use the LocationPoint Point property to set the element's physical location.

Code Region 10-4: Moving using Point


1. void LocationMove(FamilyInstance column)
2. {
3. LocationPoint columnPoint = column.Location as LocationPoint;
4. if (null != columnPoint)
5. {
6. XYZ newLocation = new XYZ(10, 20, 0);
7. // Move the column to the new location
8. columnPoint.Point = newLocation;
9. }

Copying Elements
The ElementTransformUtils class provides several static methods to copy one or more elements from one place to another, either within the same document or
view, or to a different document or view.

Table: Copy Methods

Member Description
Copies an element and places the copy at a location indicated by a given
CopyElement( Document, ElementId, XYZ)
transformation..

Copies a set of elements and places the copies at a location indicated by a


CopyElements(Document, ICollection<ElementId>, XYZ) given translation.

CopyElements(Document, ICollection<ElementId>, Document, Transform,


Copies a set of elements from source document to destination document.
CopyPasteOptions)

CopyElements(View, ICollection<ElementId>, View, Transform,


Copies a set of elements from source view to destination view.
CopyPasteOptions)

All of the methods return a collection of ElementIds of the newly created elements, including CopyElement(). The collection includes any elements created due
to dependencies.

The method for copying from one document to another can be used for copying non-view specific elements only. Copies are placed at their respective original
location or locations specified by the optional transformation.

View-specific elements should be copied using the method that copies from one view to another. That method can be used for both view-specific and model
elements however, drafting views cannot be used as a destination for model elements. The pasted elements are repositioned to ensure proper placement in
the destination view. For example, the elevation is changed when copying from one level to another. An additional transformation within the destination view
can be performed by providing the optional Transform argument. This additional transformation must be within the plane of the destination view.

When copying from one view to another, both the source and destination views must be 2D graphics views capable of drawing details and view-specific
elements, such as floor and ceiling plans, elevations, sections, or drafting views. The ElementTransformUtils.GetTransformFromViewToView() method will
return the transformation that is applied to elements when copying from a source view to a destination view.
When copying between views or between documents, an optional CopyPasteOptions parameter may be set to override default copy/paste settings. By default,
in the event of duplicate type names during a paste operation, Revit displays a modal dialog with options to either copy types with unique names only, or to
cancel the operation. CopyPasteOptions can be used to specify a custom handler, using the IDuplicateTypeNamesHandler interface, to handle duplicate type
names.

See the Duplicate Views sample in the Revit SDK for a detailed example of copying between documents and between views.

Rotating elements
The ElementTransformUtils class provides two static methods to rotate one or several elements in the project.

Table 20: Rotate Methods

Member Description

RotateElement(Document, ElementId, Line, double) Rotate an element in the document by a specified number of radians around a given axis.

RotateElements(Document, ICollection<ElementId>, Line, Rotate several elements by IDs in the project by a specified number of radians around a
double) given axis.

In these methods, the angle of rotation is in radians. The positive radian means rotating counterclockwise around the specified axis, while
the negative radian means clockwise, as the following pictures illustrates.

Figure 31: Counterclockwise rotation


Figure 32: Clockwise rotation

Note that pinned elements cannot be rotated.

Code Region 10-5: Using RotateElement()


1. public void RotateColumn(Autodesk.Revit.DB.Document document, Autodesk.Revit.DB.Element element)
2. {
3. XYZ point1 = new XYZ(10, 20, 0);
4. XYZ point2 = new XYZ(10, 20, 30);
5. // The axis should be a bound line.
6. Line axis = Line.CreateBound(point1, point2);
7. ElementTransformUtils.RotateElement(document, element.Id, axis, Math.PI / 3.0);
8. }

If the element Location can be downcast to a LocationCurve or a LocationPoint, you can rotate the curve or the point directly.

Code Region 10-6: Rotating based on location curve


1. bool LocationRotate(Autodesk.Revit.ApplicationServices.Application application, Autodesk.Revit.DB.Element element)
2. {
3. bool rotated = false;
4. // Rotate the element via its location curve.
5. LocationCurve curve = element.Location as LocationCurve;
6. if (null != curve)
7. {
8. Curve line = curve.Curve;
9. XYZ aa = line.GetEndPoint(0);
10. XYZ cc = new XYZ(aa.X, aa.Y, aa.Z + 10);
11. Line axis = Line.CreateBound(aa, cc);
12. rotated = curve.Rotate(axis, Math.PI / 2.0);
13. }
14.
15. return rotated;
16. }

Code Region 10-7: Rotating based on location point


1. bool LocationRotate(Autodesk.Revit.ApplicationServices.Application application, Autodesk.Revit.Element element)
2. {
3. bool rotated = false;
4. LocationPoint location = element.Location as LocationPoint;
5.
6. if (null != location)
7. {
8. XYZ aa = location.Point;
9. XYZ cc = new XYZ(aa.X, aa.Y, aa.Z + 10);
10. Line axis = Line.CreateBound(aa, cc);
11. rotated = location.Rotate(axis, Math.PI / 2.0);
12. }
13.
14. return rotated;
Aligning Elements
The ItemFactoryBase.NewAlignment() method can create a new locked alignment between two references. These two references must be one of the following
combinations:

• 2 planar faces
• 2 lines
• line and point
• line and reference plane
• 2 arcs
• 2 cylindrical faces

These references must be already geometrically aligned as this function will not force them to become aligned. If the alignment can be created a new
Dimension object is returned representing the locked alignment. Otherwise an exception will be thrown.

The NewAlignment() method also requires a view which will determine the orientation of the alignment.

See the CreateTruss example in the FamilyCreation folder included with the SDK Samples. It has several examples of the use of NewAlignment(), such as locking
the bottom chord of a new truss to a bottom reference plane.

Mirroring Elements
The ElementTransformUtils class provides two static methods to mirror one or more elements in the project.

Table 21: Mirror Methods

Member Description

MirrorElement(Document, ElementId, Plane) Mirror one element about a geometric plane.

MirrorElements(Document, ICollection<ElementId>, Plane) Mirror several elements about a geometric plane.

After performing the mirror operation, you can access the new elements from the Selection ElementSet.

ElementTransformUtils.CanMirrorElement() and ElementTransformUtils.CanMirrorElements() can be used to determine if one or more


elements can be mirrored prior to attempting to mirror an element.

The following code illustrates how to mirror a wall using a plane calculated based on a side face of the wall.

Code Region 10-8: Mirroring a wall


1. public void MirrorWall(Autodesk.Revit.DB.Document document, Wall wall)
2. {
3. Reference reference = HostObjectUtils.GetSideFaces(wall, ShellLayerType.Exterior).First();
4.
5. // get one of the wall's major side faces
6. Face face = wall.GetGeometryObjectFromReference(reference) as Face;
7.
8. UV bboxMin = face.GetBoundingBox().Min;
9. // create a plane based on this side face with an offset of 10 in the X & Y directions
10.
11. Plane plane = new Plane(face.ComputeNormal(bboxMin),
12. face.Evaluate(bboxMin).Add(new XYZ(10, 10, 0)));
13.
14. ElementTransformUtils.MirrorElement(document, wall.Id, plane);
15. }

Every FamilyInstance has a Mirrored property. It indicates whether a FamilyInstance (for example a column) is mirrored.
Grouping Elements
The Revit Platform API uses the Creation.Document.NewGroup() method to select an element or multiple elements or groups and then
combines them. With each instance of a group that you place, there is associatively among them. For example, you create a group with a
bed, walls, and window and then place multiple instances of the group in your project. If you modify a wall in one group, it changes for all
instances of that group. This makes modifying your building model much easier because you can change several instances of a group in one
operation.

Code Region 10-9: Creating a Group


1. Group group = null;
2. UIDocument uidoc = new UIDocument(document);
3. ElementSet selection = uidoc.Selection.Elements;
4. if (selection.Size > 0)
5. {
6. // Group all selected elements
7. group = document.Create.NewGroup(uidoc.Selection.GetElementIds());
8. }

Initially, the group has a generic name, such as Group 1. It can be modified by changing the name of the group type as follows:

Code Region 10-10: Naming a Group


1. // Change the default group name to a new name "MyGroup"
2. group.GroupType.Name = "MyGroup";

There are three types of groups in Revit; Model Group, Detail Group, and Attached Detail Group. All are created using the NewGroup()
method. The created Group's type depends on the Elements passed.

• If no detail Element is passed, a Model Group is created.

• If all Elements are detail elements, then a Detail Group is created.

• If both types of Elements are included, a Model Group that contains an Attached Detail Group is created and returned.
Note When elements are grouped, they can be deleted from the project.

• When a model element in a model group is deleted, it is still visible when the mouse cursor hovers over or clicks the group, even if
the application returns Succeeded to the UI. In fact, the model element is deleted and you cannot select or access that element.

• When the last member of a group instance is deleted, excluded, or removed from the project, the model group instance is deleted.

When elements are grouped, they cannot be moved or rotated. If you perform these operations on the grouped elements, nothing happens
to the elements, though the Move() or Rotate() method returns true.

You cannot group dimensions and tags without grouping the elements they reference. If you do, the API call will fail.

You can group dimensions and tags that refer to model elements in a model group. The dimensions and tags are added to an attached detail
group. The attached detail group cannot be moved, copied, rotated, arrayed, or mirrored without doing the same to the parent group.

Creating Arrays of Elements


The Revit Platform API provides two classes, LinearArray and RadialArray to array one or more elements in the project. These classes
provide static methods to create a linear or radial array of one or more selected components. Linear arrays represent an array created along
a line from one point, while radial arrays represent an array created along an arc.

As an example of using an array, you can select a door and windows located in the same wall and then create multiple instances of the door,
wall, and window configuration.

Both LinearArray and RadialArray also provide methods to array one or several elements without being grouped and associated. Although
similar to the Create() methods for arraying elements, each resulting element is independent of the others, and can be manipulated without
affecting the other elements. See the tables below for more information on the methods available to create linear or radial arrays.
Table 22: LinearArray Methods

Member Description

Create(Document, View, ElementId, int, XYZ, ArrayAnchorMember) Array one element in the project by a specified number.

Create(Document, View, ICollection<ElementId>, int, XYZ, ArrayAnchorMember) Array a set of elements in the project by a specified number.

ArrayElementWithoutAssociation(Document, View, ElementId, int, XYZ, Array one element in the project by a specified number. The resulting
ArrayAnchorMember) elements are not associated with a linear array.

ArrayElementsWithoutAssociation(Document, View, ICollection<ElementId>, int, Array a set of elements in the project by a specified number. The resulting
XYZ, ArrayAnchorMember) elements are not associated with a linear array.

Table 23: RadialArray Methods

Member Description

Create(Document, View, ElementId, int, Line, double, ArrayAnchorMember) Array one element in the project based on an input rotation axis.

Create(Document, View, ICollection<ElementId>, int, Line, double, Array a set of elements in the project based on an input rotation axis.
ArrayAnchorMember)

ArrayElementWithoutAssociation(Document, View, ElementId, int, Line, double, Array one element in the project based on an input rotation axis.. The
ArrayAnchorMember) resulting elements are not associated with a linear array.

ArrayElementsWithoutAssociation(Document, View, ICollection<ElementId>, int, Array a set of elements in the project based on an input rotation axis..
Line, double, ArrayAnchorMember) The resulting elements are not associated with a linear array.

The methods for arraying elements are useful if you need to create several instances of a component and manipulate them simultaneously.
Every instance in an array can be a member of a group.

Note When using the methods for arraying elements, the following rules apply:

• When performing Linear and Radial Array operations, elements dependent on the arrayed elements are also arrayed.

• Some elements cannot be arrayed because they cannot be grouped. See the Revit User's Guide for more information about
restrictions on groups and arrays.

• Arrays are not supported by most annotation symbols.

Deleting Elements
The Revit Platform API provides Delete() methods to delete one or more elements in the project.

Table 23: Delete Members

Member Description

Delete(ElementId) Delete an element from the project using the element ID

Delete(ICollection<ElementId>) Delete several elements from the project by their IDs.


The first method deletes a single element based on its Id, as shown in the example below.

Code Region: Deleting an element based on ElementId


1. private void DeleteElement(Autodesk.Revit.DB.Document document, Element element)
2. {
3. // Delete an element via its id
4. Autodesk.Revit.DB.ElementId elementId = element.Id;
5. ICollection<Autodesk.Revit.DB.ElementId> deletedIdSet = document.Delete(elementId);
6.
7. if (0 == deletedIdSet.Count)
8. {
9. throw new Exception("Deleting the selected element in Revit failed.");
10. }
11.
12. String prompt = "The selected element has been removed and ";
13. prompt += deletedIdSet.Count - 1;
14. prompt += " more dependent elements have also been removed.";
15.
16. // Give the user some information
17. TaskDialog.Show("Revit", prompt);
18. }

NoteWhen an element is deleted, any child elements associated with that element are also deleted, as indicated in the sample above.

The API also provides a way to delete several elements.

Code Region: Deleting multiple elements based on Id


1. // Delete all the selected elements via the set of element ids.
2. ICollection<Autodesk.Revit.DB.ElementId> idSelection = null ;
3. UIDocument uidoc = new UIDocument(document);
4. foreach (Autodesk.Revit.DB.Element elem in uidoc.Selection.Elements)
5. {
6. Autodesk.Revit.DB.ElementId id = elem.Id;
7. idSelection.Add(id);
8. }
9.
10. ICollection<Autodesk.Revit.DB.ElementId> deletedIdSet = document.Delete(idSelection);
11.
12. if (0 == deletedIdSet.Count)
13. {
14. throw new Exception("Deleting the selected elements in Revit failed.");
15. }
16.
17. TaskDialog.Show("Revit","The selected element has been removed.");

NoteAfter you delete the elements, any references to the deleted elements become invalid and throw an exception if they are accessed.

Pinned Elements
Elements can be pinned to prevent them from moving. The Element.Pinned property can be used to check if an Element is pinned or to pin or unpin an
element.

When Element.Pinned is set to true, the element cannot be moved or rotated.

Views
Views are images produced from a Revit model with privileged access to the data stored in the documents. They can be graphics, such as
plans, or text, such as schedules. Each project document has one or more different views. The last focused window is the active view.

The Autodesk.Revit.DB.View class is the base class for all view types in the Revit document. The Autodesk.Revit.UI.UIView class represents
the window view in the Revit user interface.

In the following sections, you learn how views are generated, the types of views supported by Revit, the features for each view, as well as
the functionality available for view windows in the user interface.
About views
This section is a high-level overview discussing the following:

• How views are generated

• View types

• Display settings

• Temporary view modes

• Element visibility

• Creating and deleting views.


View Process

The following figure illustrates how a view is generated.

Figure 94: Create view process

Each view is generated by projecting a three-dimensional object onto a two-dimensional projection plane. Projections are divided into two
basic classes:

• Perspective

• Parallel

After the projection type is determined, you must specify the conditions under which the 3D model is needed and the scene is to be
rendered. For more information about projection, refer to the View3D section.

World coordinates include the following:

• The viewer's eye position

• The viewing plane location where the projection is displayed.

Revit uses two coordinate systems:

• The global or model space coordinates where the building exists

• The viewing coordinate system.

The viewing coordinate system represents how the model is presented in the observer's view. Its origin is the viewer's eye position whose
coordinates in the model space are retrieved by the View.Origin property. The X, Y, and Z axes are represented by the View.RightDirection,
View.UpDirection, and View.ViewDirection properties respectively.

• View.RightDirection is towards the right side of the screen.

• View.UpDirection towards the up side of the screen.

• View.ViewDirection from the screen to the viewer.

The viewing coordinate system is right-handed. For more information, see the Perspective Projection picture and the Parallel Projection
picture in View3D.
Some portions of a 3D model space that do not display, such as those that are behind the viewer or are too far away to display clearly, are
excluded before being projected onto the projection plane. This action requires cropping the view. The following rules apply to cropping:

• Elements outside of the crop region are no longer in the view.


• The View.GetCropRegionShapeManager method returns a ViewCropRegionShapeManager which provides the boundary information for
the crop region, which may or may not be rectangular.

• The View.CropBoxVisible property determines whether the crop box is visible in the view.

• The View.CropBoxActive property determines whether the crop box is actually being used to crop the view.

After cropping, the model is projected onto the projection plane. The following rules apply to the projection:

• The projection contents are mapped to the screen view port for display.

• During the mapping process, the projection contents are scaled so that they are shown properly on the screen.

• The View.Scale property is the ratio of the actual model size to the view size.

• The view boundary on paper is the crop region, which is a projection of the crop shape on the projection plane.

• The size and position of the crop region is determined by the View.OutLine property.

Display Settings
The view class has properties to get and set the display style settings and the detail level settings. The View.DisplayStyle property uses the
DisplayStyle enumeration and corresponds to the display options available at the bottom of the Revit window as shown below.

Because setting a view's display style to raytrace enters a special restricted mode with limited capabilities, it is not permitted to directly
assign the display style to this value.

The View.DetailLevel property uses the ViewDetailLevel enumeration and corresponds to the detail level options available at the bottom of
the Revit window as shown below.

The ViewDetailLevel enumeration includes Undefined in the case that a given View does not use detail level.
Temporary View Modes

The View class allows for control of temporary view modes. The View.EnableRevealHiddenMode() method turns on the reveal hidden
elements mode for the view. View.EnableTemporaryAnalyticalDisplayMode() enables temporary display of Analytical Model categories only.
And the View.DisableTemporaryViewMode()will disable the specified temporary view mode. The DisableTemporaryViewMode() method takes
a TemporaryViewMode enum. The possible options are shown below.

Member Name Description

RevealHiddenElements The reveal hidden elements mode

TemporaryHideIsolate The temporary hide/isolate mode

WorksharingDisplay One of the worksharing display modes

AnalyticalModel The mode that isolates the analytical model

Rayrace The mode that shows the model in interactive raytracing

The View.IsInTemporaryViewMode method can be used to determine whether the view is currently in the specified TemporaryViewMode.

Element Visibility in a View

Views keep track of visible elements. All elements that are graphical and visible in the view can be retrieved using a FilteredElementCollector
constructed with a document and the id of the view. However, some elements in the set may be hidden or covered by other elements. You
can see them by rotating the view or removing the elements that cover them. Accessing these visible elements may require Revit to rebuild
the geometry of the view. The first time your code uses this constructor for a given view, or the first time your code uses this constructor for
a view whose display settings have just been changed, you may experience a significant performance degradation.

Elements are shown or hidden in a view by category.

• The View.GetVisiblility() method queries a category to determine if it is visible or invisible in the view.

• The View.SetVisibility() method sets all elements in a specific category to visible or invisible.

A FilteredElementCollector based on a view will only contain elements visible in the current view. You cannot retrieve elements that are not
graphical or elements that are invisible. A FilteredElementCollector based on a document retrieves all elements in the document including
invisible elements and non-graphical elements. For example, when creating a default 3D view in an empty project, there are no elements in
the view but there are many elements in the document, all of which are invisible.

The following code sample counts the number of wall category elements in the active document and active view. The number of elements in
the active view differs from the number of elements in the document since the document contains non-graphical wall category elements.

Code Region: Counting elements in the active view


1. private void CountElements(Autodesk.Revit.DB.Document document)
2. {
3. StringBuilder message = new StringBuilder();
4. FilteredElementCollector viewCollector = new
5. FilteredElementCollector(document, document.ActiveView.Id);
6. viewCollector.OfCategory(BuiltInCategory.OST_Walls);
7. message.AppendLine("Wall category elements within active View: "
8. + viewCollector.ToElementIds().Count);
9.
10. FilteredElementCollector docCollector = new FilteredElementCollector(document);
11. docCollector.OfCategory(BuiltInCategory.OST_Walls);
12. message.AppendLine("Wall category elements within document: "
13. + docCollector.ToElementIds().Count);
14.
15. TaskDialog.Show("Revit", message.ToString());
16. }

Temporary view modes can affect element visibility. The View.IsInTemporaryViewMode() method can be used to determine if a View is in a
temporary view mode. The method View.IsElementVisibleInTemporaryViewMode() identifies if an element should be visible in the indicated
view mode. This applies only to the TemporaryHideIsolate and AnalyticalModel view modes. Other modes will result in an exception.

Creating and Deleting Views


The Revit Platform API provides numerous methods to create the corresponding view elements derived from Autodesk.Revit.DB.View class.
Most view types are created using static methods of the derived view classes. If a view is created successfully, these methods return a
reference to the view, otherwise they return null. The methods are described in the following sections specific to each view class.

Views can also be created using the View.Duplicate() method. A new view can be created from an existing view with options for the new
view to be dependent or to have detailing.

Delete a view by using the Document.Delete method with the view ID. You can also delete elements associated with a view. For example,
deleting the level element causes Revit to delete the corresponding plan view or deleting the camera element causes Revit to delete the
corresponding 3D view.

View Types
Different types of Revit views are represented by different classes in the Revit API. See the following topics for more information on each type of view.

Overview
A project model can have several view types. The following picture demonstrates the different types of views in the Project browser.

Figure 95: Different views in the Project browser

In the API, there are three ways to classify views. The first way is by using the view element View.ViewType property. It returns an enumerated
value indicating the view type. The following table lists all available view types.
Table 44: Autodesk.Revit.DB.ViewType

Member Name Description

AreaPlan Area view.

CeilingPlan Reflected ceiling plan view.

ColumnSchedule Coulmn schedule view.

CostReport Cost report view.

Detail Detail view.

DraftingView Drafting view.

DrawingSheet Drawing sheet view.

Elevation Elevation view.

EngineeringPlan Engineering view.

FloorPlan Floor plan view.

Internal Revit's internal view.

Legend Legend view.

LoadsReport Loads report view.

PanelSchedule Panel schedule view.

PressureLossReport Pressure Loss Report view.

Rendering Rendering view.

Report Report view.

Schedule Schedule view.

Section Cross section view.

ThreeD 3-D view.

Undefined Undefined/unspecified view.

Walkthrough Walkthrough view.

The second way to classify views is by the class type.

The following table lists the view types and the corresponding views in the Project browser.
Table 45: Project Browser Views

Project Browser Views View Type Class Type

Area Plans ViewType.AreaPlan Elements.ViewPlan

Ceiling Plans ViewType.CeilingPlan Elements.ViewPlan

Graphic Column Schedule ViewType.ColumnSchedule Elements.View

Detail Views ViewType.Detail Elements.ViewSection

Drafting Views ViewType.DraftingView Elements.ViewDrafting

Sheets ViewType.DrawingSheet Elements.ViewSheet

Elevations ViewType.Elevation Elements.ViewSection

Structural Plans (Revit Structure) ViewType.EngineeringPlan Elements.ViewPlan

Floor Plans ViewType.FloorPlan Elements.ViewPlan

Legends ViewType.Legend Elements.View

Reports (Revit MEP) ViewType.LoadsReport Elements.View

Reports (Revit MEP) ViewType.PanelSchedule Elements.PanelScheduleView

Reports (Revit MEP) ViewType.PresureLossReport Elements.View

Renderings ViewType.Rendering Elements.ViewDrafting

Reports ViewType.Report Elements.View

Schedules/Quantities ViewType.Schedule Elements.ViewSchedule

Sections ViewType.Section Elements.ViewSection

3D Views ViewType.ThreeD Elements.View3D

Walkthroughs ViewType.Walkthrough Elements.View3D


This example shows how to use the ViewType property of a view to determine the view's type.
Code Region: Determining the View type
1. public void GetViewType(Autodesk.Revit.DB.View view)
2. {
3. // Get the view type of the given view, and format the prompt string
4. String prompt = "The view is ";
5.
6. switch (view.ViewType)
7. {
8. case ViewType.AreaPlan:
9. prompt += "an area view.";
10. break;
11. case ViewType.CeilingPlan:
12. prompt += "a reflected ceiling plan view.";
13. break;
14. case ViewType.ColumnSchedule:
15. prompt += "a column schedule view.";
16. break;
17. case ViewType.CostReport:
18. prompt += "a cost report view.";
19. break;
20. case ViewType.Detail:
21. prompt += "a detail view.";
22. break;
23. case ViewType.DraftingView:
24. prompt += "a drafting view.";
25. break;
26. case ViewType.DrawingSheet:
27. prompt += "a drawing sheet view.";
28. break;
29. case ViewType.Elevation:
30. prompt += "an elevation view.";
31. break;
32. case ViewType.EngineeringPlan:
33. prompt += "an engineering view.";
34. break;
35. case ViewType.FloorPlan:
36. prompt += "a floor plan view.";
37. break;
38. // ...
39. default:
40. break;
41. }
42. // Give the user some information
43. MessageBox.Show(prompt, "Revit", MessageBoxButtons.OK);
44. }

The third way to classify views is using the ViewFamilyType class. Most view creation methods required the Id of a ViewFamilyType for the new
view. The Id of the ViewFamilyType can be retrieved from the View.GetTypeId() method. The ViewFamilyType.ViewFamily property returns a
ViewFamily enumeration which specifies the family of the ViewFamilyType and similar to the ViewType enum documented above. The following
example shows how to get the ViewFamily from a View.

Code Region: Determining view type from ViewFamilyType


1. public ViewFamily GetViewFamily(Document doc, View view)
2. {
3. ViewFamily viewFamily = ViewFamily.Invalid;
4.
5. ElementId viewTypeId = view.GetTypeId();
6. if (viewTypeId.IntegerValue > 1) // some views may not have a ViewFamilyType
7. {
8. ViewFamilyType viewFamilyType = doc.GetElement(viewTypeId) as ViewFamilyType;
9. viewFamily = viewFamilyType.ViewFamily;
10. }
11.
12. return viewFamily;
View3D
View3D is a freely-oriented three-dimensional view. There are two kinds of 3D views, perspective and isometric, also referred to as
orthographic in the Revit user interface. The difference is based on the projection ray relationship. The View3D.IsPerspective property
indicates whether a 3D view is perspective or isometric.

Perspective View

The following picture illustrates how a perspective view is created.

Figure 96: Perspective projection

• The straight projection rays pass through each point in the model and intersect the projection plane to form the projection contents.

• To facilitate the transformation from the world coordinate onto the view plane, the viewing coordinate system is based on the viewer.

• Its origin, represented by the View.Origin property, is the viewer position.

• The viewer's world coordinates are retrieved using the ViewOrientation3D.EyePosition property (retrieved from
View3D.GetOrientation()). Therefore, in 3D views, View.Origin is always equal to the corresponding ViewOrientation3D.EyePosition.

• As described, the viewing coordinate system is determined as follows:

o The X-axis is determined by View.RightDirection.

o The Y-axis is determined by View.UpDirection.

o The Z-axis is determined by View.ViewDirection.

• The view direction is from the target point to the viewer in the 3D space, and from the screen to the viewer in the screen space.

The static method View3D.CreatePerspective() method can be used to create new perspective views.

Code Region: View3D.CreatePerspective()


1. public static View3D View3D.CreatePerspective (Document document, ElementId viewFamilyTypeId;

The viewFamilyTypeId parameter needs to be a three dimensional ViewType.

The following code sample illustrates how to create a perspective 3D view.


Code Region: Creating a Perspective 3D view
1. // Find a 3D view type
2. IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
3. let type = elem as ViewFamilyType
4. where type.ViewFamily == ViewFamily.ThreeDimensional
5. select type;
6.
7. // Create a new Perspective View3D
8. View3D view3D = View3D.CreatePerspective(document, viewFamilyTypes.First().Id);
9. if (null != view3D)
10. {
11. // By default, the 3D view uses a default orientation.
12. // Change the orientation by creating and setting a ViewOrientation3D
13. XYZ eye = new XYZ(0, -100, 10);
14. XYZ up = new XYZ(0, 0, 1);
15. XYZ forward = new XYZ(0, 1, 0);
16. view3D.SetOrientation(newViewOrientation3D(eye, up, forward));
17.
18.
19.
20.
21. // turn off the far clip plane with standard parameter API
22.
23. Parameter farClip = view3D.get_Parameter("Far Clip Active");
24. farClip.Set(0);
25. }

The perspective view crop box is part of a pyramid with the apex at the viewer position. It is the geometry between the two parallel clip
planes. The crop box bounds the portion of the model that is clipped out and projected onto the view plane.

• The crop box is represented by the View.CropBox property, which returns a BoundingBoxXYZ object.

• The CropBox.Min and CropBox.Max points are marked in the previous picture. Note that the CropBox.Min point in a perspective view
is generated by projecting the crop box front clip plane onto the back clip plane.

Crop box coordinates are based on the viewing coordinate system. Use Transform.OfPoint() to transform CropBox.Min and CropBox.Max to
the world coordinate system. For more detail about Transform, refer to Geometry.Transform in the Geometry section.

The project plane plus the front and back clip plane are all plumb to the view direction. The line between CropBox.Max and CropBox.Min is
parallel to the view direction. With these factors, the crop box geometry can be calculated.

Figure 97: Perspective 3D view

The previous picture shows the projection plane on screen after cropping. The crop region is the rectangle intersection of the projection
plane and crop box.

• Geometry information is retrieved using the View.CropRegion property. This property returns a BoundingBoxUV instance.

• The View.OutLine.Max property points to the upper right corner.

• The View.OutLine.Min property points to the lower left corner.


• Like the crop box, the crop region coordinates are based on the viewing coordinate system. The following expressions are equal.
View.CropBox.Max.X(Y) / View.OutLine.Max.X(Y) == View.CropBox.Min.X(Y) / View.OutLine.Min.X(Y)

Since the size of an object's perspective projection varies inversely with the distance from that object to the center of the projection, scale is
meaningless for perspective views. The perspective 3D view Scale property always returns zero.

Isometric View

A new isometric view can be created with the static View3D.CreateIsometric() method.

Figure 98: Parallel projection

Isometric views are generated using parallel projection rays by projecting the model onto a plane that is normal to the rays. The viewing
coordinate system is similar to the perspective view, but the crop box is a parallelepiped with faces that are parallel or normal to the
projection rays. The View.CropBox property points to two diagonal corners whose coordinates are based on the viewing coordinate system.

Figure 99: Scale the window on view plane to screen viewport

The model is projected onto a view plane and then scaled onto the screen. The View.Scale property represents the ratio of actual model size
to the view size. The related expressions are as follows:

View.CropBox.Max.X(Y) / View.OutLine.Max.X(Y) == View.CropBox.Min.X(Y) / View.OutLine.Min.X(Y) == View.Scale

Code Region: View3D.CreateIsometric()


1. public static View3D View3D.CreateIsometric (Document document, ElementId viewFamilyTypeId;
The viewFamilyTypeId parameter needs to be a three dimensional ViewType. Revit determines the following:

• Position of the viewer.

• How to create the viewing coordinate system using the view direction.

• How to create the crop box to crop the model.

Once the view is created, you can resize the crop box to view different portions of the model. You can also change the default orientation.
The API does not support modifying the viewing coordinate system.

The following code sample illustrates how to create an isometric 3D view.

Code Region: Creating an Isometric 3D view


1. // Find a 3D view type
2.
3. IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in newFilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
4. let type = elem as ViewFamilyType
5. where type.ViewFamily == ViewFamily.ThreeDimensional
6. select type;
7.
8. // Create a new View3D
9. View3D view3D = View3D.CreateIsometric(document, viewFamilyTypes.First().Id);
10. if (null != view3D)
11. {
12. // By default, the 3D view uses a default orientation.
13. // Change the orientation by creating and setting a ViewOrientation3D
14. XYZ eye = new XYZ(10, 10, 10);
15. XYZ up = new XYZ(0, 0, 1);
16. XYZ forward = new XYZ(0, 1, 0);
17.
18. ViewOrientation3D viewOrientation3D = newViewOrientation3D(eye, up, forward);
19. view3D.SetOrientation(viewOrientation3D);
20. }

3D Views SectionBox

Each view has a crop box. The crop box focuses on a portion of the model to project and show in the view. For 3D views, there is another
box named section box.

• The section box determines which model portion appears in a 3D view.

• The section box is used to clip the 3D model's visible portion.

• The part outside the box is invisible even if it is in the crop box.

• The section box is different from the crop box in that it can be rotated and moved with the model.

The section box is particularly useful for large models. For example, if you want to render a large building, use a section box. The section
box limits the model portion used for calculation. To display the section box, in the 3D view Element Properties dialog box, select Section
Box in the Extents section. You can also set it using the API:

Code Region: Showing the Section Box


1. private void ShowHideSectionBox(Autodesk.Revit.DB.View3D view3D)
2. {
3. foreach (Parameter p in view3D.Parameters)
4. {
5. // Get Section Box parameter
6. if (p.Definition.Name.Equals("Section Box"))
7. {
8. // Show Section Box
9. p.Set(1);
10. // Hide Section Box
11. // p.Set(0);
12. break;
13. }
14. }
15. }
Figure 100: Section box

The View3D.SectionBox property is used to get and change the box extents. In some cases, setting the View3D.SectionBox can have a side
effect. Setting the property to certain values can change the box capacity and display it in the view. However, you can assign a null value to
the SectionBox to keep the modified value and make the section box invisible in the view. To avoid displaying the section box, change the
section box value, then set the section box to null. The following code sample illustrates this process. Notice it only works when the Section
Box check box is selected in the View property dialog box.

Code Region: Hiding the Section Box


1. private void ExpandSectionBox(View3D view)
2. {
3. // The orignial section box
4. BoundingBoxXYZ sectionBox = view.SectionBox;
5.
6. // Expand the section box
7. XYZ deltaXYZ = sectionBox.Max - sectionBox.Min;
8. sectionBox.Max += deltaXYZ / 2;
9. sectionBox.Min -= deltaXYZ / 2;
10.
11. //After reseting the section box, it will be shown in the view.
12. //It only works when the Section Box check box is
13. //checked in View property dialog.
14. view.SectionBox = sectionBox;
15.
16. //Setting the section box to null will make it hidden.
17. view.SectionBox = null; // line x
18. }

Note If you set view.SectionBox to null, it has the same effect as hiding the section box using the Section Box parameter. The current
section box is stored by view and is restored when you show the section box using the SectionBox parameter.

The coordinate of Max and Min points of BoundingBoxXYZ returned from SectionBox property is not WCS. To convert the coordinates of Max
and Min to WCS, you need to convert point via the transform obtained from BoundingBoxXYZ.Transform property.

Code Region: Convert Max and Min to WCS


private void ConvertMaxMinToWCS(View3D view, out XYZ max, out XYZ min)
{ BoundingBoxXYZ sectionbox = view.SectionBox;
Transform transform = sectionbox.Transform;
max = transform.OfPoint(sectionbox.Max);
min = transform.OfPoint(sectionbox.Min);
}
View Locking

The View3D class has methods and properties corresponding to the locking feature available in the Revit user interface.

The View3D.SaveOrientationAndLock() method will save the orientation and lock the view while View3D.RestoreOrientationAndLock() will
restore the view's orientation and lock it. View3D.Unlock() will unlock the view if it is currently locked. The IsLocked property will return
whether the 3D view is currently locked.

ViewPlan
Plan views are level-based. There are three types of plan views, floor plan view, ceiling plan view, and area plan view.

• Generally the floor plan view is the default view opened in a new project.
• Most projects include at least one floor plan view and one ceiling plan view.
• Plan views are usually created after adding new levels to the project.

Adding new levels using the API does not add plan views automatically. Use the static ViewPlan.Create() method to create new floor and
ceiling plan views. Use the static ViewPlan.CreateAreaPlan() method to create a new area plan view.

Code Region: Creating Plan Views


1. public static ViewPlan ViewPlan.Create(Document document, ElementId viewFamilyTypeId, ElementId levelId);
2.
3. public static ViewPlan ViewPlan.CreateAreaPlan(Document document, ElementId areaSchemeId, ElementId levelId);

The viewFamilyTypeId parameter in ViewPlan.Create() needs to be a FloorPlan, CeilingPlan, AreaPlan, or StructuralPlan ViewType. The
levelId parameter represents the Id of the level element in the project to which the plan view is associated.

The following code creates a floor plan and a ceiling plan based on a certain level.

Code Region: Creating a floor plan and ceiling plan


1. // Find a floor plan view type
2. IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
3. let type = elem as ViewFamilyType
4. where type.ViewFamily == ViewFamily.FloorPlan
5. select type;
6.
7. // Create a Level and a Floor Plan based on it
8. double elevation = 10.0;
9. Level level1 = document.Create.NewLevel(elevation);
10. ViewPlan floorView = ViewPlan.Create(document, viewFamilyTypes.First().Id, level1.Id);
11.
12. // Create another Level and a Ceiling Plan based on it
13. // Find a ceiling plan view type
14. viewFamilyTypes = from elem in new FilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
15. let type = elem as ViewFamilyType
16. where type.ViewFamily == ViewFamily.CeilingPlan
17. select type;
18.
19. elevation += 10.0;
20. Level level2 = document.Create.NewLevel(elevation);
21. ViewPlan ceilingView = ViewPlan.Create(document, viewFamilyTypes.First().Id, level2.Id);
After creating a new plan view, the Discipline for the view can be set using the Discipline parameter which is type ViewDiscipline. Options
include Architectural, Structural, Mechanical, Electrical, Plumbing and Coordination.

For structural plan views, the view direction can be set to either Up or Down using the ViewFamilyType.PlanViewDirection property.
Although it is a property of the ViewFamilyType class, an exception will be thrown if the property is accessed for views other than
StructuralPlan views.

The view range for plan views can be retrieved via the ViewPlan.GetViewRange() method. The returned PlanViewRange object can be used
to find the levels which a plane is relative to and the offset of each plane from that level. It is the same information that is available in the
View Range dialog in the Revit user interface:

The following example shows how to get the top clip plane and the associated offset for a plan view

Code Region: Getting information on the view range


1. private void ViewRange(Document doc, View view)
2. {
3. if (view is ViewPlan)
4. {
5. ViewPlan viewPlan = view as ViewPlan;
6. PlanViewRange viewRange = viewPlan.GetViewRange();
7.
8. ElementId topClipPlane = viewRange.GetLevelId(PlanViewPlane.TopClipPlane);
9. double dOffset = viewRange.GetOffset(PlanViewPlane.TopClipPlane);
10.
11. if (topClipPlane.IntegerValue > 0)
12. {
13. Element levelAbove = doc.GetElement(topClipPlane);
14. TaskDialog.Show(view.Name, "Top Clip Plane: " + levelAbove.Name + "\r\nTop Offset: " + dOffset + " ft");
15. }
16. }

ViewDrafting
The drafting view is not associated with the model. It allows the user to create detail drawings that are not included in the model.

• In the drafting view, the user can create details in different view scales (coarse, fine, or medium).

• You can use 2D detailing tools, including:

• Detail lines • Reference planes


• Detail regions • Dimensions
• Detail components • Symbols
• Insulation • Text

These tools are the same tools used to create a detail view.

• Drafting views do not display model elements.

Use the Autodesk.Revit.Creation.NewViewDrafting() method to create a drafting view. Model elements are not displayed in the drafting view.
ImageView

The ImageView class is derived from ViewDrafting. It can be used to create rendering views containing images imported from disk. Use the
static ImageView.Create() method to create new rendering views.

ViewSection
The ViewSection class can be used to create section views, detail views, callout views, reference callouts and reference sections. It also
represents elevation views.

Section Views and Reference Sections

Section views cut through the model to expose the interior structure. The ViewSection.CreateSection() method creates the section view.

Code Region: ViewSection.CreateSection()


1. public ViewSection ViewSection.CreateSection(Document document, ElementId viewFamilyTypeId, BoundingBoxXYZ sectionBox);

The viewFamilyTypeId parameter is the Id for the ViewFamilyType which will be used by the new ViewSection. The type needs to be a
Section ViewFamily. The sectionBox parameter is the section view crop box. It provides the direction and extents which are required for the
section view. Usually, another view's crop box is used as the parameter. You can also build a custom BoundingBoxXYZ instance to represent
the direction and extents.
The following code shows how to create a section view. A bounding box for the section view is created at the center of a wall. The resulting
section view will be located in the Sections (Building Section) node in the Project Browser.

Code Region: Creating a section view


1. // Find a section view type
2. IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
3. let type = elem as ViewFamilyType
4. where type.ViewFamily == ViewFamily.Section
5. select type;
6.
7. // Create a BoundingBoxXYZ instance centered on wall
8. LocationCurve lc = wall.Location as LocationCurve;
9. Transform curveTransform = lc.Curve.ComputeDerivatives(0.5, true);
10. // using 0.5 and "true" (to specify that the parameter is normalized)
11. // places the transform's origin at the center of the location curve)
12.
13. XYZ origin = curveTransform.Origin; // mid-point of location curve
14. XYZ viewDirection = curveTransform.BasisX.Normalize(); // tangent vector along the location curve
15. XYZ normal = viewDirection.CrossProduct(XYZ.BasisZ).Normalize(); // location curve normal @ mid-point
16.
17. Transform transform = Transform.Identity;
18. transform.Origin = origin;
19. transform.BasisX = normal;
20. transform.BasisY = XYZ.BasisZ;
21.
22. // can use this simplification because wall's "up" is vertical.
23. // For a non-vertical situation (such as section through a sloped floor the surface normal would be needed)
24. transform.BasisZ = normal.CrossProduct(XYZ.BasisZ);
25.
26. BoundingBoxXYZ sectionBox = new BoundingBoxXYZ();
27. sectionBox.Transform = transform;
28. sectionBox.Min = new XYZ(-10,0,0);
29. sectionBox.Max = new XYZ(10,12,5);
30. // Min & Max X values (-10 & 10) define the section line length on each side of the wall
31. // Max Y (12) is the height of the section box// Max Z (5) is the far clip offset
32.
33. // Create a new view section.
34. ViewSection viewSection = ViewSection.CreateSection(document, viewFamilyTypes.First().Id, sectionBox);

Reference sections are sections that reference an existing view. Revit does not add a new view when you create a new reference section.

Code Region: ViewSection.CreateReferenceSection()


1. public ViewSection ViewSection.CreateReferenceSection(Document document,
2. ElementId parentViewId,
3. ElementId viewIdToReference,
4. XYZ headPoint,
5. XYZ tailPoint);

The parentViewId parameter is the Id of the view in which the new reference section marker will appear. Reference sections can be created
in FloorPlan, CeilingPlan, StructuralPlan, Section, Elevation, Drafting, and Detail views. The viewIdToReference can be the Id of a Detail,
Drafting or Section view. The ViewFamilyType of the referenced view will be used by the new reference section. The two XYZ points will
determine the location of the section marker's head in the parent view.

Detail Views

A detail view is a view of the model that appears as a callout or section in other views. This type of view typically represents the model at
finer scales of detail than in the parent view. It is used to add more information to specific parts of the model. The static
ViewSection.CreateDetail() method is used to create a new detail ViewSection.

Code Region: ViewSection.CreateDetail()


1. public ViewSection ViewSection.CreateDetail(Document document, ElementId viewFamilyTypeId, BoundingBoxXYZ sectionBox);
The viewFamilyTypeId parameter is the Id for the ViewFamilyType which will be used by the new ViewSection. The type needs to be a
Detail ViewFamily. Just as for a standard section view, the sectionBox parameter is the section view crop box. It provides the direction and
extents which are required for the section view.

When a new detail ViewSection is added, it will appear in the Detail Views (Detail) node in the Project Browser.

Elevation Views

An elevation view is a cross-section of the model where level lines are displayed. An elevation view is represented by the ViewSection class.
However, unlike the other types of section views, you cannot create elevation views using a static method on the ViewSection class. To
create an elevation view, first create an elevation marker, then use the marker to generate the elevation view. The newly created elevation
view will appear in the Elevations (Building Elevation) node in the Project Browser. It will be assigned a unique name.

The following example creates an elevation view based on the location of a beam.

Code Region: Creating an Elevation View


1. ViewSection CreateElevationView(Document document, FamilyInstance beam)
2. {
3. // Find an elevation view type
4. IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
5. let type = elem as ViewFamilyType
6. where type.ViewFamily == ViewFamily.Elevation
7. select type;
8.
9. LocationCurve lc = beam.Location as LocationCurve;
10. XYZ xyz = lc.Curve.GetEndPoint(0);
11. ElevationMarker marker = ElevationMarker.CreateElevationMarker(document, viewFamilyTypes.First().Id, xyz, 1);
12. ViewSection elevationView = marker.CreateElevation(document, document.ActiveView.Id, 1);
13.
14. return elevationView;
15. }

The ElevationMarker.CreateElevation() method takes an id of a ViewPlan as a parameter. That is the ViewPlan in which the ElevationMarker
is visible. The new elevation ViewSection will derive its extents and inherit settings from the ViewPlan. The last parameter is the index on
the ElevationMarker where the new elevation view will be placed. The index on the ElevationMarker must be valid and unused. The view's
direction is determined by the index.

Callouts and Reference Callouts

A callout shows part of another view at a larger scale. Callout views can be created using the static method ViewSection.CreateCallout().
Callouts can be created in FloorPlan, CeilingPlan, StructuralPlan, Section, Elevation, Drafting and Detail views. The resulting view will be
either a ViewSection, ViewPlan or ViewDetail depending on the ViewFamilyType used and will appear in the corresponding node in the Project
Browser.

Code Region: ViewSection.CreateCallout()


1. public ViewSection ViewSection.CreateCallout(Document document,
2. ElementId parentViewId,
3. ElementId viewFamilyTypeId,
4. XYZ point1,
5. XYZ point2);

The parent view Id parameter can be the Id of any type of View on which callouts can be created. The point parameters determine the
extents of the callout symbol in the parent view.

A reference callout is a callout that refers to an existing view. When you add a reference callout, Revit does not create a view in the project.
Instead, it creates a pointer to a specified, existing view. Multiple reference callouts can point to the same view.

Code Region: ViewSection.CreateReferenceCallout()


1. public ViewSection ViewSection.CreateReferenceCallout(Document document,
2. ElementId parentViewId,
3. ElementId viewIdToReference,
4. XYZ point1,
5. XYZ point2);

Creation of a reference callout is similar to creation of a callout. But rather than having the Id of the ViewFamilyType for the callout as a
parameter, the CreateReferenceCallout() method takes the Id of the view to reference. The ViewFamilyType of the referenced view will be
used by the new reference callout.
Only cropped views can be referenced, unless the referenced view is a Drafting view. Drafting views can always be referenced regardless of
the parent view type. Elevation views can be referenced from Elevation and Drafting parent views. Section views can be referenced from
Section and Drafting parent views. Detail views can be referenced from all parent views except for in FloorPlan, CeilingPlan and
StructuralPlan parent views where only horizontally-oriented Detail views can be referenced. FloorPlan, CeilingPlan and StructuralPlan views
can be referenced from FloorPlan, CeilingPlan and StructuralPlan parent views.

The following example creates a new callout using a Detail ViewFamilyType and then uses the new callout view to create a reference callout.

Code Region: Creating a callout and reference callout


1. public void CreateCalloutView(Document document, View parentView)
2. {
3. // Find a detail view type
4. IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(document).OfClass(typeof(ViewFamilyType))
5. let type = elem as ViewFamilyType
6. where type.ViewFamily == ViewFamily.Detail
7. select type;
8.
9. ElementId viewFamilyTypeId = viewFamilyTypes.First().Id;
10. XYZ point1 = new XYZ(2, 2, 2);
11. XYZ point2 = new XYZ(30, 30, 30);
12. ElementId parentViewId = parentView.Id; // a ViewPlan
13. View view = ViewSection.CreateCallout(document, parentViewId, viewFamilyTypeId, point1, point2);
14.
15. ViewSection.CreateReferenceCallout(document, parentViewId, view.Id, point1, point2);

ViewSheet
A sheet contains views and a title block. When creating a sheet view with the ViewSheet.Create() method, a title block family symbol Id is a
required parameter for the method. The Autodesk.Revit.Document TitleBlocks property contains all title blocks in the document. Choose one
title block to create the sheet.

Code Region: ViewSheet.Create()


1. public static ViewSheet ViewSheet.Create(Document document, ElementId titleBlockTypeId);

The newly created sheet has no views. The Viewport.Create() method is used to add views. The Viewport class is used to add regular views
to a view sheet, i.e. plan, elevation, drafting and three dimensional. To add schedules to a view, use ScheduleInstance.Create() instead.

Code Region: Add views to sheet


1. public static Viewport Viewport.Create(Document document, ElementId viewSheetId, ElementId viewId,
2. XYZ point);

• The XYZ location parameter identifies where the added views are located. It points to the added view's center coordinate (measured
in inches).

• The coordinates, [0, 0], are relative to the sheet's lower left corner.

Each sheet has a unique sheet number in the complete drawing set. The number is displayed before the sheet name in the Project Browser.
It is convenient to use the sheet number in a view title to cross-reference the sheets in your drawing set. You can retrieve or modify the
number using the SheetNumber property. The number must be unique; otherwise an exception is thrown when you set the number to a
duplicate value.
The following example illustrates how to create and print a sheet view. Begin by finding an available title block in the document (using a
filter in this case) and use it to create the sheet view. Next, add a 3D view. The view is placed with its lower left-hand corner at the center of
the sheet. Finally, print the sheet by calling the View.Print() method.

Code Region: Creating a sheet view


1. private void CreateSheetView(Autodesk.Revit.DB.Document document, View3D view3D)
2. {
3.
4. // Get an available title block from document
5. IEnumerable<FamilySymbol> familyList = from elem in new FilteredElementCollector(document)
6. .OfClass(typeof(FamilySymbol))
7. .OfCategory(BuiltInCategory.OST_TitleBlocks)
8. let type = elem as FamilySymbol
9. where type.Name.Contains("E1")
10. select type;
11.
12. // Create a sheet view
13. ViewSheet viewSheet = ViewSheet.Create(document, familyList.First().Id);
14. if (null == viewSheet)
15. {
16. throw new Exception("Failed to create new ViewSheet.");
17. }
18.
19. // Add passed in view onto the center of the sheet
20. if (Viewport.CanAddViewToSheet(document, viewSheet.Id, view3D.Id))
21. {
22. BoundingBoxUV sheetBox = viewSheet.Outline;
23. double yPosition = (sheetBox.Max.V - sheetBox.Min.V) / 2 + sheetBox.Min.V;
24. double xPosition = (sheetBox.Max.U - sheetBox.Min.U) / 2 + sheetBox.Min.U;
25.
26. XYZ origin = new XYZ(xPosition, yPosition, 0);
27. Viewport viewport = Viewport.Create(document, viewSheet.Id, view3D.Id, origin);
28. }
29.
30. // Print the sheet out
31. if (viewSheet.CanBePrinted)
32. {
33. TaskDialog taskDialog = new TaskDialog("Revit");
34. taskDialog.MainContent = "Print the sheet?";
35. TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No;
36. taskDialog.CommonButtons = buttons;
37. TaskDialogResult result = taskDialog.Show();
38.
39. if (result == TaskDialogResult.Yes)
40. {
41. viewSheet.Print();
42. }
43. }
44. }

Note You cannot add a sheet view to another sheet and you cannot add a view to more than one sheet; otherwise an argument exception
occurs.

Printer Setup

You may want to change the settings of the printer before printing a sheet. The API exposes the settings for the printer with the
PrintManager class, and related Autodesk.Revit.DB classes:

Class Functionality

Autodesk.Revit.DB.PrintManager Represents the Print information in Print Dialog (File->Print) within the Revit UI.

Autodesk.Revit.DB.PrintParameters An object that contains settings used for printing the document.

Autodesk.Revit.DB.PrintSetup Represents the Print Setup (File->Print Setup...) within the Revit UI.

Autodesk.Revit.DB.PaperSize An object that represents a Paper Size of Print Setup within the Autodesk Revit project.

Autodesk.Revit.DB.PaperSizeSet A set that can contain any number of paper size objects.

Autodesk.Revit.DB.PaperSource An object that represents a Paper Source of Print Setup within the Autodesk Revit project.

Autodesk.Revit.DB.PaperSourceSet A set that can contain any number of paper source objects.

Autodesk.Revit.DB.ViewSheetSetting Represents the View/Sheet Set (File->Print) within the Revit UI.

Autodesk.Revit.DB.PrintSetting Represents the Print Setup (File->Print Setup...) within the Revit UI.
For an example of code that uses these objects, see the ViewPrinter sample application that is included with the Revit Platform SDK.

ViewSchedule
A schedule is a tabular representation of data. A typical schedule shows all elements of a category (doors, rooms, etc.) with each row representing
an element and each column representing a parameter.

The ViewSchedule class represents schedules and other schedule-like views, including single-category and multi-category schedules, key
schedules, material takeoffs, view lists, sheet lists, keynote legends, revision schedules, and note blocks.

The ViewSchedule.Export() method will export the schedule data to a text file.

Placing Schedules on Sheets


The static ScheduleSheetInstance.Create() method creates an instance of a schedule on a sheet. It requires the ID of the sheet where the
schedule will be placed, the ID of the schedule view, and the XYZ location on the sheet where the schedule will be placed. The
ScheduleSheetInstance object has properties to access the ID of the "master" schedule that generates this ScheduleSheetInstance, the rotation of
the schedule on the sheet, the location on the sheet where the schedule is placed (in sheet coordinates), as well as a flag that identifies if the
ScheduleSheetInstance is a revision schedule in a titleblock family.

Creating a Schedule
The ViewSchedule class has several methods for creating new schedules depending on the type of schedule. All of the methods have a Document parameter
that is the document to which the new schedule or schedule-like view will be added. The newly created schedule views will appear under the
Schedules/Quantities node in the Project Browser.

A standard single-category or multi-category schedule can be created with the static ViewSchedule.CreateSchedule() method.

Code Region: ViewSchedule.CreateSchedule()


1. public ViewSchedule ViewSchedule.CreateSchedule(Document document, ElementId categoryId);

The second parameters the ID of the category whose elements will be included in the schedule, or InvalidElementId for a multi-category schedule.

A second CreateSchedule() method can be used to create an area schedule and takes an additional parameter that is the ID of an area scheme for
the schedule.

Code Region: Creating an area schedule


1. FilteredElementCollector collector1 = new FilteredElementCollector(doc);
2. collector1.OfCategory(BuiltInCategory.OST_AreaSchemes);
3. //Get first ElementId of AreaScheme.
4. ElementId areaSchemeId = collector1.FirstElementId();
5.
6. //If you want to create an area schedule, you must use CreateSchedule method with three arguments.
7. //The input of second argument must be ElementId of BuiltInCategory.OST_Areas category and the input of third argument must be ElementId
of a areaScheme.
8. ViewSchedule areaSchedule = Autodesk.Revit.DB.ViewSchedule.CreateSchedule(doc, new ElementId(BuiltInCategory.OST_Areas), areaSchemeId);

A key schedule displays abstract "key" elements that can be used to populate parameters of ordinary model elements and can be created with the static
ViewSchedule.CreateKeySchedule() method whose second parameter is the ID of the category of elements with which the schedule's keys will be associated.

A material takeoff is a schedule that displays information about the materials that make up elements in the model. Unlike regular schedules
where each row (before grouping) represents a single element, each row in a material takeoff represents a single <element, material> pair. The
ViewSchedule.CreateMaterialTakeoff() method has the same parameters as the ViewSchedule.CreateSchedule() method and allows for both
single- and multi-category material takeoff schedules.

View lists, sheet lists, and keynote legends are associated with a designated category and therefore their creation methods do take a category ID
as a parameter. A view list is a schedule of views in the project. It is a schedule of the Views category and is created using
ViewSchedule.CreateViewList().
A sheet list is a schedule of sheets in the project. It is a schedule of the Sheets category and is created using the ViewSchedule.CreateSheetList()
method.

A keynote legend is a schedule of the Keynote Tags category and is created using ViewSchedule.CreateKeynoteLegend().

Revision schedules are added to titleblock families and become visible as part of titleblocks on sheets. The
ViewSchedule.CreateRevisionSchedule() method will throw an exception if the document passed in is not a titleblock family.

A note block is a schedule of the Generic Annotations category that shows elements of a single family rather than all elements in a category.

Code Region: ViewSchedule.CreateNoteBlock()


1. public ViewSchedule ViewSchedule.CreateNoteBlock(Document document, ElementId familyId);

The second parameter is the ID of the family whose elements will be included in the schedule.

Code Region: Creating a note block schedule


1. //Get first ElementId of AnnotationSymbolType families.
2. ElementId annotationSymbolTypeId = ElementId.InvalidElementId;
3. if (!doc.AnnotationSymbolTypes.IsEmpty)
4. {
5. foreach (AnnotationSymbolType type in doc.AnnotationSymbolTypes)
6. {
7. annotationSymbolTypeId = type.Family.Id;
8. break;
9. }
10. }
11.
12. //Create a noteblock view schedule.
13. ViewSchedule noteBlockSchedule = ViewSchedule.CreateNoteBlock(doc, annotationSymbolTypeId);

Working with ViewSchedule


The ScheduleDefinition class contains various settings that define the contents of a schedule view, including:

• The schedule's category and other basic properties that determine the type of schedule.
• A set of fields that become the columns of the schedule.
• Sorting and grouping criteria.
• Filters that restrict the set of elements visible in the schedule.

Most schedules contain a single ScheduleDefinition which is retrieved via the ViewSchedule.Definition property. In Revit MEP, schedules of certain
categories can contain an "embedded schedule" containing elements associated with the elements in the primary schedule, for example a room
schedule showing the elements inside each room or a duct system schedule showing the elements associated with each system. An embedded
schedule has its own category, fields, filters, etc. Those settings are stored in a second ScheduleDefinition object. When present, the embedded
ScheduleDefinition is obtained from the ScheduleDefinition.EmbeddedDefinition property.

Adding Fields

Once a ViewSchedule is created, fields can be added. The ScheduleDefinition.GetSchedulableFields() method will return a list of SchedulableField
objects representing the non-calculated fields that may be included in the schedule. A new field can be added from a SchedulableField object or
using a ScheduleFieldType. The following table describes the options available from the ScheduleFieldType enumeration.
Member name Description

An instance parameter of the scheduled elements. All shared parameters also use this type, regardless of whether they are instance or type
Instance
parameters.

ElementType A type parameter of the scheduled elements.

Count The number of elements appearing on the schedule row.

A specialized type of field used for a few parameters whose displayed values can change based on the settings of the view:
ROOM_AREA and ROOM_PERIMETER in room and space schedules.
ViewBased
PROJECT_REVISION_REVISION_NUM in revision schedules.
KEYNOTE_NUMBER in keynote legends that are numbered by sheet.

Formula A formula calculated from the values of other fields in the schedule.

Percentage A value indicating what percent of the total of another field each element represents.

Room A parameter of the room that a scheduled element belongs to.

FromRoom A parameter of the room on the "from" side of a door or window.

ToRoom A parameter of the room on the "to" side of a door or window.

A parameter of the Project Info element in the project that the scheduled element belongs to, which may be a linked file. Only allowed in
ProjectInfo
schedules that include elements from linked files.

Material In a material takeoff, a parameter of one of the materials of a scheduled element.

In a material takeoff, a value representing how a particular material is used within a scheduled element. The parameter ID can be
MaterialQuantity
MATERIAL_AREA, MATERIAL_VOLUME, or MATERIAL_ASPAINT.

A parameter of the RevitLinkInstance that an element in a linked file belongs to. Currently RVT_LINK_INSTANCE_NAME is the only supported
RevitLinkInstance
parameter. Only allowed in schedules that include elements from linked files.

A parameter of the RevitLinkType that an element in a linked file belongs to. Currently RVT_LINK_FILE_NAME_WITHOUT_EXT is the only
RevitLinkType
supported parameter. Only allowed in schedules that include elements from linked files.

StructuralMaterial A parameter of the structural material of a scheduled element.

Space A parameter of the space that a scheduled element belongs to.

Using one of the ScheduleDefinition.AddField() methods will add the field to the end of the field list. To place a new field in a specific location in
the field list, use one of the ScheduleDefinition.InsertField() methods. Fields can also be ordered after the fact
using ScheduleDefinition.SetFieldOrder().
The following is a simple example showing how to add fields to a view if they are not already in the view schedule.

Code Region: Adding fields to a schedule


1. /// <summary>
2. /// Add fields to view schedule.
3. /// </summary>
4. /// <param name="schedules">List of view schedule.</param>
5. public void AddFieldToSchedule(List<ViewSchedule> schedules)
6. {
7. IList<SchedulableField> schedulableFields = null;
8.
9. foreach (ViewSchedule vs in schedules)
10. {
11. //Get all schedulable fields from view schedule definition.
12. schedulableFields = vs.Definition.GetSchedulableFields();
13.
14. foreach (SchedulableField sf in schedulableFields)
15. {
16. bool fieldAlreadyAdded = false;
17. //Get all schedule field ids
18. IList<ScheduleFieldId> ids = vs.Definition.GetFieldOrder();
19. foreach (ScheduleFieldId id in ids)
20. {
21. //If the GetSchedulableField() method of gotten schedule field returns same schedulable field,
22. // it means the field is already added to the view schedule.
23. if (vs.Definition.GetField(id).GetSchedulableField() == sf)
24. {
25. fieldAlreadyAdded = true;
26. break;
27. }
28. }
29.
30. //If schedulable field doesn't exist in view schedule, add it.
31. if (fieldAlreadyAdded == false)
32. {
33. vs.Definition.AddField(sf);
34. }
35. }
36. }
37. }

The ScheduleField class represents a single field in a ScheduleDefinition's list of fields. Each (non-hidden) field becomes a column in the schedule.

Most commonly, a field represents an instance or type parameter of elements appearing in the schedule. Some fields represent parameters of
other related elements, like the room to which a scheduled element belongs. Fields can also represent data calculated from other fields in the
schedule, specifically Formula and Percentage fields.

The ScheduleField class has properties to control column headings, both the text as well as the orientation. Column width and horizontal
alignment of text within a column can also be defined.

The ScheduleField.IsHidden property can be used to hide a field. A hidden field is not displayed in the schedule, but it can be used for filtering,
sorting, grouping, and conditional formatting and can be referenced by Formula and Percentage fields.

Some ScheduleFields can be totaled and if the HasTotals property is set to true, totals will be displayed if a footer row is enabled where the totals
will be displayed. It can either be a grand total row at the end of the schedule or a footer row for one of the schedule's grouped fields. In a non-
itemized schedule, totals are also displayed in regular rows when multiple elements appear on the same row.

Style and Formatting of Fields

ScheduleField.GetStyle() and ScheduleField.SetStyle() use the TableCellStyle class to work with the style of fields in a schedule. Using SetStyle(),
various attributes of the field can be set, including the line style for the border of the cell as well as the text font, color and size.

ScheduleField.SetFormatOptions() and ScheduleField.GetFormatOptions() use the FormatOptions class to work with the formatting of a field's
data. The FormatOptions class contains settings that control how to format numbers with units as strings. It contains those settings that are
typically chosen by an end user in the Format dialog and stored in the document.
In the following example, all length fields in a ViewSchedule are formatted to display in feet and fractional inches.

Code Region: Formatting a field


1. // format length units to display in feet and inches format
2. public void FormatLengthFields(ViewSchedule schedule)
3. {
4. int nFields = schedule.Definition.GetFieldCount();
5. for (int n = 0; n < nFields; n++)
6. {
7. ScheduleField field = schedule.Definition.GetField(n);
8. if (field.UnitType == UnitType.UT_Length)
9. {
10. FormatOptions formatOpts = new FormatOptions();
11. formatOpts.UseDefault = false;
12. formatOpts.DisplayUnits = DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES;
13. field.SetFormatOptions(formatOpts);
14. }
15. }
16. }

Grouping and Sorting in Schedules

A schedule may be sorted or grouped by one or more of the schedule's fields. Several methods can be used to control grouping and sorting of
fields. The ScheduleSortGroupField class represents one of the fields that the schedule is sorted or grouped by. Sorting and grouping are related
operations. In either case, elements appearing in the schedule are sorted based on their values for the field by which the schedule is
sorted/grouped, which automatically causes elements with identical values to be grouped together. By enabling extra header, footer, or blank
rows, visual separation between groups can be achieved.

If the ScheduleDefinition.IsItemized property is false, elements having the same values for all of the fields used for sorting/grouping will be
combined onto the same row. Otherwise the schedule displays each element on a separate row

A schedule can be sorted or grouped by data that is not displayed in the schedule by marking the field used for sorting/grouping as hidden using
the ScheduleField.IsHidden property.

Headers can also be grouped. The overloaded ViewSchedule.GroupHeaders() method can be used to specify which rows and columns to include in
a grouping of the header section. One of the overloaded methods takes a string for the caption of the grouped rows and columns.

In the following example, two or more columns are grouped using a caption. Then, if the caption text appears in the column heading, it is
removed.

Code Region: Grouping headers


1. // Group columns of related data and remove redundant text from column headings
2. public void GroupRelatedData(ViewSchedule colSchedule, int startIndex, int endIndex, string groupText)
3. {
4. colSchedule.GroupHeaders(0, startIndex, 0, endIndex, groupText);
5.
6. // If column heading has groupText in it, remove it
7. // (i.e. if groupText is "Top" and field heading is "Top Level",
8. // change the heading to just "Level"
9. for (int index = startIndex; index <= endIndex; index++)
10. {
11. ScheduleField field = colSchedule.Definition.GetField(index);
12. field.ColumnHeading = field.ColumnHeading.Replace(groupText, "");
13. }
14. }

Filtering

A ScheduleFilter can be used to filter the elements that will be displayed in a schedule. A filter is a condition that must be satisfied for an element
to appear in the schedule. All filters must be satisfied for an element to appear in the schedule.

A schedule can be filtered by data that is not displayed in the schedule by marking the field used for filtering as hidden using the
ScheduleField.IsHidden property.

Working with Schedule Data

ViewSchedule.GetTableData() returns a TableData object that holds most of the data that describe the style and contents of the rows, columns,
and cells in a table. More information can be found under TableView and TableData.
TableView and TableData
TableView is a class that represents a view that shows a table and it is the base class for ViewSchedule and PanelScheduleView.

Working with data in a schedule

The actual data for a table is contained in the TableData class. Although the TableData object cannot be obtained directly from the TableView
class, both child classes have a GetTableData() method. For ViewSchedule, this method returns a TableData object. For a PanelScheduleView,
GetTableData() returns a PanelScheduleData object, which derives from the TableData base class. The TableData class holds most of the data that
describe the style of the rows, columns, and cells in a table. PanelScheduleData provides additional methods related specifically to panel
schedules.

Working with rows, columns and cells

Data in a table is broken down into sections. To work with the rows, columns and cells of the TableData, it is necessary to get the
a TableSectionData object. TableData.GetSectionData() can be called with either an integer to the requested section data, or using the
SectionType (i.e. Header or Body).

The TableSectionData class can be used to insert or remove rows or columns, format cells, and to get details of the cells that make up that section
of the schedule, such as the cell type (i.e. Text or Graphic) or the cell's category id.

In the following example, a new row is added to the header section of the schedule and the text is set for the newly created cell. Note that the
first row of the header section defaults to the title when created with the UI.

Code Region: Inserting a row


1. public void CreateSubtitle(ViewSchedule schedule)
2. {
3. TableData colTableData = schedule.GetTableData();
4.
5. TableSectionData tsd = colTableData.GetSectionData(SectionType.Header);
6. tsd.InsertRow(tsd.FirstRowNumber + 1);
7. tsd.SetCellText(tsd.FirstRowNumber + 1, tsd.FirstColumnNumber, "Schedule of column top and base levels with offsets");
8. }

Note: Adding rows and columns is only possible in the header section of a regular schedule.

Also note, in the code example above, it uses the properties FirstRowNumber and FirstColumnNumber. In some sections the row or column
numbers might start with 0, or they might start with 1. These properties should always be used in place of a hardcoded 0 or 1.

The style of rows, columns, or individual cells can be customized for schedules. This includes the ability to set the border line style for all four sides
of cells, as well as cell color and text appearance (i.e. color, font, size). For regular schedules, this can only be done in the header section of the
table.

In the example below, the font of the subtitle of a ViewSchedule (assumed to be the second row of the header section) is set to bold and the font
size is set to 10.

Code Region: Formatting cells


1. public void FormatSubtitle(ViewSchedule colSchedule)
2. {
3. TableData colTableData = colSchedule.GetTableData();
4.
5. TableSectionData tsd = colTableData.GetSectionData(SectionType.Header);
6. // Subtitle is second row, first column
7. if (tsd.AllowOverrideCellStyle(tsd.FirstRowNumber + 1, tsd.FirstColumnNumber))
8. {
9. TableCellStyle tcs = new TableCellStyle();
10. TableCellStyleOverrideOptions options = new TableCellStyleOverrideOptions();
11. options.FontSize = true;
12. options.Bold = true;
13. tcs.SetCellStyleOverrideOptions(options);
14. tcs.IsFontBold = true;
15. tcs.TextSize = 10;
16. tsd.SetCellStyle(tsd.FirstRowNumber + 1, tsd.FirstColumnNumber, tcs);
17. }
18. }
View Filters
Filters can be applied to Views using the ParameterFilterElement class. A ParameterFilterElement filters elements based on its category and a series of filter
rules. One or more categories can be specified as allowable for the filter.

Once a filter has been defined (with one or more categories and one or more filter rules), it can be applied to a View using one of several methods. The
View.AddFilter() method will apply the filter to the view, but with default overrides, meaning the view's display will not change. View.SetFilterOverrides() will
set graphical overrides associated with a filter. And View.SetFilterVisibility() will set whether the elements that pass the filter are visible in the view or not.
AddFilter() and SetFilterVisibility() will both apply the filter to the view if it is not already applied, making it unnecessary to call AddFilter() separately.

The following example creates a filter which includes all walls whose Comments property is set to "foo". The filter is then applied to the View so that any walls
meeting this criteria are outlined in red.

Code Region: Applying a filter to a view


1. private void CreateViewFilter(Autodesk.Revit.DB.Document doc, View view)
2. {
3. List<ElementId> categories = new List<ElementId>();
4. categories.Add(new ElementId(BuiltInCategory.OST_Walls));
5. ParameterFilterElement parameterFilterElement = ParameterFilterElement.Create(doc, "Comments = foo", categories);
6.
7. FilteredElementCollector parameterCollector = new FilteredElementCollector(doc);
8. Parameter parameter = parameterCollector.OfClass(typeof(Wall)).FirstElement().get_Parameter("Comments");
9.
10. List<FilterRule> filterRules = new List<FilterRule>();
11. filterRules.Add(ParameterFilterRuleFactory.CreateEqualsRule(parameter.Id, "foo", true));
12. parameterFilterElement.SetRules(filterRules);
13.
14.
15. OverrideGraphicSettings filterSettings = new OverrideGraphicSettings();
16. // outline walls in red
17. filterSettings.SetProjectionLineColor(new Color(255, 0, 0));
18. view.SetFilterOverrides(parameterFilterElement.Id, filterSettings);
19. }

All filters applied to a view can be retrieved using the View.GetFilters() method which will return a list of filter ids. Filter visibility and graphic overrides can be
checked for a specific filter using the View.GetFilterVisibility() and View.GetFilterOverrides() methods respectively. View.RemoveFilter will remove a filter from
the view.

View Cropping
The crop region for some views may be modified using the Revit API. The ViewCropRegionShapeManager.Valid property indicates whether the view is allowed
to manage the crop region shape while the ShapeSet property indicates whether a shape has been set. The following example crops a view around the
boundary of a room.

Code Region: Cropping a view


1. public void CropAroundRoom(Room room, View view)
2. {
3. if (view != null)
4. {
5. IList<IList<Autodesk.Revit.DB.BoundarySegment>> segments = room.GetBoundarySegments(new SpatialElementBoundaryOptions());
6.
7. if (null != segments) //the room may not be bound
8. {
9. foreach (IList<Autodesk.Revit.DB.BoundarySegment> segmentList in segments)
10. {
11. CurveLoop loop = new CurveLoop();
12. foreach (Autodesk.Revit.DB.BoundarySegment boundarySegment in segmentList)
13. {
14. loop.Append(boundarySegment.Curve);
15. }
16.
17. ViewCropRegionShapeManager vcrShapeMgr = view.GetCropRegionShapeManager();
18. vcrShapeMgr.SetCropRegionShape(loop);
19. break; // if more than one set of boundary segments for room, crop around the first one
20. }
21. }
22. }
23. }
Displaced Views
Create a displaced view using the DisplacementElement class. DisplacementElement is a view-specific element that can be used to cause elements to appear
displaced from their actual location. Displaced views are useful to illustrate the relationship model elements have to the model as a whole. The
DisplacementElement does not actually change the location of any model elements; it merely causes them to be displayed in a different location.

For a detailed example of creating displaced views, see the DisplacementElementAnimation sample in the Revit SDK.

Creating a Displaced View

The static DisplacementElement.Create() method creates a new DisplacementElement. The new DisplacementElement may be a child of a
parent DisplacementElement if the parentDisplacementElement parameter is not null. If a parent is specified, the child DisplacementElement's transform will
be concatenated with that of the parent, and the displacement of its associated elements will be relative to the parent DisplacementElement.

The Create() method also requires a document, a list of elements to be displaced, the owner view, and the translation to be applied to the graphics of the
displaced elements. An element may only be displaced by a single DisplacementElement in any view. Assigning an element to more than one
DisplacementElement will result in an exception.

Other static methods of DisplacementElement can be used prior to calling Create() to help prevent any exceptions. CanCategoryBeDisplaced() tests whether
elements belonging to a specific category can be displaced, while the overloaded static method CanElementsBeDisplaced() indicates if specific elements may be
assigned to a new DisplacementElement. IsAllowedAsDisplacedElement() tests a single element for eligibility to be displaced.

The static GetAdditionalElementsToDisplace() method will return any additional elements that should be displaced along with the specified element in a
specified view. For example, when a wall is displaced, any inserts or hosted elements should also be displaced.

When creating a child DisplacementElement, the static IsValidAsParentInView() can be used to verify a specific DisplacementElement may be used as a parent
in a specific View.

Other static methods of DisplacementElement can be used to find the DisplacementElement that includes a specific element, to get a list of all displaced
elements in a View, or to get all the DisplacementElements owned by a specified View.

Working with Displaced Elements

Once a new DisplacementElement has been created, methods are available to obtain any child DisplacementElements, to get the ids of all elements affected by
the DisplacementElement, or to obtain the ids of all elements affected by the DisplacementElement as well as any child DisplacementElements. The ParentId
property will return the element id of the parent DisplacementElement, if there is one.

After creation, the set of elements affected by the DisplacementElement can be modified using SetDisplacedElementIds() or RemoveDisplacedElement().
Additionally, the relative displacement can be changed.

The method ResetDisplacedElements() will set the translation of the DisplacementElement to (0, 0, 0). The DisplacementElement continues to
exist, but its elements are displayed in their actual location.

Creating a Displaced Path

DisplacementPath is a view-specific annotation related to a DisplacementElement. The DisplacementPath class creates an annotation that depicts
the movement of the element from its actual location to its displaced location. The DisplacementPath is anchored to the DisplacementElement by
a reference to a point on an edge of a displaced element of the DisplacementElement. It is represented by a single line, or a series of jogged lines,
originating at the specified point on the displaced element.

The static DisplacementPath.Create() method requires a document, id of the associated DisplacementElement, a reference that refers to an edge
or curve of one of the elements displaced by the DisplacementElement, and a value in the range [0,1] that is a parameter along the edge specified.
Once created, the path style of the DisplacementPath can get set using the PathStyle property. The anchor point can also be changed
using SetAnchorPoint().

The associated DisplacementElement may have a parent DisplacementElement and this parent may have its own parent DisplacementElement,
producing a series of ancestors. The terminal point may be the point's original (un-displaced) location, or the corresponding point on any of the
intermediate displaced locations corresponding to these ancestor DisplacementElements. The DisplacementPath.AncestorIdx property specifies
the end point of the path.
UIView
While the View class is the base class for all view types in Revit and keeps tracks of elements in the view, the UIView class contains data about the view
windows in the Revit user interface. A list of all open views can be retrieved from the UIDocument using the GetOpenUIViews() method. The UIView class has
methods to get information about the views drawing area as well as to pan and zoom the active view.

UIView.GetWindowRectangle() returns a rectangle that describes the size and placement of the UIView window. It does not include the window border or title
bar.

Zoom Operations

UIView has several methods related to zooming the active view. UIView.GetZoomCorners() gets the corners of the view's rectangle in model coordinates and
UIView.ZoomAndCenterRectangle() offers the ability to zoom and pan the active view to center on the input region of the model.

The ZoomToFit() and ZoomSheetSize() methods provide quick ways to adjust the zoom of the window, while the Zoom() method can be used to zoom in or out
by a specified factor.

Closing a View

UIView.Close() can close a visible window. However, it cannot be used to close the last active window. Attempting to close the last active window will throw an
exception.
Revit Geometric Elements
Walls, Floors, Ceilings, Roofs and Openings
This chapter discusses Elements and the corresponding ElementTypes representing built-in place construction:

• HostObject - The first two sections focus on HostObject and corresponding HostObjAttributes subclasses

• Foundation - Different foundations in the API are represented as different classes, including Floor, ContFooting, and FamilyInstance.
The Floor and Foundation section compares them in the API.

• CompoundStructure - This section describes the CompoundStructure class and provides access to Material.

Some host element types have thermal properties which are described in the Thermal Properties section.

In addition to host Elements, the Opening class is introduced at the end of this section.

Walls
There are four kinds of Walls represented by the WallType.WallKind enumeration:

• Stacked

• Curtain

• Basic

• Unknown

The Wall and WallType class work with the Basic wall type while providing limited function to the Stacked and Curtain walls. On occasion you
need to check a Wall to determine the wall type. For example, you cannot get sub-walls from a Stacked Wall using the API. WallKind is read
only and set by System Family.

The Wall.Flipped property and Wall.flip() method gain access to and control Wall orientation. In the following examples, a Wall is compared
before and after calling the flip() method.

• The Orientation property before is (0.0, 1.0, 0.0).

• The Orientation property after the flip call is (0.0, -1.0, 0.0).

• The Wall Location Line (WALL_KEY_REF_PARAM) parameter is 3, which represents Finish Face: Interior in the following table.

• Taking the line as reference, the Wall is moved but the Location is not changed.

Figure 33: Original wall

Figure 34: Wall after flip

Table 24: Wall Location Line

Location Line Value Description

0 Wall Centerline

1 Core Centerline

2 Finish Face: Exterior

3 Finish Face: Interior

4 Core Face: Exterior

5 Core Face: Interior


There are five static override methods in the Wall class to create a Wall:

Table 25: Create() Overrides

Name Description

Create(Document, Curve, WallType, Level, Double, Double, Creates a new rectangular profile wall within the project using the specified wall type,
Boolean, Boolean) height, and offset.

Create(Document, IList<Curve>, Boolean) Creates a non rectangular profile wall within the project using the default wall style.

Create(Document, Curve, ElementId, Boolean) Creates a new rectangular profile wall within the project on the level specified by ElementId
using the default wall style.

Create(Document, IList<Curve>, ElementId, ElementId, Creates a non rectangular profile wall within the project using the specified wall type.
Boolean)

Create(Document, IList<Curve>, ElementId, ElementId, Creates a non rectangular profile wall within the project using the specified wall type and
Boolean, XYZ) normal vector.

The WallType Wall Function (WALL_ATTR_EXTERIOR) parameter influences the created wall instance Room Bounding and Structural Usage
parameter. The WALL_ATTR_EXTERIOR value is an integer:

Table 26: Wall Function

Wall Function Interior Exterior Foundation Retaining Soffit

Value 0 1 2 3 4

The following rules apply to Walls created by the API:

• If the input structural parameter is true or the Wall Function (WALL_ATTR_EXTERIOR) parameter is Foundation, the Wall
StructuralUsage parameter is Bearing; otherwise it is NonBearing.

• The created Wall Room Bounding (WALL_ATTR_ROOM_BOUNDING) parameter is false if the Wall Function (WALL_ATTR_EXTERIOR)
parameter is Retaining.

For more information about structure-related functions such as the AnalyticalModel property, refer to Revit Structure.

Floors, Ceilings and Foundations


Floor, Ceiling and Foundation-related API items include:

Table 28: Floors, Ceilings and Foundations in the API

Object Element Type ElementType Type Element Creation Other

Floor Floor FloorType NewFloor()/NewSlab() FloorType.IsFoundationSlab = false

Slab Floor FloorType NewSlab() FloorType.IsFoundationSlab = false

Ceiling Ceiling CeilingType No Category = OST_Ceilings

Wall Foundation ContFooting ContFootingType No Category = OST_StructuralFoundation

Isolated Foundation FamilyInstance FamilySymbol NewFamilyInstance() Category = OST_StructuralFoundation

Foundation Slab Floor FloorType NewFloor() Category = OST_StructuralFoundation


FloorType.IsFoundationSlab = true
Note: Floor and Ceiling derive from the class CeilingAndFloor.

The following rules apply to Floor:

• Elements created from the Foundation Design bar have the same category, OST_StructuralFoundation, but correspond to different
Classes.

• The FloorType IsFoundationSlab property sets the FloorType category to OST_StructuralFoundation or not.

When you retrieve FloorType to create a Floor or Foundation Slab with NewFloor, use the following methods:

Figure 35: Create foundation and floor/slab

Currently, the API does not provide access to the Floor Slope Arrow in the Floor class. However, in Revit Structure, you can create a sloped
slab with NewSlab():

Code Region 11-1: NewSlab()


1. public Floor NewSlab(CurveArray profile, Level level, Line slopedArrow, double slope,
2. bool isStructural);

The Slope Arrow is created using the slopedArrow parameter.

Figure 36: slopedArrow parameter in NewSlab

The unit for the slope parameter in NewSlab() is rise/run.

The Floor.FloorType property is an alternative to using the Floor.GetTypeId() method. For more information about structure-related
members such as the GetSpanDirectionSymbolIds() method and the SpanDirectionAngle property, refer to the Revit Structure chapter.
When editing an Isolated Foundation in Revit, you can perform the following actions:

• You can pick a host, such as a floor. However, the FamilyInstance object Host property always returns null.

• When deleting the host floor, the Foundation is not deleted with it.

• The Foundation host is available from the Host (INSTANCE_FREE_HOST_PARAM) parameter.

• Use another related Offset (INSTANCE_FREE_HOST_OFFSET_PARAM) parameter to control the foundation offset from the host
Element.

Figure 37: Pick Host for FoundationSlab (FamilyInstance)

Continuous footings are represented by the ContFooting class in the API. The API provides limited access to both ContFooting and ContFootingType except
when using the GetAnalyticalModel() method (refer to AnalyticalModel in the Revit Structure section). For example, the attached wall is not available in
Revit Architecture. In Revit Structure, the relationship between the Wall class and the ContFooting class is shown using the GetAnalyticalModelSupports()
method in the AnalyticalModel class. For more details, refer to AnalyticalModelSupport in the Revit Structure section.

Figure 38: Wall ContFooting

Modifying Slabs

You can modify the form of slab-based elements using the SlabShapeEditor class. This class allows you to:

• Manipulate one or more of the points or edges on a selected slab-based element

• Add points on the element to change the element's geometry

• Add linear edges and split the existing face of a slab into smaller sub-regions

• Remove the shape modifier and reset the element geometry back to the unmodified shape.
Here's an example of reverting a selected modified floor back to its original shape:

Code Region 11-2: Reverting a slab's shape


1. private void ResetSlabShapes(Autodesk.Revit.DB.Document document)
2. {
3. UIDocument uidoc = new UIDocument(document);
4. Selection choices = uidoc.Selection;
5. ElementSet collection = choices.Elements;
6. foreach (Autodesk.Revit.DB.Element elem in collection)
7. {
8. Floor floor = elem as Floor;
9. if (floor != null)
10. {
11. SlabShapeEditor slabShapeEditor = floor.SlabShapeEditor;
12. slabShapeEditor.ResetSlabShape();
13. }
14. }
15. }

For more detailed examples of using the SlabShapeEditor and related classes, see the SlabShapeEditing sample application included in the
Revit SDK.

Roofs
Roofs in the Revit Platform API all derive from the RoofBase object. There are two classes:

• FootPrintRoof - represents a roof made from a building footprint

• ExtrusionRoof - represents roof made from an extruded profile

Both have a RoofType property that gets or sets the type of roof. This example shows how you can create a footprint roof based on some
selected walls:

Code Region 11-3: Creating a footprint roof


// Before invoking this sample, select some walls to add a roof over.
// Make sure there is a level named "Roof" in the document.

// find the Roof level


FilteredElementCollector collector = new FilteredElementCollector(document);
collector.WherePasses(new ElementClassFilter(typeof(Level)));
var elements = from element in collector where element.Name == "Roof" select element;
Level level = elements.Cast<Level>().ElementAt<Level>(0);

RoofType rooftype = null;


// select the first rooftype
foreach (RoofType rt in document.RoofTypes)
{
rooftype = rt;
break;
}

// Get the handle of the application


Autodesk.Revit.ApplicationServices.Application application = document.Application;

// Define the footprint for the roof based on user selection


CurveArray footprint = application.Create.NewCurveArray();
UIDocument uidoc = new UIDocument(document);
if (uidoc.Selection.Elements.Size != 0)
{
foreach (Autodesk.Revit.DB.Element element in uidoc.Selection.Elements)
{
Wall wall = element as Wall;
if (wall != null)
{
LocationCurve wallCurve = wall.Location as LocationCurve;
footprint.Append(wallCurve.Curve);
continue;
}
ModelCurve modelCurve = element as ModelCurve;
if (modelCurve != null)
{
footprint.Append(modelCurve.GeometryCurve);
}
}
}
else
{
throw new Exception("You should select a curve loop, or a wall loop, or loops combination \nof walls and curves to create
a footprint roof.");
}

ModelCurveArray footPrintToModelCurveMapping = new ModelCurveArray();


FootPrintRoof footprintRoof = document.Create.NewFootPrintRoof(footprint, level, rooftype, out footPrintToModelCurveMapping);
ModelCurveArrayIterator iterator = footPrintToModelCurveMapping.ForwardIterator();
iterator.Reset();
while (iterator.MoveNext())
{
ModelCurve modelCurve = iterator.Current as ModelCurve;
footprintRoof.set_DefinesSlope(modelCurve, true);
footprintRoof.set_SlopeAngle(modelCurve, 0.5);
}

For an example of how to create an ExtrusionRoof, see the NewRoof sample application included with the Revit API SDK.

Gutter and Fascia

Gutter and Fascia elements are derived from the HostedSweep class, which represents a roof. They can be created, deleted or modified via
the API. To create these elements, use one of the Document.Create.NewFascia() or Document.Create.NewGutter() overrides. For an example
of how to create new gutters and fascia, see the NewHostedSweep application included in the SDK samples. Below is a code snippet showing
you can modify a gutter element's properties.

Code Region 11-4: Modifying a gutter


public void ModifyGutter(Autodesk.Revit.DB.Document document)
{
UIDocument uidoc = new UIDocument(document);
ElementSet collection = uidoc.Selection.Elements;

foreach (Autodesk.Revit.DB.Element elem in collection)


{
if (elem is Gutter)
{
Gutter gutter = elem as Gutter;
// convert degrees to rads:
gutter.Angle = 45.00 * Math.PI / 180;
TaskDialog.Show("Revit","Changed gutter angle");
}
}
}

Curtains
Curtain walls, curtain systems, and curtain roofs are host elements for CurtainGrid objects. A curtain wall can have only one CurtainGrid,
while curtain systems and curtain roofs may contain one or more CurtainGrids. For an example of how to create a CurtainSystem, see the
CurtainSystem sample application included with the Revit SDK. For an example of creating a curtain wall and populating it with grid lines,
see the CurtainWallGrid sample application.

Other Elements
Some Elements are not HostObjects (and don't have a specific class), but are special cases that can host other objects. For example, ramp
and its associated element type, do not have specific classes in the API and instead are represented as Element and ElementType in the
OST_Ramps category.
CompoundStructure
Walls, floors, ceilings and roofs are all children of the API class HostObject. HostObject (and its related type class HostObjAttributes) provide read only access
to the CompoundStructure.

The CompoundStructure class offers read and write access to a set of layers consisting of different materials:

CompoundStructure.GetLayers()
CompoundStructure.SetLayers()

Normally these layers are parallel and extend the entire host object with a fixed layer width. However, for walls the structure can also be “vertically
compound”, where the layers vary at specified vertical distances from the top and bottom of the wall. Use CompoundStructure.IsVerticallyCompound to
identify these. For vertically compound structures, the structure describes a vertical section via a rectangle which is divided into polygonal regions whose sides
are all vertical or horizontal segments. A map associates each of these regions with the index of a layer in the CompoundStructure which determines the
properties of that region.

It is possible to use the compound structure to find the geometric location of different layer boundaries. The method
CompoundStructure.GetOffsetForLocationLine() provides the offset from the center location line to any of the location line options (core centerline, finish faces
on either side, or core sides).

With the offset to the location line available, you can obtain the location of each layer boundary by starting from a known location and obtaining the widths of
each bounding layer using CompoundStructure.GetLayerWidth().

Some notes about the use of CompoundStructure:

The total width of the element is the sum of each CompoundStructureLayer's widths. You cannot change the element's total width directly but you can change
it via changing the CompoundStructureLayer width. The index of the designated variable length layer (if assigned) can be obtained from
CompoundStructure.VariableLayerIndex.

You must set the CompoundStructure back to the HostObjAttributes instance (using the HostObjAttributes.SetCompoundStructure() method) in order for any
change to be stored.

Changes to the HostObjAttributes affects every instance in the current document. If you need a new combination of layers,you will need to create a new
HostObjAttributes (use ElementType.Duplicate()) and assign the new CompoundStructure to it.

The CompoundStructureLayer DeckProfileId, and DeckEmbeddingType, properties only work with Slab in Revit Structure. For more details, refer to Revit
Structure.

Material

Each CompoundStructureLayer in HostObjAttributes is typically displayed with some type of material. If CompoundStructureLayer.MaterialId returns -1, it
means the Material is Category-related. For more details, refer to Material. Getting the CompoundStructureLayer Material is illustrated in the following sample
code:

Code Region 11-5: Getting the CompoundStructureLayer Material


1. public void GetWallLayerMaterial(Autodesk.Revit.DB.Document document, Wall wall)
2. {
3. // get WallType of wall
4. WallType aWallType = wall.WallType;
5. // Only Basic Wall has compoundStructure
6. if (WallKind.Basic == aWallType.Kind)
7. {
8.
9. // Get CompoundStructure
10. CompoundStructure comStruct = aWallType.GetCompoundStructure();
11. Categories allCategories = document.Settings.Categories;
12.
13. // Get the category OST_Walls default Material;
14. // use if that layer's default Material is <By Category>
15. Category wallCategory = allCategories.get_Item(BuiltInCategory.OST_Walls);
16. Autodesk.Revit.DB.Material wallMaterial = wallCategory.Material;
17.
18. foreach (CompoundStructureLayer structLayer in comStruct.GetLayers())
19. {
20. Autodesk.Revit.DB.Material layerMaterial =
21. document.GetElement(structLayer.MaterialId) as Material;
22.
23. // If CompoundStructureLayer's Material is specified, use default
24. // Material of its Category
25. if (null == layerMaterial)
26. {
27. switch (structLayer.Function)
28. {
29. case MaterialFunctionAssignment.Finish1:
30. layerMaterial =
31. allCategories.get_Item(BuiltInCategory.OST_WallsFinish1).Material;
32. break;
33. case MaterialFunctionAssignment.Finish2:
34. layerMaterial =
35. allCategories.get_Item(BuiltInCategory.OST_WallsFinish2).Material;
36. break;
37. case MaterialFunctionAssignment.Membrane:
38. layerMaterial =
39. allCategories.get_Item(BuiltInCategory.OST_WallsMembrane).Material;
40. break;
41. case MaterialFunctionAssignment.Structure:
42. layerMaterial =
43. allCategories.get_Item(BuiltInCategory.OST_WallsStructure).Material;
44. break;
45. case MaterialFunctionAssignment.Substrate:
46. layerMaterial =
47. allCategories.get_Item(BuiltInCategory.OST_WallsSubstrate).Material;
48. break;
49. case MaterialFunctionAssignment.Insulation:
50. layerMaterial =
51. allCategories.get_Item(BuiltInCategory.OST_WallsInsulation).Material;
52. break;
53. default:
54. // It is impossible to reach here
55. break;
56. }
57. if (null == layerMaterial)
58. {
59. // CompoundStructureLayer's default Material is its SubCategory
60. layerMaterial = wallMaterial;
61. }
62. }
63. TaskDialog.Show("Revit","Layer Material: " + layerMaterial);
64. }
65. }
66. }

Sometimes just the material from the "structural" layer is needed. Rather than looking at each layer for the one whose function is
MaterialFunctionAssignment.Structure, use the CompoundStructure.StructuralMaterialIndex property to find the index of the layer whose material defines the
structural properties of the type for the purposes of analysis.

Opening
In the Revit Platform API, the Opening object is derived from the Element object and contains all of the Element object properties and
methods. To retrieve all Openings in a project, use Document.ElementIterator to find the Elements.Opening objects.

General Properties

This section explains how to use the Opening properties.

• IsRectBoundary - Identifies whether the opening has a rectangular boundary.

o If true, it means the Opening has a rectangular boundary and you can get an IList<XYZ> collection from the Opening
BoundaryRect property. Otherwise, the property returns null.

o If false, you can get a CurveArray object from the BoundaryCurves property.

• BoundaryCurves - If the opening boundary is not a rectangle, this property retrieves geometry information; otherwise it returns null.
The property returns a CurveArray object containing the curves that represent the Opening object boundary.
For more details about Curve, refer to Geometry.

• BoundaryRect - If the opening boundary is a rectangle, you can get the geometry information using this property; otherwise it returns
null.

o The property returns an IList<XYZ> collection containing the XYZ coordinates.

o The IList<XYZ> collection usually contains the rectangle boundary minimum (lower left) and the maximum (upper right)
coordinates.

• Host - The host property retrieves the Opening host element. The host element is the element cut by the Opening object.

Note If the Opening object's category is Shaft Openings, the Opening host is null.

The following example illustrates how to retrieve the existing Opening properties.
Code Region 11-6: Retrieving existing opening properties
1. private void Getinfo_Opening(Opening opening)
2. {
3. string message = "Opening:";
4.
5. //get the host element of this opening
6. message += "\nThe id of the opening's host element is : " + opening.Host.Id.IntegerValue;
7.
8. //get the information whether the opening has a rect boundary
9. //If the opening has a rect boundary, we can get the geometry information from BoundaryRect property.
10. //Otherwise we should get the geometry information from BoundaryCurves property
11. if (opening.IsRectBoundary)
12. {
13. message += "\nThe opening has a rectangular boundary.";
14. //array contains two XYZ objects: the max and min coords of boundary
15. IList<XYZ> boundaryRect = opening.BoundaryRect;
16.
17. //get the coordinate value of the min coordinate point
18. XYZ point = opening.BoundaryRect[0];
19. message += "\nMin coordinate point:(" + point.X + ", "
20. + point.Y + ", " + point.Z + ")";
21.
22. //get the coordinate value of the Max coordinate point
23. point = opening.BoundaryRect[1];
24. message += "\nMax coordinate point: (" + point.X + ", "
25. + point.Y + ", " + point.Z + ")";
26. }
27. else
28. {
29. message += "\nThe opening doesn't have a rectangular boundary.";
30. // Get curve number
31. int curves = opening.BoundaryCurves.Size;
32. message += "\nNumber of curves is : " + curves;
33. for (int i = 0; i < curves; i++)
34. {
35. Autodesk.Revit.DB.Curve curve = opening.BoundaryCurves.get_Item(i);
36. // Get curve start point
37. message += "\nCurve start point: " + XYZToString(curve.GetEndPoint(0));
38. // Get curve end point
39. message += "; Curve end point: " + XYZToString(curve.GetEndPoint(1));
40. }
41. }
42. TaskDialog.Show("Revit",message);
43. }
44.
45. // output the point's three coordinates
46. string XYZToString(XYZ point)
47. {
48. return "(" + point.X + ", " + point.Y + ", " + point.Z + ")";
49. }

Create Opening

In the Revit Platform API, use the Document.NewOpening() method to create an opening in your project. There are four method overloads
you can use to create openings in different host elements:

Code Region 11-7: NewOpening()


//Create a new Opening in a beam, brace and column.
public Opening NewOpening(Element famInstElement, CurveArray profile, eRefFace iFace);
//Create a new Opening in a roof, floor and ceiling.
public Opening NewOpening(Element hostElement, CurveArray profile, bool bPerpendicularFace);
//Create a new Opening Element.
public Opening NewOpening(Level bottomLevel, Level topLevel, CurveArray profile);
//Create an opening in a straight wall or arc wall.
public Opening NewOpening(Wall, XYZ pntStart, XYZ pntEnd);

• Create an Opening in a Beam, Brace, or Column - Use to create an opening in a family instance. The iFace parameter indicates the
face on which the opening is placed.

• Create a Roof, Floor, or Ceiling Opening - Use to create an opening in a roof, floor, or ceiling.

• The bPerpendicularFace parameter indicates whether the opening is perpendicular to the face or vertical.

• If the parameter is true, the opening is perpendicular to the host element face. See the following picture:
Figure 39: Opening cut perpendicular to the host element face

Figure 40: Opening cut vertically to the host element

• Create a New Opening Element - Use to create a shaft opening in your project. However, make sure the topLevel is higher than the
bottomLevel; otherwise an exception is thrown.

• Create an Opening in a Straight Wall or Arc Wall - Use to create a rectangle opening in a wall. The coordinates of pntStart and pntEnd
should be corner coordinates that can shape a rectangle. For example, the lower left corner and upper right corner of a rectangle.
Otherwise an exception is thrown.
NoteUsing the Opening command you can only create a rectangle shaped wall opening. To create some holes in a wall, edit the wall profile
instead of the Opening command.
Thermal Properties
Certain assembly types such as Wall, Floor, Ceiling, Roof and Building Pad have calculated and settable thermal properties which are represented by the
ThermalProperties class.

The ThermalProperties class has properties for the values shown above. Absorptance and Roughness are modifiable while HeatTransferCoefficient,
ThermalResistance, and ThermalMass are read-only. The units for these calculated values are shown in the table below.

Property Unit

watts per meter-squared kelvin


HeatTransferCoefficient
(W/(m^2*K)

meter-squared kelvin per watt


ThermalResistance
((m^2*K)/Watt)

kilogram feet-squared per second squared kelvin


ThermalMass
(kg ft^2/(s^2 K))
Thermal properties can be retrieved using the ThermalProperties property on the following types:

WallType

FloorType

CeilingType

RoofType

BuildingPadType
Family Instances
In this section, you will learn about the following:

• The relationship between family and family instance

• Family and family instance features

• How to load or create family and family instance features

• The relationship between family instance and family symbol

Identifying Elements
In Revit, the easiest way to judge whether an element is a FamilyInstance or not is by using the properties dialog box.

• If the family name starts with System Family and the Load button is disabled, it belongs to System Family.

Figure 41: System Family

• A general FamilyInstance, which belongs to the Component Family, does not start with System Family.

• For example, in the following picture the family name for the desk furniture is Desk. In addition, the Load button is enabled.

Figure 42: Component Family

• There are some exceptions, for example: Mass and in-place member. The Family and Type fields are blank.

Figure 43: Mass or in-place member example

Families in the Revit Platform API are represented by three objects:

• Family

• FamilySymbol

• FamilyInstance

Each object plays a significant role in the family structure.

The Family object represents an entire family such as Single-Flush doors. For example, the Single-Flush door Family corresponds to the
Single-Flush.rfa file. The Family object contains several FamilySymbols that are used to get all family symbols to facilitate swapping
instances from one symbol to another.
The FamilySymbol object represents a specific set of family settings corresponding to a Type in the Revit UI, such as 34"×80".

The FamilyInstance object represents an actual Type (FamilySymbol) instance in the Revit project. For example, in the following picture, the
FamilyInstance is a single door in the project.

• Each FamilyInstance has one FamilySymbol. The door is an instance of a 34"×80".

• Each FamilySymbol belongs to one Family. The 34"×80" symbol belongs to a Single-Flush family.

• Each Family contains one or more FamilySymbols. The Single-Flush family contains a 34"×80" symbol, a 34"×84" symbol, a 36"×84"
and so on.

Note that while most component elements are exposed through the API classes FamilySymbol and FamilyInstance, some have been wrapped
with specific API classes. For example, AnnotationSymbolType wraps FamilySymbol and AnnotationSymbol wraps FamilyInstance.

Family
The Family class represents an entire Revit family. It contains the FamilySymbols used by FamilyInstances.

Loading Families

The Document class contains the LoadFamily() and LoadFamilySymbol() methods.

• LoadFamily() loads an entire family and all of its types or symbols into the project.

• LoadFamilySymbol() loads only the specified family symbol from a family file into the project.
NoteTo improve the performance of your application and reduce memory usage, if possible load specific FamilySymbols instead of entire
Family objects.

• The family file path is retrieved using the Options.Application object GetLibraryPaths() method.

• The Options.Application object is retrieved using the Application object Options property.

• In LoadFamilySymbol(), the input argument Name is the same string value returned by the FamilySymbol object Name property.

For more information, refer to Code Samples.

Categories

The FamilyBase.FamilyCategory property indicates the category of the Family such as Columns, Furniture, Structural Framing, or Windows.

FamilyInstances
Examples of categories of FamilyInstance objects in Revit are Beams, Braces, Columns, Furniture, Massing, and so on. The FamilyInstance
object provides more detailed properties so that the family instance type and appearance in the project can be changed.

Location-Related Properties

Location-related properties show the physical and geometric characteristics of FamilyInstance objects, such as orientation, rotation and
location.

Orientation

The face orientation or hand orientation can be changed for some FamilyInstance objects. For example, a door can face the outside or the
inside of a room or wall and it can be placed with the handle on the left side or the right side. The following table compares door, window,
and desk family instances.

Table 29: Compare Family Instances

Boolean Property Door Window (Fixed: 36"w × 72"h) Desk

CanFlipFacing True True False

CanFlipHand True False False

If CanFlipFacing or CanFlipHand is true, you can call the flipFacing() or flipHand() methods respectively. These methods can change the
facing orientation or hand orientation respectively. Otherwise, the methods do nothing and return False.

When changing orientation, remember that some types of windows can change both hand orientation and facing orientation, such as a
Casement 3x3 with Trim family.
There are four different facing orientation and hand orientation combinations for doors. See the following picture for the combinations and
the corresponding Boolean values are in the following table.

Figure 44: Doors with different Facing and Hand Orientations

Table 30: Different Instances of the Same Type

Boolean Property Door 1 Door 2 Door 3 Door 4

FacingFlipped False True False True

HandFlipped False True True False

Orientation - Work Plane

The work plane orientation for a FamilyInstance can be changed, as well. If CanFlipWorkPlane is true, you can set the IsWorkPlaneFlipped
property. Attempting to set this property for a FamilyInstance that does not allow the work plane to be flipped will result in an exception.

Rotation - Mirrored

The Mirrored property indicates whether the FamilyInstance object has been mirrored.

Table 31: Door Mirrored Property

Boolean Property Door 1 Door 2 Door 3 Door 4

Mirrored False False True True

In the previous door example, the Mirrored property for Door 1 and Door 2 is False, while for both Door 3 and Door 4 it is True. This is
because when you create a door in the Revit project, the default result is either Door 1 or Door 2. To create a door like Door 3 or Door 4,
you must flip the Door 1 and Door 2 hand orientation respectively. The flip operation is like a mirror transformation, which is why the Door 3
and Door 4 Mirrored property is True.

For more information about using the Mirror() method in Revit, refer to the Editing Elements chapter.

Rotation - CanRotate and rotate()

The family instance Boolean CanRotate property is used to test whether the family instance can be rotated 180 degrees. This depends on the
family to which the instance belongs. For example, in the following picture, the CanRotate properties for Window 1 (Casement 3×3 with
Trim: 36"×72") and Door 1 (Double-Glass 2: 72"×82") are true, while Window 2 (Fixed: 36"w × 72"h) is false.
Figure 45: Changes after rotate()

If CanRotate is true, you can call the family instance rotate() method, which flips the family instance by 180 degrees. Otherwise, the method
does nothing and returns False. The previous picture also shows the Window 1 and Door 1 states after executing the rotate() method.

Recall from the Rotating elements section earlier in this document, that family instances (and other elements) can be rotated a user-
specified angle usingElementTransformUtils.RotateElement() and ElementTransformUtils.RotateElements().

Location

The Location property determines the physical location of an instance in a project. An instance can have a point location or a line location.

The following characteristics apply to Location:

• A point location is a LocationPoint class object - A footing, a door, or a table has a point location
• A line location is a LocationCurve class object - A beam has a line location.
• They are both subclasses of the Location class.

For more information about Location, refer to Editing Elements.

Host and HostFace

Host and HostFace are both FamilyInstance properties.

Host

A FamilyInstance object has a Host property that returns its hosting element.

Some FamilyInstance objects do not have host elements, such as Tables and other furniture, so the Host property returns nothing because
no host elements are created. However, other objects, such as doors and windows, must have host elements. In this case the Host property
returns a wall Element in which the window or the door is located. See the following picture.
Figure 46: Doors and windows hosted in a wall

HostFace

The HostFace property gets the reference to the host face of the family instance, or if the instance is placed on a work plane, the reference
to the geometry face underlying the work plane. This property will return a null reference if the work plane is not referencing other
geometry, or if the instance is not hosted on a face or work plane.

Subcomponent and Supercomponent

The FamilyInstance.GetSubComponentIds() method returns the ElementIds of family instances loaded into that family. When an instance of
'Table-Dining Round w Chairs.rfa' is placed in a project, the ElementIds of the set of chairs are returned by the
GetSubComponentIds() method.

The SuperComponent property returns the family instance's parent component. In 'Table-Dining Round w Chairs.rfa', the family instance
supercomponent for each nested chair is the instance of 'Table-Dining Round w Chairs.rfa'.

Code Region 12-1: Getting SubComponents and SuperComponent from FamilyInstance


1. public void GetSubAndSuperComponents(FamilyInstance familyInstance)
2. {
3. ICollection<ElementId> subElemSet = familyInstance.GetSubComponentIds();
4. if (subElemSet != null)
5. {
6. string subElems = "";
7. foreach (Autodesk.Revit.DB.ElementId ee in subElemSet)
8. {
9. FamilyInstance f = familyInstance.Document.GetElement(ee) as FamilyInstance;
10. subElems = subElems + f.Name + "\n";
11. }
12. TaskDialog.Show("Revit","Subcomponent count = " + subElemSet.Count + "\n" + subElems);
13. }
14. FamilyInstance super = familyInstance.SuperComponent as FamilyInstance;
15. if (super != null)
16. {
17. TaskDialog.Show("Revit","SUPER component: " + super.Name);
18. }
19. }

Other Properties

The properties in this section are specific to Revit Architecture and Revit Structure. They are covered thoroughly in their respective chapters.

Room Information

FamilyInstance properties include Room, FromRoom, and ToRoom. For more information about Room, refer to Revit Architecture.
Space Information

FamilyInstance has a Space property for identifying the space that holds an instance in MEP.

Revit Structure Related Analytical Model

The GetAnalyticalModel() method retrieves the family instance structural analytical model.

For more information about AnalyticalModel refer to Revit Structure.

Creating FamilyInstance Objects

Typically a FamilyInstance object is created using one of the twelve overload methods of Autodesk.Revit.Creation.Document called
NewFamilyInstance(). The choice of which overload to use depends not only on the category of the instance, but also other characteristics of
the placement like whether it should be hosted, placed relative to a reference level, or placed directly on a particular face. The details are
included in Table 32 - Options for creating instance with NewFamilyInstance() below.

Some FamilyInstance objects require more than one location to be created. In these cases, it is more appropriate to use the more detailed
creation method provided by this object (see Table 33 - Options for creating instances with other methods below). If the instance is not
created, an exception is thrown. The type/symbol used must be loaded into the project before the method is called.
Table 32 - Options for creating instance with NewFamilyInstance()

Category NewFamilyInstance() parameters Comments

Air Terminals XYZ, FamilySymbol, StructuralType Creates the instance in an arbitrary location without reference to a level or host element.
Boundary Conditions
XYZ, FamilySymbol, Element, If it is to be hosted on a wall, floor or ceiling
Casework
StructuralType
Communication Devices
Data Devices XYZ, FamilySymbol, XYZ, Element, If it is to be hosted on a wall, floor, or ceiling, and needs to be oriented in a non-default
Electrical Equipment StructuralType direction

Electrical Fixtures XYZ, FamilySymbol, Element, Level, If it is to be hosted on a wall, floor or ceiling and associated to a reference level
Entourage StructuralType
Fire Alarm Devices
XYZ, FamilySymbol, Level, If it is to be associated to a reference level
Furniture
StructuralType
Furniture Systems
Generic Models Face, XYZ, XYZ, FamilySymbol If it is face-based and needs to be oriented in a non-default direction
Lighting Devices Reference, XYZ, XYZ, FamilySymbol If it is face-based and needs to be oriented in a non-default direction, accepts a reference
Lighting Fixtures to a face rather than a Face
Mass
Face, Line, FamilySymbol If it is face-based and linear
Mechanical Equipment
Nurse Call Devices Reference, Line, FamilySymbol If it is face-based and linear, but accepts a reference to a face, rather than a Face
Parking
Planting
Plumbing Fixtures
Security Devices
Site
Specialty Equipment
Sprinklers
Structural Connections
Structural Foundations
Structural Stiffeners
Telephone Devices

Columns XYZ, FamilySymbol, Level, Creates the column so that its base lies on the reference level. The column will extend to
Structural Columns StructuralType the next available level in the model, or will extend the default column height if there are
no suitable levels above the reference level.

Doors XYZ, FamilySymbol, Element, Doors and windows must be hosted by a wall. Use this method if they can be placed with
Windows StructuralType the default orientation.

XYZ, FamilySymbol, XYZ, Element, If the created instance needs to be oriented in a non-default direction
StructuralType

XYZ, FamilySymbol, Element, Level, If the instance needs to be associated to a reference level
StructuralType

Structural Framing Curve, FamilySymbol, Level, Creates a level based brace or beam given its curve. This is the recommended method to
(Beams, Braces) StructuralType create Beams and Braces

XYZ, FamilySymbol, StructuralType Creates instance in an arbitrary location1

XYZ, FamilySymbol, Element, Level, If it is hosted on an element (floor etc.) and associated to a reference level 1
StructuralType

XYZ, FamilySymbol, Level, If it is associated to a reference level 1


StructuralType

XYZ, FamilySymbol, Element, If it is hosted on an element (floor etc.) 1


StructuralType

Detail Component Line, FamilySymbol, View Applies only to 2D family line based detail symbols
Generic Annotations XYZ, FamilySymbol, View Applies only to 2D family symbols

1
The structural instance will be of zero-length after creation. Extend it by setting its curve (FamilyInstance.Location as LocationCurve) using
LocationCurve.Curve property.

You can simplify your code and improve performance by creating more than one family instance at a time using
Document.NewFamilyInstances(). This method has a single parameter, which is a list of FamilyInstanceCreationData objects describing the
family instances to create.

Code Region 12-2: Batch creating family instances


1. ICollection<ElementId> BatchCreateColumns(Autodesk.Revit.DB.Document document, Level level)
2. {
3. List<FamilyInstanceCreationData> fiCreationDatas = new List<FamilyInstanceCreationData>();
4.
5. ICollection<ElementId> elementSet = null;
6.
7. //Try to get a FamilySymbol
8. FamilySymbol familySymbol = null;
9. FilteredElementCollector collector = new FilteredElementCollector(document);
10. ICollection<Element> collection = collector.OfClass(typeof(FamilySymbol)).ToElements();
11. foreach (Element e in collection)
12. {
13. familySymbol = e as FamilySymbol;
14. if (null != familySymbol.Category)
15. {
16. if ("Structural Columns" == familySymbol.Category.Name)
17. {
18. break;
19. }
20. }
21. }
22.
23. if (null != familySymbol)
24. {
25. //Create 10 FamilyInstanceCreationData items for batch creation
26. for (int i = 1; i < 11; i++)
27. {
28. XYZ location = new XYZ(i * 10, 100, 0);
29. FamilyInstanceCreationData fiCreationData = new FamilyInstanceCreationData(location, familySymbol, level,
30. StructuralType.Column);
31. if (null != fiCreationData)
32. {
33. fiCreationDatas.Add(fiCreationData);
34. }
35. }
36.
37. if (fiCreationDatas.Count > 0)
38. {
39. // Create Columns
40. elementSet = document.Create.NewFamilyInstances2(fiCreationDatas);
41. }
42. else
43. {
44. throw new Exception("Batch creation failed.");
45. }
46. }
47. else
48. {
49. throw new Exception("No column types found.");
50. }
51.
52. return elementSet;
53. }

Instances of some family types are better created through methods other than Autodesk.Revit.Creation.Document.NewFamilyInstance().
These are listed in the table below.
Table 33 - Options for creating instances with other methods

Category Creation method Comments

Air Terminal Tags NewTag(View, Element, Boolean, TagMode should be TM_ADDBY_CATEGORY and there should be a related tag
Area Load Tags TagMode, TagOrientation, XYZ) family loaded when try to create a tag, otherwise exception will be thrown
Area Tags
Casework Tags
Ceiling Tags
Communication Device Tags
Curtain Panel Tags
Data Device Tags
Detail Item Tags
Door Tags
Duct Accessory Tags
Duct Fitting Tags
Duct Tags
Electrical Equipment Tags
Electrical Fixture Tags
Fire Alarm Device Tags
Flex Duct Tags
Flex Pipe Tags
Floor Tags
Furniture System Tags
Furniture Tags
Generic Model Tags
Internal Area Load Tags
Internal Line Load Tags
Internal Point Load Tags
Keynote Tags
Lighting Device Tags
Lighting Fixture Tags
Line Load Tags
Mass Floor Tags
Mass Tags
Mechanical Equipment Tags
Nurse Call Device Tags
Parking Tags
Pipe Accessory Tags
Pipe Fitting Tags
Pipe Tags
Planting Tags
Plumbing Fixture Tags
Point Load Tags
Property Line Segment Tags
Property Tags
Railing Tags
Revision Cloud Tags
Roof Tags
Room Tags
Security Device Tags
Site Tags
Space Tags
Specialty Equipment Tags
Spinkler Tags
Stair Tags
Structural Area Reinforcement
Tags
Structural Beam System Tags
Structural Column Tags
Structural Connection Tags
Structural Foundation Tags
Structural Framing Tags
Structural Path Reinforcement
Tags
Structural Rebar Tags
Structural Stiffener Tags
Structural Truss Tags
Telephone Device Tags
Wall Tags
Window Tags
Wire Tag
Zone Tags

Material Tags NewTag(View, Element, Boolean, TagMode should be TM_ADDBY_MATERIAL and there should be a material tag
TagMode, TagOrientation, XYZ) family loaded, otherwise exception will be thrown

Multi-Category Tags NewTag(View, Element, Boolean, TagMode should be TM_ADDBY_MULTICATEGORY, and there should be a
TagMode, TagOrientation, XYZ) multi-category tag family loaded, otherwise exception will be thrown

Title Blocks NewViewSheet(FamilySymbol) The titleblock will be added to the newly created sheet.

Families and family symbols are loaded using the Document.LoadFamily() or Document.LoadFamilySymbol() methods. Some families, such
as Beams, have more than one endpoint and are inserted in the same way as a single point instance. Once the linear family instances are
inserted, their endpoints can be changed using the Element.Location property. For more information, refer to Code Samples.

Code Samples
Review the following code samples for more information about working with Family Instances. Please note that in the NewFamilyInstance()
method, a StructuralType argument is required to specify the type of the family instance to be created. Here are some examples:

Table 34: The value of StructuralType argument in the NewFamilyInstance() method

Type of Family Instance Value of StructuralType

Doors, tables, etc. NonStructural

Beams Beam

Braces Brace

Columns Column

Footings Footing

Create Tables

The following function demonstrates how to load a family of Tables into a Revit project and create instances from all symbols in this family.

The LoadFamily() method returns false if the specified family was previously loaded. Therefore, in the following case, do not load the family,
Table-Dining Round w Chairs.rfa, before this function is called. In this example, the tables are created at Level 1 by default.

Code Region 12-3: Creating tables


String fileName = @"C:\Documents and Settings\All Users\Application Data\Autodesk\RST 2011\Imperial Library\Furniture\Table-
Dining Round w Chairs.rfa";
// try to load family
Family family = null;
if (!document.LoadFamily(fileName, out family))
{
throw new Exception("Unable to load " + fileName);
}
// Loop through table symbols and add a new table for each
FamilySymbolSetIterator symbolItor = family.Symbols.ForwardIterator();
double x = 0.0, y = 0.0;
while (symbolItor.MoveNext())
{
FamilySymbol symbol = symbolItor.Current as FamilySymbol;
XYZ location = new XYZ(x, y, 10.0);
// Do not use the overloaded NewFamilyInstance() method that contains
// the Level argument, otherwise Revit cannot show the instances
// correctly in 3D View, for the table is not level-based component.
FamilyInstance instance = document.Create.NewFamilyInstance(location, symbol, StructuralType.NonStructural);

x += 10.0;
}

The result of loading the Tables family and placing one instance of each FamilySymbol:

Figure 47: Load family and create tables in the Revit project
Create a Beam

In this sample, a family symbol is loaded instead of a family, because loading a single FamilySymbol is faster than loading a Family that
contains many FamilySymbols.

Code Region 12-4: Creating a beam


// get the active view's level for beam creation
Level level = document.ActiveView.Level;

// load a family symbol from file


FamilySymbol gotSymbol = null;
String fileName = @"C:\Documents and Settings\All Users\Application Data\Autodesk\RST 2011\Imperial
Library\Structural\Framing\Steel\W-Wide Flange.rfa";
String name = "W10X54";

FamilyInstance instance = null;

if (document.LoadFamilySymbol(fileName, name, out gotSymbol))


{
// look for a model line in the list of selected elements
UIDocument uidoc = new UIDocument(document);
ElementSet sel = uidoc.Selection.Elements;
ModelLine modelLine = null;
foreach (Autodesk.Revit.DB.Element elem in sel)
{
if (elem is ModelLine)
{
modelLine = elem as ModelLine;
break;
}
}
if (null != modelLine)
{
// create a new beam
instance = document.Create.NewFamilyInstance(modelLine.GeometryCurve, gotSymbol, level, StructuralType.Beam);
}
else
{
throw new Exception("Please select a model line before invoking this command");
}

}
else
{
throw new Exception("Couldn't load " + fileName);
}
Create Doors

Create a long wall about 180' in length and select it before running this sample. The host object must support inserting instances; otherwise
the NewFamilyInstance() method will fail. If a host element is not provided for an instance that must be created in a host, or the instance
cannot be inserted into the specified host element, the method NewFamilyInstance() does nothing.

Code Region 12-5: Creating doors


void CreateDoorsInWall(Autodesk.Revit.DB.Document document, Wall wall)
{
String fileName = @"C:\Documents and Settings\All Users\Application Data\Autodesk\RST 2011\Imperial Library\Doors\Single-
Decorative 2.rfa";

Family family = null;


if (!document.LoadFamily(fileName, out family))
{
throw new Exception("Unable to load " + fileName);
}

// get the active view's level for beam creation


Level level = document.ActiveView.Level;

FamilySymbolSetIterator symbolItor = family.Symbols.ForwardIterator();


double x = 0, y = 0, z = 0;
while (symbolItor.MoveNext())
{
FamilySymbol symbol = symbolItor.Current as FamilySymbol;
XYZ location = new XYZ(x, y, z);
FamilyInstance instance = document.Create.NewFamilyInstance(location, symbol, wall, level,
StructuralType.NonStructural);
x += 10;
y += 10;
z += 1.5;
}
}

The result of the previous code in Revit is shown in the following picture. Notice that if the specified location is not at the specified level, the
NewFamilyInstance() method uses the location elevation instead of the level elevation.

Figure 48: Insert doors into a wall


Create FamilyInstances Using Reference Directions

Use reference directions to insert an item in a specific direction.

Code Region 12-6: Creating FamilyInstances using reference directions


String fileName = @"C:\Documents and Settings\All Users\Application Data\Autodesk\RST 2011\Imperial Library\Furniture\Bed-
Box.rfa";

Autodesk.Revit.DB.Family family = null;


if (!document.LoadFamily(fileName, out family))
{
throw new Exception("Couldn't load " + fileName);
}

FilteredElementCollector collector = new FilteredElementCollector(document);


Floor floor = collector.OfClass(typeof(Floor)).FirstElement() as Floor;
if (floor != null)
{
FamilySymbolSetIterator symbolItor = family.Symbols.ForwardIterator();
int x = 0, y = 0;
int i = 0;
while (symbolItor.MoveNext())
{
FamilySymbol symbol = symbolItor.Current as FamilySymbol;
XYZ location = new XYZ(x, y, 0);
XYZ direction = new XYZ();
switch (i % 3)
{
case 0:
direction = new XYZ(1, 1, 0);
break;
case 1:
direction = new XYZ(0, 1, 1);
break;
case 2:
direction = new XYZ(1, 0, 1);
break;
}
FamilyInstance instance = document.Create.NewFamilyInstance(location, symbol, direction, floor,
StructuralType.NonStructural);
x += 10;
i++;
}
}
else
{
throw new Exception("Please open a model with at least one floor element before invoking this command.");
}
The result of the previous code appears in the following picture:

Figure 49: Create family instances using different reference directions

FamilySymbol
The FamilySymbol class represents a single Type within a Family. Each family can contain one or more family symbols. Each FamilyInstance has an associated
FamilySymbol which can be accessed from its Symbol property.

Thermal Properties

Certain types of families (doors, windows, and curtain wall panels) contain thermal properties as shown in the Type Properties window below for a window.
The thermal properties for a FamilySymbol are represented by the FamilyThermalProperties class and are retrieved using the
FamilySymbol.GetThermalProperties() method. The FamilyThermalProperties for a FamilySymbol can be set using SetThermalProperties(). The properties of
the FamilyThermalProperties class itself are read-only.

The units for the calculated values are shown in the table below.

Property Unit

watts per meter-squared kelvin


HeatTransferCoefficient
(W/(m^2*K)

meter-squared kelvin per watt


ThermalResistance
((m^2*K)/Watt)
The AnalyticConstructionTypeId property is the construction gbXML type and returns the value that corresponds to the 'id' property of a constructionType
node in Constructions.xml. The static FamilyThermalProperties.Find() method will find the FamilyThermalProperties by the 'id' property of a constructionType
node in Constructions.xml.

Family Documents
This section discusses families and how to:

• Create and modify Family documents

• Access family types and parameters

About family documents


Family

The Family object represents an entire Revit family. A Family Document is a Document that represents a Family rather than a Revit project.

Using the Family Creation functionality of the Revit API, you can create and edit families and their types. This functionality is particularly
useful when you have pre-existing data available from an external system that you want to convert to a Revit family library.

API access to system family editing is not available.

Categories

As noted in the previous chapter, the FamilyBase.FamilyCategory property indicates the category of the Family such as Columns, Furniture,
Structural Framing, or Windows.

The following code can be used to determine the category of the family in an open Revit Family document.

Code Region 13-1: Category of open Revit Family Document


1. string categoryName = familyDoc.OwnerFamily.FamilyCategory.Name;

The FamilyCategory can also be set, allowing the category of a family that is being edited to be changed.

Parameters

Family parameters can be accessed from the OwnerFamily property of a Family Document as the following example shows.

Code Region 13-2: Category of open Revit Family Document


1. // get the owner family of the family document.
2. Family family = familyDoc.OwnerFamily;
3. Parameter param = family.get_Parameter(BuiltInParameter.FAMILY_WORK_PLANE_BASED);
4. // this param is a Yes/No parameter in UI, but an integer value in API
5. // 1 for true and 0 for false
6. int isTrue = param.AsInteger();
7. // param.Set(1); // set value to true.
Creating a Family Document

The ability to modify Revit Family documents and access family types and parameters is available from the Document class if the Document
is a Family document, as determined by the IsFamilyDocument property. To edit an existing family while working in a Project document, use
the EditFamily() functions available from the Document class, and then use LoadFamily() to reload the family back into the owner document
after editing is complete. To create a new family document use Application.NewFamilyDocument():

Code Region 13-3: Creating a new Family document


1. // create a new family document using Generic Model.rft template
2. string templateFileName = @"C:\Documents and Settings\All Users\Application Data\Autodesk\RST 2011\Imperial Templates\Generic Model.rft";

3.
4. Document familyDocument = application.NewFamilyDocument(templateFileName);
5. if (null == familyDocument)
6. {
7. throw new Exception("Cannot open family document");
8. }

Nested Family Symbols

You can filter a Family Document for FamilySymbols to get all of the FamilySymbols loaded into the Family. In this code sample, all the
nested FamilySymbols in the Family for a given FamilyInstance are listed.

Code Region 13-4: Getting nested Family symbols in a Family


1. public void GetLoadedSymbols(Autodesk.Revit.DB.Document document, FamilyInstance familyInstance)
2. {
3. if (null != familyInstance.Symbol)
4. {
5. // Get family associated with this
6. Family family = familyInstance.Symbol.Family;
7.
8. // Get Family document for family
9. Document familyDoc = document.EditFamily(family);
10. if (null != familyDoc && familyDoc.IsFamilyDocument == true)
11. {
12. String loadedFamilies = "FamilySymbols in " + family.Name + ":\n";
13. FilteredElementCollector collector = new FilteredElementCollector(document);
14. ICollection<Element> collection =
15. collector.OfClass(typeof(FamilySymbol)).ToElements();
16. foreach (Element e in collection)
17. {
18. FamilySymbol fs = e as FamilySymbol;
19. loadedFamilies += "\t" + fs.Name + "\n";
20. }
21.
22. TaskDialog.Show("Revit",loadedFamilies);
23. }
24. }
25. }

Creating elements in families


The FamilyItemFactory class provides the ability to create elements in family documents. It is accessed through the Document.FamilyCreate
property. FamilyItemFactory is derived from the ItemFactoryBase class which is a utility to create elements in both Revit project documents
and family documents.
Create a form element
The FamilyItemFactory class provides the ability to create form elements in families, such as extrusions, revolutions, sweeps, and blends. See the section on 3D
Sketch for more information on these 3D sketch forms.

The following example demonstrates how to create a new Extrusion element. It creates a simple rectangular profile and then moves the newly created
Extrusion to a new location.

Code Region: Creating a new Extrusion


1. private Extrusion CreateExtrusion(Autodesk.Revit.DB.Document document, SketchPlane sketchPlane)
2. {
3. Extrusion rectExtrusion = null;
4.
5. // make sure we have a family document
6. if (true == document.IsFamilyDocument)
7. {
8. // define the profile for the extrusion
9. CurveArrArray curveArrArray = new CurveArrArray();
10. CurveArray curveArray1 = new CurveArray();
11. CurveArray curveArray2 = new CurveArray();
12. CurveArray curveArray3 = new CurveArray();
13.
14. // create a rectangular profile
15. XYZ p0 = XYZ.Zero;
16. XYZ p1 = new XYZ(10, 0, 0);
17. XYZ p2 = new XYZ(10, 10, 0);
18. XYZ p3 = new XYZ(0, 10, 0);
19. Line line1 = Line.CreateBound(p0, p1);
20. Line line2 = Line.CreateBound(p1, p2);
21. Line line3 = Line.CreateBound(p2, p3);
22. Line line4 = Line.CreateBound(p3, p0);
23. curveArray1.Append(line1);
24. curveArray1.Append(line2);
25. curveArray1.Append(line3);
26. curveArray1.Append(line4);
27.
28. curveArrArray.Append(curveArray1);
29.
30. // create solid rectangular extrusion
31. rectExtrusion = document.FamilyCreate.NewExtrusion(true, curveArrArray, sketchPlane, 10);
32.
33. if (null != rectExtrusion)
34. {
35. // move extrusion to proper place
36. XYZ transPoint1 = new XYZ(-16, 0, 0);
37. ElementTransformUtils.MoveElement(document, rectExtrusion.Id, transPoint1);
38. }
39. else
40. {
41. throw new Exception("Create new Extrusion failed.");
42. }
43. }
44. else
45. {
46. throw new Exception("Please open a Family document before invoking this command.");
47. }
48.
49. return rectExtrusion;
50. }
The following sample shows how to create a new Sweep from a solid ovoid profile in a Family Document.

Code Region: Creating a new Sweep


1. private Sweep CreateSweep(Autodesk.Revit.DB.Document document, SketchPlane sketchPlane)
2. {
3. Sweep sweep = null;
4.
5. // make sure we have a family document
6. if (true == document.IsFamilyDocument)
7. {
8. // Define a profile for the sweep
9. CurveArrArray arrarr = new CurveArrArray();
10. CurveArray arr = new CurveArray();
11.
12. // Create an ovoid profile
13. XYZ pnt1 = new XYZ(0, 0, 0);
14. XYZ pnt2 = new XYZ(2, 0, 0);
15. XYZ pnt3 = new XYZ(1, 1, 0);
16. arr.Append(Arc.Create(pnt2, 1.0d, 0.0d, 180.0d, XYZ.BasisX, XYZ.BasisY));
17. arr.Append(Arc.Create(pnt1, pnt3, pnt2));
18. arrarr.Append(arr);
19. SweepProfile profile = document.Application.Create.NewCurveLoopsProfile(arrarr);
20.
21. // Create a path for the sweep
22. XYZ pnt4 = new XYZ(10, 0, 0);
23. XYZ pnt5 = new XYZ(0, 10, 0);
24. Curve curve = Line.CreateBound(pnt4, pnt5);
25.
26. CurveArray curves = new CurveArray();
27. curves.Append(curve);
28.
29. // create a solid ovoid sweep
30. sweep = document.FamilyCreate.NewSweep(true, curves, sketchPlane, profile, 0, ProfilePlaneLocation.Start);
31.
32. if (null != sweep)
33. {
34. // move to proper place
35. XYZ transPoint1 = new XYZ(11, 0, 0);
36. ElementTransformUtils.MoveElement(document, sweep.Id, transPoint1);
37. }
38. else
39. {
40. throw new Exception("Failed to create a new Sweep.");
41. }
42. }
43. else
44. {
45. throw new Exception("Please open a Family document before invoking this command.");
46. }
47.
48. return sweep;
49. }

Figure 50: Ovoid sweep created by previous example

The FreeFormElement class allows for the creation of non-parametric geometry created from an input solid outline. A FreeFormElement can participate in joins
and void cuts with other combinable elements. Planar faces of the element can be offset interactively and programmatically in the face normal direction.

Assigning Subcategories to forms

After creating a new form in a family, you may want to change the subcategory for the form. For example, you may have a Door family and want to create
multiple subcategories of doors and assign different subcategories to different door types in your family.
The following example shows how to create a new subcategory, assign it a material, and then assign the subcategory to a form.

Code Region: Assigning a subcategory


1. public void AssignSubCategory(Document document, GenericForm extrusion)
2. {
3. // create a new subcategory
4. Category cat = document.OwnerFamily.FamilyCategory;
5. Category subCat = document.Settings.Categories.NewSubcategory(cat, "NewSubCat");
6.
7. // create a new material and assign it to the subcategory
8. ElementId materialId = Material.Create(document, "Wood Material");
9. subCat.Material = document.GetElement(materialId) as Material;
10.
11. // assign the subcategory to the element
12. extrusion.Subcategory = subCat;
13. }

Create an annotation
New annotations such as Dimensions and ModelText and TextNote objects can also be created in families, as well as curve annotation elements such as
SymbolicCurve, ModelCurve, and DetailCurve. See Annotation Elements for more information on Annotation elements.

Additionally, a new Alignment can be added, referencing a View that determines the orientation of the alignment, and two geometry references.

The following example demonstrates how to create a new arc length Dimension.

Code Region: Creating a Dimension


1. public Dimension CreateArcDimension(Document document, SketchPlane sketchPlane)
2. {
3. Autodesk.Revit.Creation.Application appCreate = document.Application.Create;
4. Line gLine1 = Line.CreateBound(new XYZ(0, 2, 0), new XYZ(2, 2, 0));
5. Line gLine2 = Line.CreateBound(new XYZ(0, 2, 0), new XYZ(2, 4, 0));
6. Arc arctoDim = Arc.Create(new XYZ(1, 2, 0), new XYZ(-1, 2, 0), new XYZ(0, 3, 0));
7. Arc arcofDim = Arc.Create(new XYZ(0, 3, 0), new XYZ(1, 2, 0), new XYZ(0.8, 2.8, 0));
8.
9. Autodesk.Revit.Creation.FamilyItemFactory creationFamily = document.FamilyCreate;
10. ModelCurve modelCurve1 = creationFamily.NewModelCurve(gLine1, sketchPlane);
11. ModelCurve modelCurve2 = creationFamily.NewModelCurve(gLine2, sketchPlane);
12. ModelCurve modelCurve3 = creationFamily.NewModelCurve(arctoDim, sketchPlane);
13. //get their reference
14. Reference ref1 = modelCurve1.GeometryCurve.Reference;
15. Reference ref2 = modelCurve2.GeometryCurve.Reference;
16. Reference arcRef = modelCurve3.GeometryCurve.Reference;
17.
18. Dimension newArcDim = creationFamily.NewArcLengthDimension(document.ActiveView, arcofDim, arcRef, ref1, ref2);
19. if (newArcDim == null)
20. {
21. throw new Exception("Failed to create new arc length dimension.");
22. }
23.
24. return newArcDim;
25. }
Figure 51: Resulting arc length dimension

Some types of dimensions can be labeled with a FamilyParameter. Dimensions that cannot be labeled will throw an
Autodesk.Revit.Exceptions.InvalidOperationException if you try to get or set the Label property. In the following example, a new linear dimension is created
between two lines and labeled as "width".

Code Region: Labeling a dimension


1. public Dimension CreateLinearDimension(Document document)
2. {
3. // first create two lines
4. XYZ pt1 = new XYZ(5, 5, 0);
5. XYZ pt2 = new XYZ(5, 10, 0);
6. Line line = Line.CreateBound(pt1, pt2);
7. Plane plane = document.Application.Create.NewPlane(pt1.CrossProduct(pt2), pt2);
8. SketchPlane skplane = SketchPlane.Create (document, plane);
9. ModelCurve modelcurve1 = document.FamilyCreate.NewModelCurve(line, skplane);
10.
11. pt1 = new XYZ(10, 5, 0);
12. pt2 = new XYZ(10, 10, 0);
13. line = Line.CreateBound(pt1, pt2);
14. plane = document.Application.Create.NewPlane(pt1.CrossProduct(pt2), pt2);
15. skplane = SketchPlane.Create (document, plane);
16. ModelCurve modelcurve2 = document.FamilyCreate.NewModelCurve(line, skplane);
17.
18. // now create a linear dimension between them
19. ReferenceArray ra = new ReferenceArray();
20. ra.Append(modelcurve1.GeometryCurve.Reference);
21. ra.Append(modelcurve2.GeometryCurve.Reference);
22.
23. pt1 = new XYZ(5, 10, 0);
24. pt2 = new XYZ(10, 10, 0);
25. line = Line.CreateBound(pt1, pt2);
26.
27. Dimension dim = document.FamilyCreate.NewLinearDimension(document.ActiveView, line, ra);
28.
29. // create a label for the dimension called "width"
30. FamilyParameter param = document.FamilyManager.AddParameter("width",
31. BuiltInParameterGroup.PG_CONSTRAINTS,
32. ParameterType.Length, false);
33.
34. dim.FamilyLabel = param;
35.
36. return dim;
37. }
Figure 52: Labeled linear dimension

Visibility of family elements


The FamilyElementVisibility class can be used to control the visibility of family elements in the project document. For example, if you have a
door family, you may only want the door swing to be visible in plan views in the project document in which doors are placed, not 3D views.
By setting the visibility on the curves of the door swing, you can control their visibility. FamilyElementVisibility is applicable to the following
family element classes which have the SetVisibility() function:

• GenericForm, which is the base class for form classes such as Sweep and Extrusion
• SymbolicCurve
• ModelText
• CurveByPoints
• ModelCurve
• ReferencePoint
• ImportInstance
In the example below, the resulting family document will display the text "Hello World" with a line under it. When the family is loaded into a
Revit project document and an instance is placed, in plan view, only the line will be visible. In 3D view, both the line and text will be
displayed, unless the Detail Level is set to Course, in which case the line will disappear.

Code Region 13-10: Setting family element visibility


1. public void CreateAndSetVisibility(Autodesk.Revit.DB.Document familyDocument, SketchPlane sketchPlane)
2. {
3. // create a new ModelCurve in the family document
4. XYZ p0 = new XYZ(1, 1, 0);
5. XYZ p1 = new XYZ(5, 1, 0);
6. Line line1 = Line.CreateBound(p0, p1);
7.
8. ModelCurve modelCurve1 = familyDocument.FamilyCreate.NewModelCurve(line1, sketchPlane);
9.
10. // create a new ModelText along ModelCurve line
11. ModelText text = familyDocument.FamilyCreate.NewModelText("Hello World", null, sketchPlane, p0, HorizontalAlign.Center, 0.1);
12.
13. // set visibility for text
14. FamilyElementVisibility textVisibility = new FamilyElementVisibility(FamilyElementVisibilityType.Model);
15. textVisibility.IsShownInTopBottom = false;
16. text.SetVisibility(textVisibility);
17.
18. // set visibility for line
19. FamilyElementVisibility curveVisibility = new FamilyElementVisibility(FamilyElementVisibilityType.Model);
20. curveVisibility.IsShownInCoarse = false;
21. modelCurve1.SetVisibility(curveVisibility);
22.
23. }

Managing family types and parameters


Family documents provide access to the FamilyManager property. The FamilyManager class provides access to family types and parameters.
Using this class you can add and remove types, add and remove family and shared parameters, set the value for parameters in different
family types, and define formulas to drive parameter values.

Getting Types in a Family

The FamilyManager can be used to iterate through the types in a family, as the following example demonstrates.

Code Region 13-11: Getting the types in a family


view plaincopy to clipboardprint?

1. public void GetFamilyTypesInFamily(Document familyDoc)


2. {
3. if (familyDoc.IsFamilyDocument == true)
4. {
5. FamilyManager familyManager = familyDoc.FamilyManager;
6.
7. // get types in family
8. string types = "Family Types: ";
9. FamilyTypeSet familyTypes = familyManager.Types;
10. FamilyTypeSetIterator familyTypesItor = familyTypes.ForwardIterator();
11. familyTypesItor.Reset();
12. while (familyTypesItor.MoveNext())
13. {
14. FamilyType familyType = familyTypesItor.Current as FamilyType;
15. types += "\n" + familyType.Name;
16. }
17. MessageBox.Show(types, "Revit");
18. }
19. }

Figure 53: Family types in Concrete-Rectangular-Column family


Editing FamilyTypes

FamilyManager provides the ability to iterate through existing types in a family, and add and modify types and their parameters.

The following example shows how to add a new type, set its parameters and then assign the new type to a FamilyInstance. Type editing is
done on the current type by using the Set() function. The current type is available from the CurrentType property. The CurrentType property
can be used to set the current type before editing, or use the NewType() function which creates a new type and sets it to the current type
for editing.

Note that once the new type is created and modified, Document.LoadFamily() is used to load the family back into the Revit project to make
the new type available.

Code Region 13-12: Editing Family Types


1. public void EditFamilyTypes(Document document, FamilyInstance familyInstance)
2. {
3. // example works best when familyInstance is a rectangular concrete element
4. if (null != familyInstance.Symbol)
5. {
6. // Get family associated with this
7. Family family = familyInstance.Symbol.Family;
8.
9. // Get Family document for family
10. Document familyDoc = document.EditFamily(family);
11. if (null != familyDoc)
12. {
13. FamilyManager familyManager = familyDoc.FamilyManager;
14.
15. // add a new type and edit its parameters
16. FamilyType newFamilyType = familyManager.NewType("2X2");
17. // look for 'b' and 'h' parameters and set them to 2 feet
18. FamilyParameter familyParam = familyManager.get_Parameter("b");
19. if (null != familyParam)
20. {
21. familyManager.Set(familyParam, 2.0);
22. }
23. familyParam = familyManager.get_Parameter("h");
24. if (null != familyParam)
25. {
26. familyManager.Set(familyParam, 2.0);
27. }
28.
29. // now update the Revit project with Family which has a new type
30. family = familyDoc.LoadFamily(document);
31. // find the new type and assign it to FamilyInstance
32. FamilySymbolSetIterator symbolsItor = family.Symbols.ForwardIterator();
33. symbolsItor.Reset();
34. while (symbolsItor.MoveNext())
35. {
36. FamilySymbol familySymbol = symbolsItor.Current as FamilySymbol;
37. if (familySymbol.Name == "2X2")
38. {
39. familyInstance.Symbol = familySymbol;
40. break;
41. }
42. }
43. }
44. }
45. }

Conceptual Design
This chapter discusses the conceptual design functionality of the Revit API for the creation of complex geometry in a family document. Form-
making is supported by the addition of new objects: points and spline curves that pass through these points. The resulting surfaces can be
divided, patterned, and panelized to create buildable forms with persistent parametric relationships.
Point and curve objects
A reference point is an element that specifies a location in the XYZ work space of the conceptual design environment. You create reference
points to design and plot lines, splines, and forms. A ReferencePoint can be added to a ReferencePointArray, then used to create a
CurveByPoints, which in turn can be used to create a form.

The following example demonstrates how to create a CurveByPoints object. See the "Creating a loft form" example in the next section to see
how to create a form from multiple CurveByPoints objects.

Code Region 14-1: Creating a new CurveByPoints


1. ReferencePointArray rpa = new ReferencePointArray();
2.
3. XYZ xyz = document.Application.Create.NewXYZ(0, 0, 0);
4. ReferencePoint rp = document.FamilyCreate.NewReferencePoint(xyz);
5. rpa.Append(rp);
6.
7. xyz = document.Application.Create.NewXYZ(0, 30, 10);
8. rp = document.FamilyCreate.NewReferencePoint(xyz);
9. rpa.Append(rp);
10.
11. xyz = document.Application.Create.NewXYZ(0, 60, 0);
12. rp = document.FamilyCreate.NewReferencePoint(xyz);
13. rpa.Append(rp);
14.
15. xyz = document.Application.Create.NewXYZ(0, 100, 30);
16. rp = document.FamilyCreate.NewReferencePoint(xyz);
17. rpa.Append(rp);
18.
19. xyz = document.Application.Create.NewXYZ(0, 150, 0);
20. rp = document.FamilyCreate.NewReferencePoint(xyz);
21. rpa.Append(rp);
22.
23. CurveByPoints curve = document.FamilyCreate.NewCurveByPoints(rpa);

Figure 54: CurveByPoints curve


Reference points can be created based on XYZ coordinates as in the example above, or they can be created relative to other geometry so
that the points will move when the referenced geometry changes. These points are created using the subclasses of the
PointElementReference class. The subclasses are:

• PointOnEdge

• PointOnEdgeEdgeIntersection

• PointOnEdgeFaceIntersection

• PointOnFace

• PointOnPlane

For example, the last two lines of code in the previous example create a reference point in the middle of the CurveByPoints.

Forms can be created using model lines or reference lines. Model lines are "consumed" by the form during creation and no longer exist as
separate entities. Reference lines, on the other hand, persist after the form is created and can alter the form if they are moved. Although the
API does not have a ReferenceLine class, you can change a model line to a reference line using the ModelCurve.ChangeToReferenceLine()
method.

Code Region 14-2: Using Reference Lines to create Form


1. private FormArray CreateRevolveForm(Document document)
2. {
3. FormArray revolveForms = null;
4.
5. // Create one profile
6. ReferenceArray ref_ar = new ReferenceArray();
7.
8. XYZ ptA = new XYZ(0, 0, 10);
9. XYZ ptB = new XYZ(100, 0, 10);
10. Line line = Line.CreateBound(ptA, ptB);
11. ModelCurve modelcurve = MakeLine(document, ptA, ptB);
12. ref_ar.Append(modelcurve.GeometryCurve.Reference);
13.
14. ptA = new XYZ(100, 0, 10);
15. ptB = new XYZ(100, 100, 10);
16. modelcurve = MakeLine(document, ptA, ptB);
17. ref_ar.Append(modelcurve.GeometryCurve.Reference);
18.
19. ptA = new XYZ(100, 100, 10);
20. ptB = new XYZ(0, 0, 10);
21. modelcurve = MakeLine(document, ptA, ptB);
22. ref_ar.Append(modelcurve.GeometryCurve.Reference);
23.
24. // Create axis for revolve form
25. ptA = new XYZ(-5, 0, 10);
26. ptB = new XYZ(-5, 10, 10);
27. ModelCurve axis = MakeLine(document, ptA, ptB);
28.
29. // make axis a Reference Line
30. axis.ChangeToReferenceLine();
31.
32. // Typically this operation produces only a single form,
33. // but some combinations of arguments will create multiple froms from a single profile.
34. revolveForms = document.FamilyCreate.NewRevolveForms(true, ref_ar, axis.GeometryCurve.Reference, 0, Math.PI / 4);
35.
36. return revolveForms;
37. }
38.
39. public ModelCurve MakeLine(Document doc, XYZ ptA, XYZ ptB)
40. {
41. Autodesk.Revit.ApplicationServices.Application app = doc.Application;
42. // Create plane by the points
43. Line line = Line.CreateBound(ptA, ptB);
44. XYZ norm = ptA.CrossProduct(ptB);
45. if (norm.IsZeroLength()) norm = XYZ.BasisZ;
46. Plane plane = app.Create.NewPlane(norm, ptB);
47. SketchPlane skplane = SketchPlane.Create(doc, plane);
48. // Create line here
49. ModelCurve modelcurve = doc.FamilyCreate.NewModelCurve(line, skplane);
50. return modelcurve;
51. }
Figure 55: Resulting Revolve Form
Forms
Creating Forms

Similar to family creation, the conceptual design environment provides the ability to create new forms. The following types of forms can be
created: extrusions, revolves, sweeps, swept blends, lofts, and surface forms. Rather than using the Blend, Extrusion, Revolution, Sweep,
and SweptBlend classes used in Family creation, Mass families use the Form class for all types of forms.

An extrusion form is created from a closed curve loop that is planar. A revolve form is created from a profile and a line in the same plane as
the profile which is the axis around which the shape is revolved to create a 3D form. A sweep form is created from a 2D profile that is swept
along a planar path. A swept blend is created from multiple profiles, each one planar, that is swept along a single curve. A loft form is
created from 2 or more profiles located on separate planes. A single surface form is created from a profile, similarly to an extrusion, but is
given no height.

The following example creates a simple extruded form. Note that since the ModelCurves used to create the form are not converted to
reference lines, they will be consumed by the resulting form.

Code Region 14-3: Creating an extrusion form


1. private Form CreateExtrusionForm(Autodesk.Revit.DB.Document document)
2. {
3. Form extrusionForm = null;
4.
5. // Create one profile
6. ReferenceArray ref_ar = new ReferenceArray();
7.
8. XYZ ptA = new XYZ(10, 10, 0);
9. XYZ ptB = new XYZ(90, 10, 0);
10. ModelCurve modelcurve = MakeLine(document, ptA, ptB);
11. ref_ar.Append(modelcurve.GeometryCurve.Reference);
12.
13. ptA = new XYZ(90, 10, 0);
14. ptB = new XYZ(10, 90, 0);
15. modelcurve = MakeLine(document, ptA, ptB);
16. ref_ar.Append(modelcurve.GeometryCurve.Reference);
17.
18. ptA = new XYZ(10, 90, 0);
19. ptB = new XYZ(10, 10, 0);
20. modelcurve = MakeLine(document, ptA, ptB);
21. ref_ar.Append(modelcurve.GeometryCurve.Reference);
22.
23. // The extrusion form direction
24. XYZ direction = new XYZ(0, 0, 50);
25.
26. extrusionForm = document.FamilyCreate.NewExtrusionForm(true, ref_ar, direction);
27.
28. int profileCount = extrusionForm.ProfileCount;
29.
30. return extrusionForm;
31. }
32.
33. public ModelCurve MakeLine(Document doc, XYZ ptA, XYZ ptB)
34. {
35. Autodesk.Revit.ApplicationServices.Application app = doc.Application;
36. // Create plane by the points
37. Line line = Line.CreateBound(ptA, ptB);
38. XYZ norm = ptA.CrossProduct(ptB);
39. if (norm.IsZeroLength()) norm = XYZ.BasisZ;
40. Plane plane = app.Create.NewPlane(norm, ptB);
41. SketchPlane skplane = SketchPlane.Create(doc, plane);
42. // Create line here
43. ModelCurve modelcurve = doc.FamilyCreate.NewModelCurve(line, skplane);
44. return modelcurve;
45. }
Figure 56: Resulting extrusion form

The following example shows how to create loft form using a series of CurveByPoints objects.

Code Region 14-4: Creating a loft form


view plaincopy to clipboardprint?

1. private Form CreateLoftForm(Autodesk.Revit.Document document)


2. {
3. Form loftForm = null;
4.
5. ReferencePointArray rpa = new ReferencePointArray();
6. ReferenceArrayArray ref_ar_ar = new ReferenceArrayArray();
7. ReferenceArray ref_ar = new ReferenceArray();
8. ReferencePoint rp = null;
9. XYZ xyz = null;
10.
11. // make first profile curve for loft
12. xyz = document.Application.Create.NewXYZ(0, 0, 0);
13. rp = document.FamilyCreate.NewReferencePoint(xyz);
14. rpa.Append(rp);
15.
16. xyz = document.Application.Create.NewXYZ(0, 50, 10);
17. rp = document.FamilyCreate.NewReferencePoint(xyz);
18. rpa.Append(rp);
19.
20. xyz = document.Application.Create.NewXYZ(0, 100, 0);
21. rp = document.FamilyCreate.NewReferencePoint(xyz);
22. rpa.Append(rp);
23.
24. CurveByPoints cbp = document.FamilyCreate.NewCurveByPoints(rpa);
25. ref_ar.Append(cbp.GeometryCurve.Reference);
26. ref_ar_ar.Append(ref_ar);
27. rpa.Clear();
28. ref_ar = new ReferenceArray();
29.
30. // make second profile curve for loft
31. xyz = document.Application.Create.NewXYZ(50, 0, 0);
32. rp = document.FamilyCreate.NewReferencePoint(xyz);
33. rpa.Append(rp);
34.
35. xyz = document.Application.Create.NewXYZ(50, 50, 30);
36. rp = document.FamilyCreate.NewReferencePoint(xyz);
37. rpa.Append(rp);
38.
39. xyz = document.Application.Create.NewXYZ(50, 100, 0);
40. rp = document.FamilyCreate.NewReferencePoint(xyz);
41. rpa.Append(rp);
42.
43. cbp = document.FamilyCreate.NewCurveByPoints(rpa);
44. ref_ar.Append(cbp.GeometryCurve.Reference);
45. ref_ar_ar.Append(ref_ar);
46. rpa.Clear();
47. ref_ar = new ReferenceArray();
48.
49. // make third profile curve for loft
50. xyz = document.Application.Create.NewXYZ(75, 0, 0);
51. rp = document.FamilyCreate.NewReferencePoint(xyz);
52. rpa.Append(rp);
53.
54. xyz = document.Application.Create.NewXYZ(75, 50, 5);
55. rp = document.FamilyCreate.NewReferencePoint(xyz);
56. rpa.Append(rp);
57.
58. xyz = document.Application.Create.NewXYZ(75, 100, 0);
59. rp = document.FamilyCreate.NewReferencePoint(xyz);
60. rpa.Append(rp);
61.
62. cbp = document.FamilyCreate.NewCurveByPoints(rpa);
63. ref_ar.Append(cbp.GeometryCurve.Reference);
64. ref_ar_ar.Append(ref_ar);
65.
66. loftForm = document.FamilyCreate.NewLoftForm(true, ref_ar_ar);
67.
68. return loftForm;
69. }

Figure 57: Resulting loft form

Form modification

Once created, forms can be modified by changing a sub element (i.e. a face, edge, curve or vertex) of the form, or an entire profile. The
methods to modify a form include:

• AddEdge

• AddProfile

• DeleteProfile

• DeleteSubElement

• MoveProfile

• MoveSubElement

• RotateProfile

• RotateSubElement

• ScaleSubElement
Additionally, you can modify a form by adding an edge or a profile, which can then be modified using the methods listed above.

The following example moves the first profile curve of the given form by a specified offset. The corresponding figure shows the result of
applying this code to the loft form from the previous example.

Code Region 14-5: Moving a profile


1. public void MoveForm(Form form)
2. {
3. int profileCount = form.ProfileCount;
4. if (form.ProfileCount > 0)
5. {
6. int profileIndex = 0; // modify the first form only
7. if (form.CanManipulateProfile(profileIndex))
8. {
9. XYZ offset = new XYZ(-25, 0, 0);
10. form.MoveProfile(profileIndex, offset);
11. }
12. }
13. }

Figure 58: Modified loft form

The next sample demonstrates how to move a single vertex of a given form. The corresponding figure demonstrate the effect of this code on
the previous extrusion form example

Code Region 14-6: Moving a sub element


1. public void MoveSubElement(Form form)
2. {
3. if (form.ProfileCount > 0)
4. {
5. int profileIndex = 0; // get first profile
6. ReferenceArray ra = form.get_CurveLoopReferencesOnProfile(profileIndex, 0);
7. foreach (Reference r in ra)
8. {
9. ReferenceArray ra2 = form.GetControlPoints(r);
10. foreach (Reference r2 in ra2)
11. {
12. Point vertex = document.GetElement(r2).GetGeometryObjectFromReference(r2) as Point;
13.
14. XYZ offset = new XYZ(0, 15, 0);
15. form.MoveSubElement(r2, offset);
16. break; // just move the first point
17. }
18. }
19. }
20. }
Figure 59: Modified extrusion form

Rationalizing a Surface
Dividing a surface

Faces of forms can be divided with UV grids. You can access the data for a divided surface using the Form.GetDividedSurfaceData() method
(as is shown in a subsequent example) as well as create new divided surfaces on forms as shown below.

Code Region 14-7: Dividing a surface


1. public void DivideSurface(Document document, Form form)
2. {
3. Application application = document.Application;
4. Options opt = application.Create.NewGeometryOptions();
5. opt.ComputeReferences = true;
6.
7. Autodesk.Revit.Geometry.Element geomElem = form.get_Geometry(opt);
8. foreach (GeometryObject geomObj in geomElem)
9. {
10. Solid solid = geomObj as Solid;
11. foreach (Face face in solid.Faces)
12. {
13. if (face.Reference != null)
14. {
15. DividedSurface ds = document.FamilyCreate.NewDividedSurface(face.Reference);
16. // create a divided surface with fixed number of U and V grid lines
17. SpacingRule srU = ds.USpacingRule;
18. srU.SetLayoutFixedNumber(16, SpacingRuleJustification.Center, 0, 0);
19.
20. SpacingRule srV = ds.VSpacingRule;
21. srV.SetLayoutFixedNumber(24, SpacingRuleJustification.Center, 0, 0);
22.
23. break; // just divide one face of form
24. }
25. }
26. }
27. }
Figure 60: Face of form divided by UV grids

Accessing the USpacing and VSpacing properties of DividedSurface, you can define the SpacingRule for the U and V gridlines by specifying
either a fixed number of grids (as in the example above), a fixed distance between grids, or a minimum or maximum spacing between grids.
Additional information is required for each spacing rule, such as justification and grid rotation.

Patterning a surface

A divided surface can be patterned. Any of the built-in tile patterns can be applied to a divided surface. A tile pattern is an ElementType that
is assigned to the DividedSurface. The tile pattern is applied to the surface according to the UV grid layout, so changing the USpacing and
VSpacing properties of the DividedSurface will affect how the patterned surface appears.

The following example demonstrates how to cover a divided surface with the OctagonRotate pattern. The corresponding figure shows how
this looks when applied to the divided surface in the previous example. Note this example also demonstrates how to get a DividedSurface on
a form.

Code Region 14-8: Patterning a surface


1. public void TileSurface(Document document, Form form)
2. {
3. // cover surface with OctagonRotate tile pattern
4. TilePatterns patterns = document.Settings.TilePatterns;
5. DividedSurfaceData dsData = form.GetDividedSurfaceData();
6. if (dsData != null)
7. {
8. foreach (Reference r in dsData.GetReferencesWithDividedSurfaces())
9. {
10. DividedSurface ds = dsData.GetDividedSurfaceForReference(r);
11. ds.ChangeTypeId(patterns.GetTilePattern(TilePatternsBuiltIn.OctagonRotate).Id);
12. }
13. }
14. }
Figure 61: Tile pattern applied to divided surface

In addition to applying built-in tile patterns to a divided surface, you can create your own massing panel families using the "Curtain Panel
Pattern Based.rft" template. These panel families can then be loaded into massing families and applied to divided surfaces using the
DividedSurface.ChangeTypeId() method.

The following properties of Family are specific to curtain panel families:

• IsCurtainPanelFamily

• CurtainPanelHorizontalSpacing - horizontal spacing of driving mesh

• CurtainPanelVerticalSpacing - vertical spacing of driving mesh

• CurtainPanelTilePattern - choice of tile pattern


The following example demonstrates how to edit a massing panel family which can then be applied to a form in a conceptual mass
document. To run this example, first create a new family document using the "Curtain Panel Pattern Based.rft" template.

Code Region 14-9: Editing a curtain panel family


1. Family family = document.OwnerFamily;
2. if (family.IsCurtainPanelFamily == true &&
3. family.CurtainPanelTilePattern == TilePatternsBuiltIn.Rectangle)
4. {
5. // first change spacing of grids in family document
6. family.CurtainPanelHorizontalSpacing = 20;
7. family.CurtainPanelVerticalSpacing = 30;
8.
9. // create new points and lines on grid
10. Autodesk.Revit.ApplicationServices.Application app = document.Application;
11. FilteredElementCollector collector = new FilteredElementCollector(document);
12. ICollection<Element> collection = collector.OfClass(typeof(ReferencePoint)).ToElements();
13. int ctr = 0;
14. ReferencePoint rp0 = null, rp1 = null, rp2 = null, rp3 = null;
15. foreach (Autodesk.Revit.DB.Element e in collection)
16. {
17. ReferencePoint rp = e as ReferencePoint;
18. switch (ctr)
19. {
20. case 0:
21. rp0 = rp;
22. break;
23. case 1:
24. rp1 = rp;
25. break;
26. case 2:
27. rp2 = rp;
28. break;
29. case 3:
30. rp3 = rp;
31. break;
32. }
33. ctr++;
34. }
35.
36. ReferencePointArray rpAr = new ReferencePointArray();
37. rpAr.Append(rp0);
38. rpAr.Append(rp2);
39. CurveByPoints curve1 = document.FamilyCreate.NewCurveByPoints(rpAr);
40. PointLocationOnCurve pointLocationOnCurve25 = new PointLocationOnCurve(PointOnCurveMeasurementType.NormalizedCurveParameter, 0.25, Po
intOnCurveMeasureFrom.Beginning);
41. PointOnEdge poeA = app.Create.NewPointOnEdge(curve1.GeometryCurve.Reference, pointLocationOnCurve25);
42. ReferencePoint rpA = document.FamilyCreate.NewReferencePoint(poeA);
43. PointLocationOnCurve pointLocationOnCurve75 = new PointLocationOnCurve(PointOnCurveMeasurementType.NormalizedCurveParameter, 0.75, Po
intOnCurveMeasureFrom.Beginning);
44. PointOnEdge poeB = app.Create.NewPointOnEdge(curve1.GeometryCurve.Reference, pointLocationOnCurve75);
45. ReferencePoint rpB = document.FamilyCreate.NewReferencePoint(poeB);
46.
47. rpAr.Clear();
48. rpAr.Append(rp1);
49. rpAr.Append(rp3);
50. CurveByPoints curve2 = document.FamilyCreate.NewCurveByPoints(rpAr);
51. PointOnEdge poeC = app.Create.NewPointOnEdge(curve2.GeometryCurve.Reference, pointLocationOnCurve25);
52. ReferencePoint rpC = document.FamilyCreate.NewReferencePoint(poeC);
53. PointOnEdge poeD = app.Create.NewPointOnEdge(curve2.GeometryCurve.Reference, pointLocationOnCurve75);
54. ReferencePoint rpD = document.FamilyCreate.NewReferencePoint(poeD);
55. }
56. else
57. {
58. throw new Exception("Please open a curtain family document before calling this command.");
59. }
Figure 62: Curtain panel family

Figure 63: Curtain panel assigned to divided surface


Adaptive Components
Adaptive Components are designed to handle cases where components need to flexibly adapt to many unique contextual conditions. For
example, adaptive components could be used in repeating systems generated by arraying multiple components that conform to user-defined
constraints.

The following code shows how to create an instance of an adaptive component family into a massing family and align the adaptive points in
the instance with points in the massing family.

Code Region: Creating an Instance of an Adaptive Component Family


1. // find the first placement point that will host the adaptive component
2. IEnumerable<ReferencePoint> points0 = from obj in new FilteredElementCollector(doc).OfClass(typeof(ReferencePoint)).Cast<ReferencePoint>(
)
3. let type = obj as ReferencePoint
4. where type.Name == "PlacementPoint0" // these names were manually assigned to the points
5. select obj;
6. ReferencePoint placementPoint0 = points0.First();
7.
8. // find the 2nd placement point that will host the adaptive component
9. IEnumerable<ReferencePoint> points1 = from obj in new FilteredElementCollector(doc).OfClass(typeof(ReferencePoint)).Cast<ReferencePoint>(
)
10. let type = obj as ReferencePoint
11. where type.Name == "PlacementPoint1"
12. select obj;
13. ReferencePoint placementPoint1 = points1.First();
14.
15. if (AdaptiveComponentInstanceUtils.IsAdaptiveFamilySymbol(symbol))
16. {
17. // create an instance of the adaptive component
18. FamilyInstance familyInstance = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(doc, symbol);
19.
20. // find the adaptive points in the family instance
21. IList<ElementId> pointList = AdaptiveComponentInstanceUtils.GetInstancePointElementRefIds(familyInstance);
22. ReferencePoint point0 = doc.GetElement(pointList.ElementAt(0)) as ReferencePoint;
23. ReferencePoint point1 = doc.GetElement(pointList.ElementAt(1)) as ReferencePoint;
24.
25. // move the adaptive component's points (point0 & point1) to match the position of the placement points
26. point0.Position = placementPoint0.Position;
27. point1.Position = placementPoint1.Position;
28. }

Datum and Information Elements


This chapter introduces Datum Elements and Information Elements in Revit.

• Datum Elements include levels, grids, and ModelCurves.

• Information Elements include phases, design options, and EnergyDataSettings.

For more information about Revit Element classifications, refer to Elements Essentials

Note If you need more information, refer to the related chapter:

• For LoadBase, LoadCase, LoadCombination, LoadNature and LoadUsage, refer toRevit Structure

• For ModelCurve, refer to Sketching

• For Material and FillPattern, refer to Material

• For EnergyDataSettings, refer to Revit Architecture


Levels
A level is a finite horizontal plane that acts as a reference for level-hosted elements, such as walls, roofs, floors, and ceilings. In the Revit
Platform API, the Level class is derived from the Element class. The inherited Name property is used to retrieve the user-visible level name
beside the level bubble in the Revit UI. To retrieve all levels in a project, use the ElementIterator iterator to search for Level objects.

Elevation

The Level class has the following properties:

• The Elevation property (LEVEL_ELEV) is used to retrieve or change the elevation above or below ground level.

• The ProjectElevation property is used to retrieve the elevation relative to the project origin regardless of the Elevation Base
parameter value.

• Elevation Base is a Level type parameter.

o Its BuiltInParameter is LEVEL_RELATIVE_BASE_TYPE.

o Its StorageType is Integer


o 0 corrDesponds to Project and 1 corresponds to Shared.

Figure 64: Level Type Elevation Base property

The following code sample illustrates how to retrieve all levels in a project using ElementIterator.

Code Region 15-1: Retrieving all Levels


private void Getinfo_Level(Document document)
{
StringBuilder levelInformation = new StringBuilder();
int levelNumber = 0;
FilteredElementCollector collector = new FilteredElementCollector(document);
ICollection<Element> collection = collector.OfClass(typeof(Level)).ToElements();
foreach (Element e in collection)
{
Level level = e as Level;

if (null != level)
{
// keep track of number of levels
levelNumber++;

//get the name of the level


levelInformation.Append("\nLevel Name: " + level.Name);

//get the elevation of the level


levelInformation.Append("\n\tElevation: " + level.Elevation);

// get the project elevation of the level


levelInformation.Append("\n\tProject Elevation: " + level.ProjectElevation);
}
}
//number of total levels in current document
levelInformation.Append("\n\n There are " + levelNumber + " levels in the document!");

//show the level information in the messagebox


TaskDialog.Show("Revit",levelInformation.ToString());
}
Creating a Level

Using the Level command, you can define a vertical height or story within a building and you can create a level for each existing story or
other building references. Levels must be added in a section or elevation view. Additionally, you can create a new level using the Revit
Platform API.

The following code sample illustrates how to create a new level.

Code Region 15-2: Creating a new Level


Level CreateLevel(Autodesk.Revit.Document document)
{
// The elevation to apply to the new level
double elevation = 20.0;

// Begin to create a level


Level level = document.Create.NewLevel(elevation);
if (null == level)
{
throw new Exception("Create a new level failed.");
}

// Change the level name


level.Name = "New level";

return level;
}
Note After creating a new level, Revit does not create the associated plan view for this level. If necessary, you can create it yourself. For
more information about how to create a plan view, refer to Views.
Grids
Grids are represented by the Grid class which is derived from the Element class. It contains all grid properties and methods. The inherited
Name property is used to retrieve the content of the grid line's bubble.

Curve

The Grid class Curve property gets the object that represents the grid line geometry.

• If the IsCurved property returns true, the Curve property will be an Arc class object.

• If the IsCurved property returns false, the Curve property will be a Line class object.

For more information, refer to Geometry.

The following code is a simple example using the Grid class. The result appears in a message box after invoking the command.

Code Region 15-3: Using the Grid class


view plaincopy to clipboardprint?

1. public void GetInfo_Grid(Grid grid)


2. {
3. string message = "Grid : ";
4.
5. // Show IsCurved property
6. message += "\nIf grid is Arc : " + grid.IsCurved;
7.
8. // Show Curve information
9. Autodesk.Revit.DB.Curve curve = grid.Curve;
10. if (grid.IsCurved)
11. {
12. // if the curve is an arc, give center and radius information
13. Autodesk.Revit.DB.Arc arc = curve as Autodesk.Revit.DB.Arc;
14. message += "\nArc's radius: " + arc.Radius;
15. message += "\nArc's center: (" + XYZToString(arc.Center);
16. }
17. else
18. {
19. // if the curve is a line, give length information
20. Autodesk.Revit.DB.Line line = curve as Autodesk.Revit.DB.Line;
21. message += "\nLine's Length: " + line.Length;
22. }
23. // Get curve start point
24. message += "\nStart point: " + XYZToString(curve.GetEndPoint(0));
25. // Get curve end point
26. message += "; End point: " + XYZToString(curve.GetEndPoint(0));
27.
28. TaskDialog.Show("Revit",message);
29. }
30.
31. // output the point's three coordinates
32. string XYZToString(XYZ point)
33. {
34. return "(" + point.X + ", " + point.Y + ", " + point.Z + ")";
35. }

Creating a Grid

Two overloaded Document methods are available to create a new grid in the Revit Platform API. Using the following method with different
parameters, you can create a curved or straight grid:

Code Region 15-4: NewGrid()


public Grid NewGrid( Arc arc );
public Grid NewGrid( Line line );
NoteThe arc or the line used to create a grid must be in a horizontal plane.
The following code sample illustrates how to create a new grid with a line or an arc.

Code Region 15-5: Creating a grid with a line or an arc


1. void CreateGrid(Autodesk.Revit.DB.Document document)
2. {
3. // Create the geometry line which the grid locates
4. XYZ start = new XYZ(0, 0, 0);
5. XYZ end = new XYZ(30, 30, 0);
6. Line geomLine = Line.CreateBound(start, end);
7.
8. // Create a grid using the geometry line
9. Grid lineGrid = document.Create.NewGrid(geomLine);
10.
11. if (null == lineGrid)
12. {
13. throw new Exception("Create a new straight grid failed.");
14. }
15.
16. // Modify the name of the created grid
17. lineGrid.Name = "New Name1";
18.
19. // Create the geometry arc which the grid locates
20. XYZ end0 = new XYZ(0, 0, 0);
21. XYZ end1 = new XYZ(10, 40, 0);
22. XYZ pointOnCurve = new XYZ(5, 7, 0);
23. Arc geomArc = Arc.Create(end0, end1, pointOnCurve);
24.
25.
26. // Create a grid using the geometry arc
27. Grid arcGrid = document.Create.NewGrid(geomArc);
28.
29. if (null == arcGrid)
30. {
31. throw new Exception("Create a new curved grid failed.");
32. }
33.
34. // Modify the name of the created grid
35. arcGrid.Name = "New Name2";
36. }

NoteIn Revit, the grids are named automatically in a numerical or alphabetical sequence when they are created.

You can also create several grids at once using the Document.NewGrids() method, which takes a CurveArray parameter.

Phase
Some architectural projects, such as renovations, proceed in phases. Phases have the following characteristics:

• Phases represent distinct time periods in a project lifecycle.

• The lifetime of an element within a building is controlled by phases.

• Each element has a construction phase but only the elements with a finite lifetime have a destruction phase.

All phases in a project can be retrieved from the Document object. A Phase object contains three pieces of useful information: Name, ID and
UniqueId. The remaining properties always return null or an empty collection.

Each new modeling component added to a project has a Created Phase ID and a Demolished Phase ID property. The Element.AllowPhases()
method indicates whether its phase ID properties can be modified.

The Created Phase ID property has the following characteristics:

• It identifies the phase in which the component was added.

• The default value is the same ID as the current view Phase value.

• Change the Created Phase ID parameter by selecting a new value corresponding to the drop-down list.

The Demolished Phase ID property has the following characteristics:

• It identifies in which phase the component is demolished.

• The default value is none.

• Demolishing a component with the demolition tool updates the property to the current Phase ID value in the view where you
demolished the element.

• You can demolish a component by setting the Demolished Phase ID property to a different value.
• If you delete a phase using the Revit Platform API, all modeling components in the current phase still exist. The Created Phase ID
parameter value for these components is changed to the next item in the drop-down list in the Properties dialog box.

Figure 65: Phase-created component parameter value

The following code sample displays all supported phases in the current document. The phase names are displayed in a message box.

Code Region 15-6: Displaying all supported phases


1. void Getinfo_Phase(Document doc)
2. {
3. // Get the phase array which contains all the phases.
4. PhaseArray phases = doc.Phases;
5. // Format the string which identifies all supported phases in the current document.
6. String prompt = null;
7. if (0 != phases.Size)
8. {
9. prompt = "All the phases in current document list as follow:";
10. foreach (Phase ii in phases)
11. {
12. prompt += "\n\t" + ii.Name;
13. }
14. }
15. else
16. {
17. prompt = "There are no phases in current document.";
18. }
19. // Give the user the information.
20. TaskDialog.Show("Revit",prompt);
21. }

Design Options
Design options provide a way to explore alternative designs in a project. Design options provide the flexibility to adapt to changes in project
scope or to develop alternative designs for review. You can begin work with the main project model and then develop variations along the
way to present to a client. Most elements can be added into a design option. Elements that cannot be added into a design option are
considered part of the main model and have no design alternatives.

The main use for Design options is as a property of the Element class. See the following example.

Code Region 15-7: Using design options


void Getinfo_DesignOption(Document document)
{
// Get the selected Elements in the Active Document
UIDocument uidoc = new UIDocument(document);
ElementSet selection = uidoc.Selection.Elements;

foreach (Autodesk.Revit.DB.Element element in selection)


{
// Use the DesignOption property of Element
if (element.DesignOption != null)
{
TaskDialog.Show("Revit", element.DesignOption.Name.ToString());
}
}
}

The following rules apply to Design Options

• The value of the DesignOption property is null if the element is in the Main Model. Otherwise, the name you created in the Revit UI is
returned.

• Only one active DesignOption Element can exist in an ActiveDocument.


o The primary option is considered the default active DesignOption. For example, a design option set is named Wall and there
are two design options in this set named "brick wall" and "glass wall". If "brick wall" is the primary option, only this option
and elements that belong to it are retrieved by the Element Iterator. "Glass wall" is inactive.
Annotation Elements
This chapter introduces Revit Annotation Elements, including the following:

• Dimension

• DetailCurve

• IndependentTag

• TextNote

• AnnotationSymbol

Note that:

• Dimensions are view-specific elements that display sizes and distances in a project.

• Detail curves are created for detailed drawings. They are visible only in the view in which they are drawn. Often they are drawn over
the model view.

• Tags are an annotation used to identify elements in a drawing. Properties associated with a tag can appear in schedules.

• AnnotationSymbol has multiple leader options when loaded into a project.

For more information about Revit Element classification, refer to Elements Essentials.

Dimensions and Constraints


The Dimension class represents permanent dimensions and dimension related constraint elements. Temporary dimensions created while
editing an element in the UI are not accessible. Spot elevation and spot coordinate are represented by the SpotDimension class.

The following code sample illustrates, near the end, how to distinguish permanent dimensions from constraint elements.

Code Region 16-1: Distinguishing permanent dimensions from constraints


1. public void GetInfo_Dimension(Dimension dimension)
2. {
3. string message = "Dimension : ";
4. // Get Dimension name
5. message += "\nDimension name is : " + dimension.Name;
6.
7. // Get Dimension Curve
8. Autodesk.Revit.DB.Curve curve = dimension.Curve;
9. if (curve != null && curve.IsBound)
10. {
11. // Get curve start point
12. message += "\nCurve start point:(" + curve.GetEndPoint(0).X + ", "
13. + curve.GetEndPoint(0).Y + ", " + curve.GetEndPoint(0).Z + ")";
14. // Get curve end point
15. message += "; Curve end point:(" + curve.GetEndPoint(1).X + ", "
16. + curve.GetEndPoint(1).Y + ", " + curve.GetEndPoint(1).Z + ")";
17. }
18.
19. // Get Dimension type name
20. message += "\nDimension type name is : " + dimension.DimensionType.Name;
21.
22. // Get Dimension view name
23. message += "\nDimension view name is : " + dimension.View.Name;
24.
25. // Get Dimension reference count
26. message += "\nDimension references count is " + dimension.References.Size;
27.
28. if ((int)BuiltInCategory.OST_Dimensions == dimension.Category.Id.IntegerValue)
29. {
30. message += "\nDimension is a permanent dimension.";
31. }
32. else if ((int)BuiltInCategory.OST_Constraints == dimension.Category.Id.IntegerValue)
33. {
34. message += "\nDimension is a constraint element.";
35. }
36.
37.
38. TaskDialog.Show("Revit",message);
39. }
Dimensions

There are five kinds of permanent dimensions:

• Linear dimension

• Radial dimension

• Diameter Dimension

• Angular dimension

• Arc length dimension

Figure 66: Permanent dimensions

The BuiltInCategory for all permanent dimensions is OST_Dimensions. There is not an easy way to distinguish the four dimensions using the
API.

Except for radial and diameter dimensions, every dimension has one dimension line. Dimension lines are available from the Dimension.Curve
property which is always unbound. In other words, the dimension line does not have a start-point or end-point. Based on the previous
picture:

• A Line object is returned for a linear dimension.

• An arc object is returned for a radial dimension or angular dimension.

• A radial dimension returns null.

• A diamter diimension returns null.

Figure 67: Dimension references

A dimension is created by selecting geometric references as the previous picture shows. Geometric references are represented as a
Reference class in the API. The following dimension references are available from the References property. For more information about
Reference, please see Reference in the Geometry section.

• Radial and diameter dimensions - One Reference object for the curve is returned

• Angular and arc length dimensions - Two Reference objects are returned.

• Linear dimensions - Two or more Reference objects are returned. In the following picture, the linear dimension has five Reference
objects.
Figure 68: Linear dimension references

Dimensions, like other Annotation Elements, are view-specific. They display only in the view where they are added. The Dimension.View
property returns the specific view.

Constraint Elements

Dimension objects with Category Constraints (BuitInCategory.OST_Constraints) represent two kinds of dimension-related constraints:

• Linear and radial dimension constraints

• Equality constraints

In the following picture, two kinds of locked constraints correspond to linear and radial dimension. In the application, they appear as
padlocks with green dashed lines. (The green dashed line is available from the Dimension.Curve property.) Both linear and radial dimension
constraints return two Reference objects from the Dimension.References property.

Figure 69: Linear and Radial dimension constraints

Constraint elements are not view-specific and can display in different views. Therefore, the View property always returns null. In the
following picture, the constraint elements in the previous picture are also visible in the 3D view.

Figure 70: Linear and Radial dimension constraints in 3D view

Although equality constraints are based on dimensions, they are also represented by the Dimension class. There is no direct way to
distinguish linear dimension constraints from equality constraints in the API using a category or DimensionType. Equality constraints return
three or more References while linear dimension constraints return two or more References.
Figure 71: Equality constraints

Note Not all constraint elements are represented by the Dimension class but all belong to a Constraints (OST_Constraints) category such as
alignment constraint.

Spot Dimensions

Spot coordinates and spot elevations are represented by the SpotDimension class and are distinguished by category. Like the permanent
dimension, spot dimensions are view-specific. The type and category for each spot dimension are listed in the following table:

Table 35: Spot dimension Type and Category

Type Category

Spot Coordinates OST_SpotCoordinates

Spot Elevations OST_SpotElevations

Figure 72: SpotCoordinates and SpotElevations

The SpotDimension Location can be downcast to LocationPoint so that the point coordinate that the spot dimension points to is available
from the LocationPoint.Point property.

• SpotDimensions have no dimension curve so their Curve property always returns null.

• The SpotDimension References property returns one Reference representing the point or the edge referenced by the spot dimension.

• To control the text and tag display style, modify the SpotDimension and SpotDimensionType Parameters.
Comparison

The following table compares different kinds of dimensions and constraints in the API:

Table 36: Dimension Category Comparison

Dimension or Constraint API Class BuiltInCategory Curve Reference View Location

Permanent Dimension linear dimension Dimension OST_Dimensions A Line >=2 Specific view null

radial dimension Null 1

diameter dimension Null 1

angular dimension An Arc 2

arc length dimension An Arc 2

Dimension Constraint linear dimension constraint OST_Constraints An Arc 2

angular dimension An Arc 2

Equality Constraint A Line >=3


Create and Delete

The NewDimension() method is available in the Creation.Document class. This method can create a linear dimension only.

Code Region 16-2: NewDimension()


1. public Dimension NewDimension (View view, Line line, ReferenceArray references)

1. public Dimension NewDimension (View view, Line line, ReferenceArray references,


2. DimensionType dimensionType)

Using the NewDimension() method input parameters, you can define the visible View, dimension line, and References (two or more).
However, there is no easy way to distinguish a linear dimension DimensionType from other types. The overloaded NewDimension() method
with the DimensionType parameter is rarely used.

The following code illustrates how to use the NewDimension() method to duplicate a dimension.

Code Region 16-3: Duplicating a dimension with NewDimension()


1. public void DuplicateDimension(Document document, Dimension dimension)
2. {
3. Line line = dimension.Curve as Line;
4. if (null != line)
5. {
6. Autodesk.Revit.DB.View view = dimension.View;
7. ReferenceArray references = dimension.References;
8. Dimension newDimension = document.Create.NewDimension(view, line, references);
9. }
10. }

Though only linear dimensions are created, you can delete all dimensions and constraints represented by Dimension and SpotDimension
using the Document.Delete() method.
Detail Curve
Detail curve is an important Detail component usually used in the detail or drafting view. Detail curves are accessible in the DetailCurve class
and its derived classes.

DetailCurve is view-specific as are other annotation elements. However, there is no DetailCurve.View property. When creating a detail curve,
you must compare the detail curve to the model curve view.

Code Region 16-4: NewDetailCurve() and NewModelCurve()


public DetailCurve NewDetailCurve (View, Curve, SketchPlane)
public ModelCurve NewModelCurve (Curve, SketchPlane)

Generally only 2D views such as level view and elevation view are acceptable, otherwise an exception is thrown.

Except for view-related features, DetailCurve is very similar to ModelCurve. For more information about ModelCurve properties and usage,
see ModelCurve in the Sketching section.

Tags
A tag is an annotation used to identify drawing elements. The API exposes the IndependentTag and RoomTag classes to cover most tags
used in the Revit application. For more details about RoomTag, see Room in the Revit Architecture section.

NoteThe IndependentTag class represents the tag element in Revit and other specific tags such as keynote, beam system tag, electronic
circuit symbol (Revit MEP), and so on. In Revit internal code, the specific tags have corresponding classes derived from IndependentTag. As
a result, specific features are not exposed by the API and cannot be created using the NewTag() method. They can be distinguished by the
following categories:

Table 37: Tag Name and Category

Tag Name BuiltInCategory

Keynote Tag OST_KeynoteTags

Beam System Tag OST_BeamSystemTags

Electronic Circuit Tag OST_ElectricalCircuitTags

Span Direction Tag OST_SpanDirectionSymbol

Path Reinforcement Span Tag OST_PathReinSpanSymbol

Rebar System Span Tag OST_IOSRebarSystemSpanSymbolCtrl

In this section, the main focus is on the tag type represented in the following picture.

Figure 73: IndependentTag

Every category in the family library has a pre-made tag. Some tags are automatically loaded with the default Revit application template,
while others are loaded manually. The IndependentTag objects return different categories based on the host element if it is created using the
By Category option. For example, the Wall and Floor IndependentTag are respectively OST_WallTags and OST_FloorTags.

If the tag is created using the Multi-Category or Material style, their categories are respectively OST_MultiCategoryTags and
OST_MaterialTags.

Note that NewTag() only works in the 2D view or in a locked 3D view, otherwise an exception is thrown. The following code is an example of
IndependentTag creation. Run it when the level view is the active view.
Note You can't change the text displayed in the IndependentTag directly. You need to change the parameter that is used to populate tag text
in the Family Type for the Element that's being tagged. In the example below, that parameter is "Type Mark", although this setting can be
changed in the Family Editor in the Revit UI.

Code Region 16-5: Creating an IndependentTag


1. private IndependentTag CreateIndependentTag(Autodesk.Revit.DB.Document document, Wall wall)
2. {
3. // make sure active view is not a 3D view
4. Autodesk.Revit.DB.View view = document.ActiveView;
5.
6. // define tag mode and tag orientation for new tag
7. TagMode tagMode = TagMode.TM_ADDBY_CATEGORY;
8. TagOrientation tagorn = TagOrientation.Horizontal;
9.
10. // Add the tag to the middle of the wall
11. LocationCurve wallLoc = wall.Location as LocationCurve;
12. XYZ wallStart = wallLoc.Curve.GetEndPoint(0);
13. XYZ wallEnd = wallLoc.Curve.GetEndPoint(1);
14. XYZ wallMid = wallLoc.Curve.Evaluate(0.5, true);
15.
16. IndependentTag newTag = document.Create.NewTag(view, wall, true, tagMode, tagorn, wallMid);
17. if (null == newTag)
18. {
19. throw new Exception("Create IndependentTag Failed.");
20. }
21.
22. // newTag.TagText is read-only, so we change the Type Mark type parameter to
23. // set the tag text. The label parameter for the tag family determines
24. // what type parameter is used for the tag text.
25.
26. WallType type = wall.WallType;
27.
28. Parameter foundParameter = type.get_Parameter("Type Mark");
29. bool result = foundParameter.Set("Hello");
30.
31. // set leader mode free
32. // otherwise leader end point move with elbow point
33.
34. newTag.LeaderEndCondition = LeaderEndCondition.Free;
35. XYZ elbowPnt = wallMid + new XYZ(5.0, 5.0, 0.0);
36. newTag.LeaderElbow = elbowPnt;
37. XYZ headerPnt = wallMid + new XYZ(10.0, 10.0, 0.0);
38. newTag.TagHeadPosition = headerPnt;
39.
40. return newTag;
41. }

Figure 74: Create IndependentTag using sample code

T
ext
In the API, the TextNote class represents Text. Its general features are as follows:

Table 38: General Features of TextNote

Function API Method or Property

Add text to the application Document.Create.NewTextNote() Method

Get and set string from the text component TextNote.Text Property

Get and set text component position TextNote.Coord Property

Get and set text component width TextNote.Width Property

Get all text component leaders TextNote.Leaders Property

Add a leader to the text component TextNote.AddLeader() Method

Remove all leaders from the text component TextNote.RemoveLeaders() Method

Revit supports two kinds of Leaders: straight leaders and arc leaders. Control the TextNote leader type using the TextNoteLeaderType
enumerated type:

Table 39: Leader Types

Function Member Name

TNLT_ARC_R

-Add a right arc leader

TNLT_ARC_L

-Add a left arc leader

TNLT_STRAIGHT_R

-Add a right leader.

TNLT_STRAIGHT_L

-Add a left leader.


Note Straight leaders and arc leaders cannot be added to a Text type at the same time.

Annotation Symbol
An annotation symbol is a symbol applied to a family to uniquely identify that family in a project.

Figure 75: Add annotation symbol

Figure 76: Annotation Symbol with two leaders


Create and Delete

Annotation symbols can be created using the following overload of the Creation.Document.NewFamilyInstance() method:

Code Region 16-6: Create a new Annotation Symbol


1. public FamilyInstance NewFamilyInstance Method (XYZ origin, FamilySymbol symbol, View specView)

The annotation symbol can be deleted using the Document.Delete() method.

Add and Remove Leader

Add and remove leaders using the addLeader() and removeLeader() methods.

Code Region 16-7: Using addLeader() and removeLeader()


1. public void AddAndRemoveLeaders(AnnotationSymbol symbol)
2. {
3. int leaderSize = symbol.Leaders.Size;
4. string message = "Number of leaders in Annotation Symbol before add: " + leaderSize;
5. symbol.addLeader();
6. leaderSize = symbol.Leaders.Size;
7. message += "\nNumber of leaders after add: " + leaderSize;
8. symbol.removeLeader();
9. leaderSize = symbol.Leaders.Size;
10. message += "\nNumber of leaders after remove: " + leaderSize;
11.
12. TaskDialog.Show("Revit", message);
13. }
Geometry
The Autodesk.Revit.DB namespace contains many classes related to geometry and graphic-related types used to describe the graphical
representation in the API. The geometry-related classes include:

• GeometryObject class - Includes classes derived from the GeometryObject class.

• Geometry Helper classes - Includes classes derived from the APIObject class and value types

• Geometry Utility classes - Includes classes to create non-element geometry and to find intersections of solids

• Collection classes - Includes classes derived from the IEnumerable or IEnumerator interface.

In this section, you learn how to use various graphic-related types, how to retrieve geometry data from an element, how to transform an
element, and more.

Example: Retrieve Geometry Data from a Wall


This walkthrough illustrates how to get geometry data from a wall. The following information is covered:

• Getting the wall geometry edges.

• Getting the wall geometry faces.


Note Retrieving the geometry data from Element in this example is limited because Instance is not considered. For example, sweeps
included in the wall are not available in the sample code. The goal for this walkthrough is to give you a basic idea of how to retrieve
geometry data but not cover all conditions. For more information about retrieving geometry data from Element, refer to Example: Retrieving
Geometry Data from a Beam.

Create Geometry Options

In order to get the wall's geometry information, you must create a Geometry.Options object which provides detailed customized options. The
code is as follows:

Code Region 20-1: Creating Geometry.Options


Autodesk.Revit.DB.Options geomOption = application.Create.NewGeometryOptions();
if (null != geomOption)
{
geomOption.ComputeReferences = true;
geomOption.DetailLevel = Autodesk Autodesk.Revit.DB.DetailLevels.Fine;

// Either the DetailLevel or the View can be set, but not both
//geomOption.View = commandData.Application.ActiveUIDocument.Document.ActiveView;

TaskDialog.Show("Revit", "Geometry Option created successfully.");


}
Note For more information, refer to Geometry.Options.

Retrieve Faces and Edges

Wall geometry is a solid made up of faces and edges. Complete the following steps to get the faces and edges:

1. Retrieve a Geometry.Element instance using the Wall class Geometry property. This instance contains all geometry objects in the
Object property, such as a solid, a line, and so on.

2. Iterate the Object property to get a geometry solid instance containing all geometry faces and edges in the Faces and Edges
properties.

3. Iterate the Faces property to get all geometry faces.

4. Iterate the Edges property to get all geometry edges.

You might also like