This is the third instalment of a series publishing the information provided in the 'What's New' sections of the past few Revit API releases help file RevitAPI.chm.
The first instalment covering What's New in the Revit 2010 API explains my motivation for this and provides an overview of the other releases.
We now move on to the Revit 2012 API, looking at:
First, however, another update on my vacation.
I am still on holiday in Italy, so please do not expect any immediate responses to comments for a while.
I love adventures, and finding myself in unexpected places, and I am getting my fill of that here and now.
I found better weather further south, and a beautiful empty beach north of Bari.
Acting on a recommendation by a cyclist whom I asked about his unintelligible dialect in a bar, I also ended up enjoying the unique trulli of Alberobello.
From there we continued to Lecce and started exploring the sweet and efficient little local train system connecting many of the communities on the peninsula of Salento.
We visited Galatina, continued to Nardo, and walked a long way on foot towards Santa Caterina to reach the protected natural park and beach of Porto Selvaggio.
In spite of some rain and cold, with some warm sunshine in between, we spent a day or two in pure uninterrupted nature.
On the way out towards Nardo again, a passing car picked us up and took us to Galipoli, another surprise visit, with a direct train connection back to Lecce.
Now, to continue the promised series of 'What's New' documentation from the past few Revit API releases.
The Revit API has been enhanced to run with the .NET 4.0 runtime. As a result, Visual Studio 2010 with a framework target of .NET 3.5 or 4.0 must be used to debug your addins. Addins compiled with Visual Studio 2008 will run normally outside the debugging environment.
All samples in the Revit API SDK have been upgraded to Visual Studio 2010.
Microsoft has not yet announced when Visual Studio Tools for Applications (VSTA) for .NET 4.0 will be available. VSTA is the technology used for Revit macros. The Microsoft VSTA debugger is not compatible with the default Revit 2012 .NET 4.0 environment. VSTA macros can run successfully in the .NET 4.0 environment, but a special Revit configuration is required for debugging. In order to use VSTA debugging, you must:
Note: Revit's native components continue to be compiled with the VS 2008 C++ compiler. Therefore Revit 2012 does not include the VS2010 redistributable. Third-party applications which include natively compiled C++ components should use the VS 2008 C++ compiler or must include the VS 2010 C++ redistributables with the installation.
Automatic regeneration mode has been removed. You no longer have to include the RegenerationMode attribute on your add-ins. All APIs expect that add-in code is written using manual regeneration when necessary.
Two new registration properties have been added:
Here is an example of the new entries:
<?xml version="1.0" encoding="utf-16" standalone="no"? <RevitAddIns> <AddIn Type="Command"> <Assembly>Command.dll</Assembly> <ClientId>d7e30025-97d4-4012-a581-5f8ed8d18808</ClientId> <FullClassName>Revit.Command</FullClassName> <Text>Command</Text> <VendorId>ADSK</VendorId> <VendorDescription>Autodesk, www.autodesk.com</VendorDescription> </AddIn> </RevitAddIns>
The CompoundStructure class has been replaced. The old CompoundStructure class in the API was read-only and supported only the nominal layers list without support for the settings related to vertical regions, sweeps, and reveals. The new CompoundStructure class supports read and modification of all of the structure information include vertical regions, sweeps and reveals.
The CompoundStructure.Layers property has been replaced by CompoundStructure.GetLayers() and CompoundStructure.SetLayers().
The CompoundStructureLayer class has also been replaced for the same reasons as CompoundStructure.
The following table maps properties from the old CompoundStructureLayer to the new version of the class:
The property HostObjAttributes.CompoundStructure has been replaced by two methods:
Remember that you must set the CompoundStructure back to the HostObjAttributes instance in order for any change to be stored in the element.
In addition to the information on wall sweeps found in the CompoundStructure class, there is a new API representing a wall sweep or reveal. The WallSweep class is an element that represents either a standalone wall sweep/reveal, or one added by the settings in a given wall's compound structure. Standalone wall sweeps and reveals may be constructed using the static method Create().
The LinePattern class has been replaced. The old LinePattern class in the API represented both the line pattern itself and the element that contains it, and offered no details on the contents of the pattern beyond its name. The new classes available are:
The method
offers the ability to add new LinePattern elements to the Revit database.
The property of the Settings class:
has been removed. LinePatterns may be found by the following approaches:
The FillPattern class has been replaced. The old FillPattern class in the API represented both the fill pattern itself and the element that contains it, and offered no details on the contents of the pattern beyond its name. The new classes available are:
The method
offers the ability to add new FillPattern elements to the Revit database.
The property of the Settings class:
has been removed. FillPatterns may be found by the following approaches:
A good portion of the IndependentTag class and related classes have been renovated.
Some new members were added to determine the elements referenced by the tag:
The import and export APIs no longer have special argument combinations which permit use of the "active view". If you wish to export from or import to the active view, you must obtain it directly and pass it as input to the method.
The methods
provide access to predefined setups and settings from a given document for DWG and DFX export.
The method
has been replaced by
The behaviour of these methods has been changed. Previously, they would prompt the interactive user to pick a target path name if the document's path name was not already set, or if the target file was read-only. Now they will throw an exception if the document's path name is not yet set, or if the saving target file is read-only.
The behaviour of this method has been changed. Previously, it would prompt the interactive user to pick a target path name if the document's path name was not already set, or if the target file was read-only. Now it will throw an exception if the document's path name is not set yet. In this case, it needs to be first saved using the SaveAs method instead, or when the target file is read-only.
This new method behaves identically to Document.Save(), but allows you to specify a temporary id to use to generate the file preview.
The behaviour of these methods has been changed. Previously, they would prompt the user before overwriting another file. Now an exception will be thrown in that situation.
This new method allows you to save a document, and encapsulates the options to rename the document in session, overwrite an existing file (if it exists), and temporarily assign a view id to use to generate the file preview.
This new method 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.
This new method saves the document to a file name and path obtained from the Revit user (via the "Save As" dialog).
The Reference class is being renovated to be more closely aligned with the native Revit class it wraps. Because of this change, References will no longer carry information on the document, element, or geometry object it was obtained from. The following table lists the replacement API calls for the obsolete Reference properties:
The method
is affected most by this change. The method was the only method to populate the Transform and ProximityParameter properties of Reference. You should switch to the replacement method:
This replacement method returns a list of ReferenceWithContext objects, containing the Reference plus additional members:
Note that methods which existed in Revit 2011 and earlier will continue in this release to return a fully populated Reference object (it is not necessary to change code dealing with these methods). However, methods added in Revit 2012 may not return a fully populated Reference handle and will need to be parsed using the replacement methods above. Also, affected members have been marked obsolete and planned to be removed in a future release.
A few changes have been made to event argument classes as we align frameworks to generate code for events.
Note: some of these classes and methods may change again in future.
The following table of changes lists the affected property, the classes providing it, and the new member with optional notes:
For some UI events on UIApplication and UIControlledApplication, the type of the "sender" object has been changed.
The new static methods
replace the Document.Move() overloads.
The new static methods
replace the Document.Mirror() methods. These new methods allow you to mirror one or more elements directly about a geometric plane which you may construct directly. Previously the Document.Mirror() methods required you to obtain a reference to an actual plane, or implicitly used the active view to calculate the mirror plane.
The new static methods
replace the Document.Rotate() methods.
The new static methods
allow you to copy and translate one or more physical elements and place the newly copied elements by applying the given translation vector.
The new methods
replace the Document.Array() overloads that return LinearArray.
The new methods
replace the Document.ArrayWithoutAssociate() methods that create sets of elements based on linear translation.
The new methods
replace the Document.Array() overloads that return RadialArray. The new methods require a view input (where previously the old overloads would use the active view implicitly, which could lead to unexpected failure in some conditions).
The new methods
replace the Document.ArrayWithoutAssociate() methods that create sets of elements based on rotation.
The AnalyticalModel class is now a subclass of Element.
One consequence of this change: the AnalyticalModel of a newly created structural element can no longer be obtained without regeneration (as the AnalyticalModel element must be generated).
The following two constructors were removed from AnalyticalModelSelector:
The following method was also removed:
Instead of passing the array of curves and the index to create the selector, you should use the constructor that accepts the Curve directly (obtain the curve from the collection prior to input).
The enumerated value SlabFoundationType.Slab is now SlabFoundationType.SlabOneWay. A new option, SlabTwoWay, is also available. Existing floors assigned the value Slab will report SlabOneWay.
The Revit API now allows you to create your own class-like Schema data structures and attach instances of them to any Element in a Revit model. This functionality can be used to replace the technique of storing data in hidden shared parameters. Schema-based data is saved with the Revit model and allows for higher-level, metadata-enhanced, object-oriented data structures. Schema data can be configured to be readable and/or writable to all users, just a specific application vendor, or just a specific application from a vendor.
The extensible storage classes are all found in Autodesk.Revit.DB.ExtensibleStorage
The following data types are currently supported:
// Create a data structure, attach it to a wall, // populate it with data, and retrieve the data // back from the wall public void StoreDataInWall( Wall wall, XYZ dataToStore ) { Transaction createSchemaAndStoreData = new Transaction(wall.Document, "tCreateAndStore"); createSchemaAndStoreData.Start(); SchemaBuilder schemaBuilder = new SchemaBuilder( new Guid("720080CB-DA99-40DC-9415-E53F280AA1F0")); // allow anyone to read the object schemaBuilder.SetReadAccessLevel(AccessLevel.Public); // restrict writing to this vendor only schemaBuilder.SetWriteAccessLevel(AccessLevel.Vendor); // required because of restricted write-access schemaBuilder.SetVendorId("ADSK"); // create a field to store an XYZ FieldBuilder fieldBuilder = schemaBuilder .AddSimpleField("WireSpliceLocation", typeof(XYZ)); fieldBuilder.SetUnitType(UnitType.UT_Length); fieldBuilder.SetDocumentation( "A stored location value representing a wiring splice in a wall."); schemaBuilder.SetSchemaName("WireSpliceLocation"); // register the Schema object Schema schema = schemaBuilder.Finish(); // create an entity (object) for this schema (class) Entity entity = new Entity(schema); // get the field from the schema Field fieldSpliceLocation = schema.GetField("WireSpliceLocation"); // set the value for this entity entity.Set<XYZ>(fieldSpliceLocation, dataToStore, DisplayUnitType.DUT_METERS); // store the entity in the element wall.SetEntity(entity); // get the data back from the wall Entity retrievedEntity = wall.GetEntity(schema); XYZ retrievedData = retrievedEntity.Get<XYZ>( schema.GetField("WireSpliceLocation"), DisplayUnitType.DUT_METERS); createSchemaAndStoreData.Commit(); }
Several new classes were added to provide access to worksharing information in the document:
Some related additions were made to existing classes:
In addition, there is API support for the new 2012 worksharing visualization functionality:
The new property
has both a getter and setter, so it allows you to query the currently active view of the currently active document, and also allows you to set it similarly to what an end user can do by changing a view in the Project Browser in Revit.
The setter has a number of limitations:
A new method:
was added to the UI API. It opens a Revit document and makes it the active one. The document is opened with its default view displayed.
There are limitations preventing this method to be called at certain situations:
The new methods
(and the corresponding methods in UIControlledApplication) provide the ability to add a new ribbon tab to Revit, at the end of the list of static tabs (to the right of the Add-Ins tab, if shown). If multiple tabs are added, they will be shown in the order added.
There is a limit to the number of custom tabs supported in a given session of Revit (20). This limit is provided to ensure that the standard tabs remain visible and usable. Because of this, your application should only add a custom tab if it's really needed.
New functionality in Revit 2012 allows elements to be divided into sub-parts, collected into assemblies, and displayed in special assembly views. The API for dividing parts is still under development and likely to change.
Read, write and create access to assemblies in the Revit environment is provided through the classes:
A new assembly containing the selected elements can be created as follows:
ElementId categoryId = doc.get_Element( uidoc.Selection.GetElementIds(). FirstOrDefault() ).Category.Id; ElementId titleblockId = doc.TitleBlocks.Cast<FamilySymbol>() .First<FamilySymbol>().Id; AssemblyInstance instance = null; Transaction t = new Transaction( doc ); if( AssemblyInstance.IsValidNamingCategory( doc, categoryId, uidoc.Selection.GetElementIds() ) ) { t.SetName( "Create Assembly Instance" ); t.Start(); instance = AssemblyInstance.Create( doc, uidoc.Selection.GetElementIds(), categoryId ); t.Commit(); t.SetName( "Set Assembly Name" ); t.Start(); string assemblyName = "Assembly #1"; if( AssemblyInstance.IsValidAssemblyName( doc, assemblyName, categoryId ) ) { instance.AssemblyTypeName = assemblyName; } t.Commit(); }
Other important methods include AssemblyInstance.GetMemberIds(), AssemblyInstance.SetMemberIds(), and AssemblyInstance.Disassemble().
Assembly views, that display only the elements in the assembly, are created with the AssemblyViewUtils class such as:
if( instance.AllowsAssemblyViewCreation() ) { ViewSheet viewSheet = AssemblyViewUtils .CreateSheet( doc, instance.Id, titleblockId ); View3D view3d = AssemblyViewUtils .Create3DOrthographic( doc, instance.Id ); ViewSection detailSectionA = AssemblyViewUtils .CreateDetailSection( doc, instance.Id, AssemblyDetailViewOrientation.DetailSectionA ); View materialTakeoff = AssemblyViewUtils .CreateMaterialTakeoff( doc, instance.Id ); View partList = AssemblyViewUtils .CreatePartList( doc, instance.Id ); }
The PartUtils class provides methods to identify Part elements that are created by sub-dividing model elements. These methods describe the relationship between Parts and the elements (such as walls, floors, etc) that are divided to create the Parts.
The add-in framework has been extended to support database-level add-ins. These add-ins should be used when the purpose of your application is to assign events and/or updaters to the Revit session, but not to add anything to the Revit user interface or use APIs from RevitAPIUI.dll.
To implement a DB-level application, implement the methods in the Autodesk.Revit.DB.IExternalDBApplication interface:
Within the OnStartup() method you should register events and updaters which your application will respond to during the session.
To register the DB-level application with Revit, add the appropriate registry entry to a manifest file in the Addins folder. A DB-level application has a similar structure as for a UI external application:
<?xml version="1.0" standalone="no"?> <RevitAddIns> <AddIn Type="DBApplication"> <Assembly>MyDBLevelApplication.dll</Assembly> <AddInId>DA3D570A-1AB3-4a4b-B09F-8C15DFEC6BF0</AddInId> <FullClassName>MyCompany.MyDBLevelAddIn</FullClassName> <Name>My DB-Level AddIn</Name> </AddIn> </RevitAddIns>
The new method
returns the original geometry of the instance, before the instance is modified by joins, cuts, coping, extensions, or other post-processing.
The utility class
allows you to attempt to “fit” a given piece of geometry into the shape of an extrusion. An instance of this class is a single-time use class which should be supplied a solid geometry, a plane, and a direction. The utility will calculate a base boundary parallel to the input plane which is the outer boundary of the shadow cast by the solid onto the input plane and along the extrusion direction.
After the extrusion has been calculated, the class permits a second step analysis to identify all faces from the original geometry which do not align with the faces of the calculated extrusion.
This utility works best for geometry which are at least somewhat “extrusion-like”, for example, the geometry of a wall which may or may not be affected by end joins, floor joins, roof joins, openings cut by windows and doors, or other modifications.
The new utility class GeometryCreationUtilities offers the ability to create solid geometry from input curves:
The resulting geometry is not added to the document as a part of any element. However, you may use the created Solid, and its constituent faces and edges, in several ways:
The new element filters:
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 routine used to determine if an interference exists during generation of an InterferenceReport. With ElementIntersectsSolidFilter, the target object is any solid, including one created from scratch using GeometryCreationUtilities.
This example uses a created cylinder centered on the end of a wall to find other walls in close proximity (whether or not they are actually joined):
public ICollection<ElementId> FindWallJoinsAtEndUsingProximity( Wall wall, int end ) { // Get properties of wall at the end point LocationCurve wallCurve = wall.Location as LocationCurve; XYZ endPoint = wallCurve.Curve.get_EndPoint( end ); double height = wall.get_Parameter( BuiltInParameter.WALL_USER_HEIGHT_PARAM ).AsDouble(); double elevation = wall.Level.Elevation; // Build cylinder centered at wall end point, // extending 3' in diameter CurveLoop cylinderLoop = new CurveLoop(); XYZ arcCenter = new XYZ( endPoint.X, endPoint.Y, elevation ); Application application = wall.Document.Application; Arc firstArc = application.Create.NewArc( arcCenter, 1.5, 0, Math.PI, XYZ.BasisX, XYZ.BasisY ); Arc secondArc = application.Create.NewArc( arcCenter, 1.5, Math.PI, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY ); cylinderLoop.Append( firstArc ); cylinderLoop.Append( secondArc ); List<CurveLoop> singleLoop = new List<CurveLoop>(); singleLoop.Add( cylinderLoop ); Solid proximityCylinder = GeometryCreationUtilities .CreateExtrusionGeometry( singleLoop, XYZ.BasisZ, height ); // Filter walls FilteredElementCollector proximityCollector = new FilteredElementCollector( wall.Document ); proximityCollector.OfClass( typeof( Wall ) ); // Exclude the wall itself List<ElementId> toExclude = new List<ElementId>(); toExclude.Add( wall.Id ); proximityCollector.Excluding( toExclude ); // Filter only elements intersecting our target cylinder proximityCollector.WherePasses( new ElementIntersectsSolidFilter( proximityCylinder ) ); // Return matches return proximityCollector.ToElementIds(); }
The new methods
execute a boolean operation combining a pair of solid geometry objects. Options to the method include the operations type: Union, Difference, or Intersect.
The first method takes a copy of the input solids and produces a new solid as a result. Its first argument can be any solid, either obtained directly from a
Revit element or created via another operation like GeometryCreationUtils.
The second method performs the boolean operation directly on the first input solid. The first input must be a solid which is not obtained directly from a Revit
element. The property
can identify whether the solid is appropriate as input for this method.
In this example, the geometry of intersecting columns and walls is obtained by a Boolean intersection operation. The intersection volume and number of boundary faces is shown in the resulting dialog.
/// <summary> /// A data structure containing the details /// of each intersecting wall/column pair. /// </summary> struct Intersection { public Element Wall; public Element Column; public Solid Solid; } /// <summary> /// A collection of all intersections. /// </summary> private List<Intersection> m_allIntersections; /// <summary> /// Finds and posts information on wall/column intersections. /// </summary> /// <param name="doc">The document.</param> public void FindIntersectionVolumes( Document doc ) { // Find all Wall elements. FilteredElementCollector collector = new FilteredElementCollector( doc ); collector.OfClass( typeof( Wall ) ); m_allIntersections = new List<Intersection>(); foreach( Wall wall in collector.OfType<Wall>() ) { // Find all intersecting columns FilteredElementCollector columnIntersectionCollector = new FilteredElementCollector( doc ); // Columns may be one of two different categories List<BuiltInCategory> categories = new List<BuiltInCategory>(); categories.Add( BuiltInCategory.OST_Columns ); categories.Add( BuiltInCategory.OST_StructuralColumns ); ElementMulticategoryFilter categoryFilter = new ElementMulticategoryFilter( categories ); // Apply intersection filter to find matches ElementIntersectsElementFilter intersectsFilter = new ElementIntersectsElementFilter( wall ); columnIntersectionCollector .WhereElementIsNotElementType() .WherePasses( categoryFilter ) .WherePasses( intersectsFilter ); foreach( Element element in columnIntersectionCollector ) { // Store information on intersection Intersection intersection; intersection.Wall = wall; intersection.Column = element; Solid wallSolid = GetGeometry( wall ); Solid columnSolid = GetGeometry( element ); // Intersect the solid geometry of the two elements intersection.Solid = BooleanOperationsUtils .ExecuteBooleanOperation( wallSolid, columnSolid, BooleanOperationsType.Intersect ); m_allIntersections.Add( intersection ); } } TaskDialog td = new TaskDialog( "Intersection info" ); td.MainInstruction = "Intersections found: " + m_allIntersections.Count; StringBuilder builder = new StringBuilder(); foreach( Intersection intersection in m_allIntersections ) { builder.AppendLine( String.Format( "{0} x {1}: volume {2} faces {3}", intersection.Wall.Name, intersection.Column.Name, intersection.Solid.Volume, intersection.Solid.Faces.Size ) ); } td.MainContent = builder.ToString(); td.Show(); } /// <summary> /// Gets the solid geometry of an element. /// </summary> /// <remarks>Makes an assumption that each element /// consists of only one postive-volume solid, and /// returns the first one it finds.</remarks> /// <param name="e"></param> /// <returns></returns> private Solid GetGeometry( Element e ) { GeometryElement geomElem = e.get_Geometry( new Options() ); foreach( GeometryObject geomObj in geomElem.Objects ) { // Walls and some columns will have a // solid directly in its geometry if( geomObj is Solid ) { Solid solid = (Solid)geomObj; if( solid.Volume > 0 ) return solid; } // Some columns will have a instance // pointing to symbol geometry if( geomObj is GeometryInstance ) { GeometryInstance geomInst = (GeometryInstance) geomObj; // Instance geometry is obtained so that the // intersection works as expected without // requiring transformation GeometryElement instElem = geomInst.GetInstanceGeometry(); foreach( GeometryObject instObj in instElem.Objects ) { if( instObj is Solid ) { Solid solid = (Solid)instObj; if( solid.Volume > 0 ) return solid; } } } } return null; }
The new methods
provide a shortcut to locate the faces of a given roof, floor, or wall which act as the exterior or interior boundary of the object's CompoundStructure. Top and bottom faces are applicable to roofs and floors. Side faces are applicable to walls.
The property
gets the reference to the host face of family instance, or if the instance is placed on a work plane, the reference to the geometry face underlying the work plane.
This property has been modified to throw an exception when attempting to read the geometry of a newly added or modified element, if the element has not yet been regenerated. Call Document.Regenerate() to regenerate the affected element and to be able to obtain the geometry.
This property now returns results for ElementType subclasses which own geometry.
This new property allows access to the GraphicsStyle and Category of individual family primitives to be determined while working in the project environment.
The methods
provide a curve that corresponds to the edge (either oriented along the edge's parametric direction, or oriented in the edge's topological direction on the specified face).
The method
calculates the centroid of the solid using an approximation, with an accuracy suitable for architectural purposes. This will correspond only with the center of gravity if the solid represents a homogeneous structure of a single material.
The new method
returns a copy of the geometry in the original element, transformed by the input coordinate transformation.
These new methods provide the transform for a given Instance (which is the parent class for elements like family instances, link instances, and imported CAD content). GetTransform() obtains the basic transform for the instance based on how the instance is placed. GetTotalTransform() provides the transform modified with the true north transform, for instances like import instances.
The new methods
allow you to save a reference to a geometry object, for example a face, edge, or curve, as a string, and to obtain an identical Reference later using the String as input.
This property and method provide information about the faces created by the Split Face command. HasRegions returns a boolean indicating if the face has any Split Face regions. GetRegions returns a list of faces. As the material of these faces can be independently modified through the UI with the Paint tool, the material of each face can be found from its MaterialElementId property.
Face.MaterialElement has been obsoleted. Face.MaterialElementId should be used instead.
In some cases the return face will not have access to its Document, so the MaterialElement cannot be returned, but the id can.
A new overload takes optional XYZ inputs for the tangency at the start and end of the spline.
The new overload
creates a NurbSpline in an identical manner to how the spline sketching tool creates such a curve in the Revit UI. Remaining fields in the curve definition (Knots, Degree) are automatically assigned from the calculation.
A new geometry object called a PolyLine is exposed through the API. The PolyLine represents a set of coordinate points forming contiguous line segments. Typically this type of geometry would be seen in geometry imported from other formats (such as DWG). Previous Element.Geometry[] would skip extraction of these geometry object completely.
The new method:
computes the 3D geometry of the input spatial element (room or space) and returns it, along with information about the elements which form the boundary of the element.
The new classes:
encapsulate the results of the geometric calculation.
The class:
provides the available options for the calculation (currently limited to an option to calculate the boundaries at the finish face or at the boundary object's centerlines and whether to include the free boundary faces in the calculation result).
A new API is provided to obtain and analyze the contents of a project's detailed energy analysis model, as seen in the Export to gbXML and the Heating and Cooling Loads features:
This analysis produces an analytical thermal model from the physical model of a building. The analytical thermal model is composed of spaces, zones and planar surfaces that represent the actual volumetric elements of the building.
The new classes in Autodesk.Revit.DB.Analysis namespace:
can be used to generate and analyze the contents of the detailed energy analysis model. Use
to create and populate the model (while setting up appropriate options); use
to extract the entities from the analysis; and use
to clean up the Revit database after finishing with the analysis results.
The new classes in the Autodesk.Revit.DB.Analysis namespace:
provide access to the elements and objects created by Revit to perform energy analyses on conceptual design models.
The method
supports export of a gBXML file containing conceptual energy analysis elements (mass elements) only.
The analysis visualization framework was improved to support multiple analysis results shown in the same view at the same time.
The new class
was added to store meta-data for each analysis result. The Results Visibilty view frame control in the user interface and the API's SpatialFieldManager.ResultsEnabledInView and AnalysisResultSchema.IsVisible properties control which results (if any) are displayed.
The class SpatialFieldManager now has new methods:
to register and access results meta-data. Corresponding methods and properties of SpatialFieldManager:
are deprecated. They can be used if SpatialFieldManager contains only one analysis result, but they throw an exception if multiple results are registered.
The method
is changed to take a result index as an additional argument; the old version is deprecated and can be used if SpatialFieldManager contains only one analysis result.
New classes allow for different types of analysis data and different appearance of results:
// Create a SpatialFieldManager for the active view SpatialFieldManager sfm = SpatialFieldManager .CreateSpatialFieldManager(doc.ActiveView, 1); int primitiveIndex = sfm.AddSpatialFieldPrimitive(); // This example creates two result schema. // Each schema contains a single value at the origin. IList<XYZ> pts = new List<XYZ>(); pts.Add(XYZ.Zero); FieldDomainPointsByXYZ pnts = new FieldDomainPointsByXYZ(pts); // Create the schema AnalysisResultSchema resultSchemaA = new AnalysisResultSchema( "Schema A", "Time"); AnalysisResultSchema resultSchemaB = new AnalysisResultSchema( "Schema B", "Distance"); // Data in Schema A measures time and can be // displayed using Hours or Minutes for units List<string> unitsList = new List<string>(); unitsList.Add("Hours"); unitsList.Add("Minutes"); List<double> unitsMultipliers = new List<double>(); unitsMultipliers.Add(1); unitsMultipliers.Add(60); resultSchemaA.SetUnits(unitsList, unitsMultipliers); List<double> doubleList = new List<double>(); // The data value in Schema A is 3.5 hours doubleList.Add(3.5); IList<ValueAtPoint> valueList = new List<ValueAtPoint>(); valueList.Add(new ValueAtPoint(doubleList)); FieldValues fieldValuesA = new FieldValues(valueList); // Data in Schema B measures distance and can be // displayed using Feet or Inches for units unitsList.Clear(); unitsMultipliers.Clear(); unitsList.Add("Feet"); unitsList.Add("Inches"); unitsMultipliers.Add(1); unitsMultipliers.Add(12); resultSchemaB.SetUnits(unitsList, unitsMultipliers); doubleList.Clear(); valueList.Clear(); // The data value in Schema B is 5 feet doubleList.Add(5); valueList.Add(new ValueAtPoint(doubleList)); FieldValues fieldValuesB = new FieldValues(valueList); // Update the view's spatial field primitive with the schema sfm.UpdateSpatialFieldPrimitive(primitiveIndex, pnts, fieldValuesA, sfm.RegisterResult(resultSchemaA)); sfm.UpdateSpatialFieldPrimitive(primitiveIndex, pnts, fieldValuesB, sfm.RegisterResult(resultSchemaB));
Revit offers two sets of APIs related to Point Clouds.
The client API is capable of working with point cloud instances within Revit (creating them, manipulating their properties, and reading the points found matching a given volumetric filter).
The major classes of the client API are:
There are two methods to access the points as a client:
The following snippets show how to iterate part of a point cloud using both methods. The same point cloud filter is applied for both routines:
private int ReadPointCloud_Iteration( PointCloudInstance pcInstance ) { PointCloudFilter filter = CreatePointCloudFilter( pcInstance.Document.Application, pcInstance ); // Get points. Number of points is // determined by the needs of the client PointCollection points = pcInstance.GetPoints( filter, 10000 ); int numberOfPoints = 0; foreach( CloudPoint point in points ) { // Process each point System.Drawing.Color color = System.Drawing.ColorTranslator.FromWin32( point.Color ); String pointDescription = String.Format( "({0}, {1}, {2}, {3}", point.X, point.Y, point.Z, color.ToString() ); numberOfPoints++; } return numberOfPoints; }
public unsafe int ReadPointCloud_Pointer( PointCloudInstance pcInstance ) { PointCloudFilter filter = CreatePointCloudFilter( pcInstance.Document.Application, pcInstance ); // Get points. Number of points is // determined by the needs of the client PointCollection points = pcInstance.GetPoints( filter, 10000 ); int totalCount = points.Count; CloudPoint* pointBuffer = (CloudPoint*) points .GetPointBufferPointer().ToPointer(); for( int numberOfPoints = 0; numberOfPoints < totalCount; numberOfPoints++ ) { CloudPoint point = *( pointBuffer + numberOfPoints ); // Process each point System.Drawing.Color color = System.Drawing.ColorTranslator.FromWin32( point.Color ); String pointDescription = String.Format( "({0}, {1}, {2}, {3}", point.X, point.Y, point.Z, color.ToString() ); } return totalCount; }
private PointCloudFilter CreatePointCloudFilter( Application app, PointCloudInstance pcInstance ) { // Filter will match 1/8 of the overall point cloud // Use the bounding box (filter coordinates // are in the coordinates of the model) BoundingBoxXYZ boundingBox = pcInstance.get_BoundingBox( null ); List<Plane> planes = new List<Plane>(); XYZ midpoint = ( boundingBox.Min + boundingBox.Max ) / 2.0; // X boundaries planes.Add( app.Create.NewPlane( XYZ.BasisX, boundingBox.Min ) ); planes.Add( app.Create.NewPlane( -XYZ.BasisX, midpoint ) ); // Y boundaries planes.Add( app.Create.NewPlane( XYZ.BasisY, boundingBox.Min ) ); planes.Add( app.Create.NewPlane( -XYZ.BasisY, midpoint ) ); // Z boundaries planes.Add( app.Create.NewPlane( XYZ.BasisZ, boundingBox.Min ) ); planes.Add( app.Create.NewPlane( -XYZ.BasisZ, midpoint ) ); // Create filter PointCloudFilter filter = PointCloudFilterFactory .CreateMultiPlaneFilter( planes ); return filter; }
There are two special API-only tools intended to help your client application interact with the user:
This example prompts the user to select a portion of the cloud, and creates a highlight filter for it.
public void PromptForPointCloudSelection( UIDocument uiDoc, PointCloudInstance pcInstance ) { Application app = uiDoc.Application.Application; Selection currentSel = uiDoc.Selection; PickedBox pickedBox = currentSel.PickBox( PickBoxStyle.Enclosing, "Select region of cloud for highlighting" ); XYZ min = pickedBox.Min; XYZ max = pickedBox.Max; //Transform points into filter View view = uiDoc.ActiveView; XYZ right = view.RightDirection; XYZ up = view.UpDirection; List<Plane> planes = new List<Plane>(); // X boundaries bool directionCorrect = IsPointAbovePlane( right, min, max ); planes.Add( app.Create.NewPlane( right, directionCorrect ? min : max ) ); planes.Add( app.Create.NewPlane( -right, directionCorrect ? max : min ) ); // Y boundaries directionCorrect = IsPointAbovePlane( up, min, max ); planes.Add( app.Create.NewPlane( up, directionCorrect ? min : max ) ); planes.Add( app.Create.NewPlane( -up, directionCorrect ? max : min ) ); // Create filter PointCloudFilter filter = PointCloudFilterFactory .CreateMultiPlaneFilter( planes ); Transaction t = new Transaction( uiDoc.Document, "Highlight" ); t.Start(); pcInstance.SetSelectionFilter( filter ); pcInstance.FilterAction = SelectionFilterAction.Highlight; t.Commit(); } private static bool IsPointAbovePlane( XYZ normal, XYZ planePoint, XYZ point ) { XYZ difference = point - planePoint; difference = difference.Normalize(); double dotProduct = difference.DotProduct( normal ); return dotProduct > 0; }
The engine API is capable of supplying points in a point cloud to Revit. A custom engine implementation consists of the following:
Engine implementations may be file-based or non-file-based:
Regardless of the type of engine used, the implementation must supply enough information to Revit to display the contents of the point cloud. There are two ReadPoints methods which must be implemented:
The Revit Materials API is largely renovated to allow for a representation of materials that is both more compact and more extensible.
The following classes are now obsolete:
The properties on these classes are now accessible from PropertySets or the Material class itself.
All named properties on Material specific to appearance or structure (e.g. Shininess) are also obsolete.
In their place, a material will have one or more aspects pertaining to rendering appearance, structure, or other major material category. Each aspect is represented by a PropertySet or PropertySetElement. Each material can own its properties of an aspect via a PropertySet or share them with other materials as a reference to a PropertySetElement.
New enumerated types:
New classes:
New methods:
The new Revit feature Performance adviser is designed to analyze the document and flag for the user any elements and/or settings that may cause performance degradation. The Performance Adviser command executes set of rules and displays their result in a standard review warnings dialog.
The API for performance adviser consists of 2 classes (PerformanceAdviser and IPerformanceAdviserRule). PerformanceAdviser is an application-wide singleton that has a dual role: it is a registry of performance checking rules and an engine to execute them. The methods of PerformanceAdviser:
allow you to manipulate what rules are checked. Applications that create new rules are expected to use AddRule() to register the new rule during application startup and DeleteRule() to deregister it during application shutdown.
Methods of PerformanceAdviser
allow UI or API application to mark rules for execution and run them on a given document, getting report as a list of FailureMessage objects.
The new interface IPerformanceAdviserRule allows you to define new rules for the Performance Adviser. Your application should create a class implementing this interface, instantiate an object of the derived class and register it using PerformanceAdviser.AddRule(). Methods of IPerformanceAdviserRule available for override include:
which provide rule identification information;
which are executed once per check and can be used to perform checks of the document "as a whole";
which allow the rule to identify a subset of elements in the document to be checked and run the check on the individual elements.
Potentially problematic results found during rule execution are reported by returning FailureMessage(s).
The API can now tell what elements in Revit are references to external files, and can make some modifications to where Revit loads external files from.
An Element which contains an ExternalFileReference is an element which refers to some external file (ie. a file other than the main .rvt file of the project.) Two new Element methods, IsExternalFileReference() and GetExternalFileReference(), let you get the ExternalFileReference for a given Element.
ExternalFileReference contains methods for getting the path of the external file, the type of the external file, and whether the file was loaded, unloaded, not found, etc. the last time the main .rvt file was opened.
The classes RevitLinkType and CADLinkType can have IsExternalFileReference() return true. RevitLinkTypes refer to Revit files linked into another Revit project. CADLinkTypes refer to DWG files. Note that CADLinkTypes can also refer to DWG imports, which are not external file references, as imports are brought completely into Revit. A property IsImport exists to let users distinguish between these two types.
Additionally, the element which contains the location of the keynote file is an external file reference, although it has not been exposed as a separate class.
There is also a class ExternalFileUtils, which provides a method for getting all Elements in a document which are references to external files.
Additionally, the classes ModelPath and ModelPathUtils have been exposed. ModelPaths can store paths to a location on disk, a network drive, or a Revit Server location. ModelPathUtils provides methods for converting between modelPath and String.
Finally, the class TransmissionData allows users to examine the external file data in a closed Revit document, and to modify path and load-state information for that data. Two methods, ReadTransmissionData, and WriteTransmissionData, are provided. With WriteTransmissionData, users can change the path from which to load a given link, and can change links from loaded to unloaded and vice versa. (WriteTransmissionData cannot be used to add links to or remove links from a document, however.)
Newly exposed classes:
The classes
allow your custom application to override the default implementation for the IFC export process.
The interface is passed an ExporterIFC object. The ExporterIFC object is the starting point for all IFC export activities and offers access to the options selected for the given export operation. It also contains access to information cached by Revit during the export process; this information is cached to provide easy access to it later, and sometimes to write it to the file at the end of the export process.
There are several auxiliary objects provided to support implementation of an IFC export client. These are the most important:
The IFC export client for Revit 2012 represents a transitional state between the version implemented internally in Revit 2011 and the final state which should be written 100% using the Revit API. Temporary APIs are exposed to bridge the gaps between the API client code and portions of the previous implementation. As Autodesk continues to evolve this export client, temporary APIs will be changed, deprecated and/or removed in future versions of Revit.
The following new classes provide read/write access to MEP pipe settings:
The following new properties identify placeholder ducts and pipes:
These new static methods allows creation of placeholder ducts and pipes:
New utility methods are exposed to convert a set of placeholder ducts and pipes to real 3D entities:
The new classes
and related types support read/write and create access to duct & pipe insulation and lining. In Revit 2012, these objects are now accessible as standalone elements related to their parent duct, pipe, or fitting.
The properties
now use Revit's TimeZone calculation engine to assign an appropriate time zone for the coordinates. (Previously the time zone was not modified when these values were changed).
SiteLocation retains the ability to set the TimeZone manually as the calculation is may not be accurate for locations near the boundaries.
The City class has been adjusted to return the more accurate TimeZone values.
The new static method
provides direct access to the results of a time zone calculation.
Returns the GUID of a particular family parameter. Allows you to determine if family parameters are shared or not.
Identifies if a parameter definition represents a visible or hidden parameter (hidden applies to shared parameters only).
Returns a collection containing the ids of the selected elements. This collection can be used directly with FilteredElementCollector.
PickedBox Selection.PickBox(PickBoxStyle style); PickedBox Selection.PickBox(PickBoxStyle style, String statusPrompt)
The limitation against calling Save/SaveAs has been removed for most events.
The restriction against calling Save/SaveAs remains only in the following special events:
Please note that other restrictions may still prevent a successful save (e.g. save cannot be performed if a transaction group or transaction is still opened by the API client or via Revit's UI when the event handler is invoked)
A new method allows opening an IFC Document. This method is similar in behaviour to OpenDocumentFile rather than to standard Import methods. It opens the specified file as a newly created document rather than importing it into an existing one. The new document is retuned by the method if opening was successful.
The class RevitUIFamilyLoadOptions is no longer available for direct construction in the API. If you want to trigger the Revit UI to respond to situations when a loaded family is already found in the target project, obtain a special IFamilyLoadOptions instance from the new static method UIDocument.GetRevitUIFamilyLoadOptions() (in RevitAPIUI.dll) instead.
The members of the BuiltInParameter enum (which are parameter "ids" for Revit use) now have automatically generated documentation. 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 case you must examine the parameters associated with a specific element to determine which parameter id to use.
This method has been removed and replaced by
The new method provides a reason why the cutting element cannot cut the other element.
The methods in the new classes
provide access to data related to adaptive component families and instances.
This new method converts a placeholder sheet to a real view sheet, optionally applying a titleblock at the same time.
A new class
allows access to the initial view settings for a document that controls which view should initially be shown when the model is opened.
It has the following public methods/properties:
The new method
gets the settings related to the stored document preview image for a given document. It returns a DocumentPreviewSettings object, whose members include:
Note that it is also possible to temporarily assign a preview view id for one save operation through the SaveOptions and SaveAsOptions classes. The id set to these classes is not stored in the saved documented.
An override for
was added to determine if two Documents represent the same document currently opened in the Revit session.
An override for
was added to return the same hashcode for document instances that represent the same document currently opened in the Revit session.
There are new settings to flag an updater as optional. Optional updaters will not cause prompting the end user when they are opening a document which was modified by that updater but the updater is not currently registered. red). Optional updaters should be used only when necessary. By default, updaters are non-optional. New methods introduced to support this change are:
New methods were added to access information about currently registered updaters:
Revit now disallows any calls to UpdaterRegistry from within the Execute() method of an updater. That means any calls to RegistryUpdater(), AddTrigger(), etc. will now throw an exception. The only method of UpdaterRegistry allowed to be called during execution of an updater is UnregisterUpdater(,) but the updater to be unregistered must be not the one currently being executed.
The Enclosure class, introduced in Revit 2011 as the parent class for Rooms, Spaces and Areas, was renamed to SpatialElement.
The individual BoundarySegment properties for the Room, Space and Area classes have been marked obsolete.
The SpatialElement class contains a new method:
which works for all subclass types.
Two new properties added to Line class to get the origin and direction of a line:
Five new read-only properties have been added to the TextElement class:
The FaceSplitter class, representing the element produced by a Split Face operation, has been exposed to the API.
Use this class to identify the element whose face was split by the element (SplitElementId property).
Autodesk.Revit.DB.Options opt = app.Create.NewGeometryOptions(); opt.ComputeReferences = true; opt.IncludeNonVisibleObjects = true; FilteredElementCollector collector = new FilteredElementCollector( doc ); ICollection<FaceSplitter> splitElements = collector.OfClass( typeof( FaceSplitter ) ) .Cast<FaceSplitter>().ToList(); foreach( FaceSplitter faceSplitter in splitElements ) { Element splitElement = doc.get_Element( faceSplitter.SplitElementId ); Autodesk.Revit.DB.GeometryElement geomElem = faceSplitter.get_Geometry( opt ); foreach( GeometryObject geomObj in geomElem.Objects ) { Line line = geomObj as Line; if( line != null ) { XYZ end1 = line.get_EndPoint( 0 ); XYZ end2 = line.get_EndPoint( 1 ); double length = line.ApproximateLength; } } }
To find the faces created by the split, use the new Face.GetFaceRegions() method on the face of the host element for the split.
The newly exposed ColumnAttachment class represents an attachment of the top or bottom of a column to a roof, floor, ceiling, or beam. Static methods:
provide access to the settings in this class for a given element.
The API color class may represent an invalid or uninitialized color when an instance of it is obtained from Revit. Invalid colors cannot be read; a new exception will throw from the Red, Green, and Blue properties if you attempt to read them. Setting the color properties is permitted and makes the color no longer invalid.
The property
identifies if the color is valid.
The new property
is a settable property capable of changing if the work plane for a particular family instance is flipped.
The new property
identifies if the family instance allows flipping of the work plane.
Two new overloads are provided for creating family instances from References:
These are identical to their counterparts that accept Faces as input. Because the Reference member will not always be populated in all Face handles, these overloads allow an alternate means of creating the target family instance attached to the right face.
The new overload
provides the ability to create a line-based detail component.
The new methods
provide access to the setting for whether or not joining is allowed at a particular end of the wall. If joins exist at the end of a wall and joins are disallowed, the walls will become disjoint. If joins are disallowed for the end of the wall, and then the setting is toggled to allow the joins, the wall will automatically join to its neighbors if there are any.
The Element.Pinned property is no longer read-only. It now allows you to set an element to be pinned or unpinned.
Two new overloads allow you to evaluate the result of an ElementFilter:
This new ElementFilter subtype allows you to easily find elements whose category matches any of a given set of categories.
This new ElementFilter subtype allows you to easily find elements whose class type matches any of a given set of classes.
The new method
returns the status of a given element in the input phase. Options include none (elements unaffected by phasing), new, demolished, past, future, existing and temporary.
The new element filter allows you to filter for elements which have a status matching one of the set of input statuses.
The new method:
identifies if a particular temporary view mode is active for a view.
The new method:
identifies if an element should be visible in the indicated view mode. This applies only to the TemporaryHideIsolate and AnalyticalModel view modes.
The Revit API classes in Autodesk.Revit.Collections:
have been removed. More flexible alternatives exist in the .NET framework System.Collections and System.Collections.Generic namespaces.
The property
has been replaced by
The data type is now an IDictionary<String, String>.
The previous Data property has been marked Obsolete.
The property
has been replaced by two methods
The data type is now an IDictionary<String, String>.
The previous LibraryPaths property has been marked Obsolete.
The members of the LinkElementId class have changed in order to clarify what element is represented by an instance of this object. The new properties are:
The new properties:
provide read access to information in the current Revit session.
This DLL is now compiled as a compatible binary capable of execution on 32-bit or 64-bit systems.
Macros can now be used in multiple Revit sessions launched from a single installation. Revit will no longer warn you about VSTA being disabled when the second and subsequent sessions are launched.
There are a few restrictions regarding what you can do from the second and subsequent sessions:
The track changes UI previously offered by Revit Structure has been removed. In previous releases, this offered the ability to highlight elements changed by API commands, and a limited ability to revert some or all of the changes.
Unfortunately, the functionality was limited in certain ways:
If you wish to offer some ability for your users to see what changes were made by a given transaction, you can implement something similar or more sophisticated using the DocumentChanged event. End users are best served using the Undo mechanism to revert all changes made during a given transaction, if that is their desire. The Undo mechanism is consistent and compatible with multiple API transactions, events and updaters as well as individual commands.
This property has been corrected to be Boolean instead of integer.
The family of NewBeamSystem() methods has changed. Previously curves could be input without a sketch plane or level as input, and the orientation of the active view would determine the orientation of the resultant beam system. Now, there are overloads accepting either the sketch plane or the level and those inputs are required.
The overloads of NewBeamSystem() now check that the input profile curves lie properly in the sketch plane or level. They also check to ensure that the profile forms a closed loop.
The SketchPlane input for this method is now required. Previously null could be input, and the orientation of the active view would determine the orientation of the resultant truss.
RebarShape elements are no longer modifiable (except for Allowed Bar Types). Instead of changing a RebarShape, create a new one based on the old one. This change results in a simplified API that works in the same way as the UI.
Also, the syntax for RebarShape creation has been changed. In 2011, the steps were:
In 2012, the steps are:
Specifically, the following methods are removed:
and replaced by:
The ability to modify hook angle, hook orientation, and style has been removed. These can only be set at creation.
The interface for Rebar Shape Parameters has changed. Throughout the Rebar API, all methods now use ElementId to stand for a shared parameter, instead of ExternalDefinition. Methods are provided in the new RebarShapeParameters class to convert between ElementId and ExternalDefinition:
The following RebarShape properties were replaced with get methods:
The ability to modify hook angle, hook orientation, and style has been removed.
The return type of RebarShape.GetCurvesForBrowser() was changed from CurveArray to IList<Curve>.
The method
was replaced by
New members were added to the RebarHookType class are new (its properties were only available through the Parameters interface before).
The RebarHostData class has the following changes:
The two methods Creation.Document.NewRebar() were replaced by:
The new methods are similar to the old ones, except that they no longer return null for invalid arguments, and they no longer regenerate the document.
The new class RebarBendData is to support functionality that is not part of Alpha 3.
The new property
identifies the type of an electrical circuit (circuit, spare or space).
The method ElectricalSystem.AddToCircuit now throws an exception when the system is a spare or space circuit.
The enum class
adds a new enum value to represent cable tray & conduit.
New read-only properties have been added:
The new property
identifies if the system currently contains no components.
The new properties:
and the matching setters control whether Revit MEP will highlight disconnects in systems graphically.
The new property
indicates if the value of Space.LatentHeatGainperPerson and Space.SensibleHeatGainperPerson properties is the default value or if it is user-defined.
To accomodate this property, the namespace of enum BaseLoadOn has changed from Autodesk.Revit.DB.Electrical to Autodesk.Revit.DB.
The following methods no longer remove unused or dangling curve connectors:
Please use ConnectorManager.UnusedConnectors.Erase to remove unused connectors after creating a new fitting.
End of document
That was the news in the Revit 2012 API back in the year 2011.
Please be aware that some of the changes mentioned above have been updated yet again since.
Stay tuned for the next installment, coming soon, leading up towards the current day.