Hope you’re sitting down for this one as you’re going to have to do a good bit of experimentation to really understand the overall scope.
First up, it’s important to note a two things about geometry in Revit.
- Geometry is secondary to elements
- Geometry is calculated on demand
The first is important as it means you can’t just ask for geometry, but you have to pull it form something else. This is somewhat unique to Revit - if you look at say an IFC file, you can define a curve, or a solid, or whatever without having an element in the building.
The second is important as it means nothing is there to quarry from the object until you ask for it - it’s not stored in the file directly, but how to build the geometry is.
Now one last important note, we’re dealing with Revit geometry when we use the Python method get_Geometry
, not Dynamo geometry. As such things aren’t going to be functional in the Dynamo environment without making more direct calls to the Revit API. To put it bluntly: the standard Dynamo nodes will be of little to no use use untill you convert the data type. Think of it like speaking Swedish, Spanish, or English - we could say sfär, esfera, or sphere and all mean the same thing, but the person listening needs to speak the same language for things to be understood. The ToProtoType()
, ToPoint()
, and ToVector()
methods will do that conversion for you.
Hopefully you’re with me so far, as this is where things get interesting.
In order to simplify the process of deriving geometry, Revit utilizes a variety of methods to calculate the geometry. The first is calculating the family type geometry and transforming it into the location and orientation of the element in the model. Most families with a repeatable type have this in their sequencing. Then next is getting the geometry from the transformed instance and applying it’s modifiers (ie: the openings you added to each column) and pulling that. This requires the extra step of getting the modifiers, pulling their geometry, and applying them to the solids of the original instance geometry. A lot more steps - hence the second method. There are additional methods depending on the object type (think of walls, stairs, railings, direct shapes, adaptive components, and the rest of the Revit object type database). Oh and don’t forget about groups and links, plus the interaction of those on objects… all in it’s a difficult thing to do consistently, and once data is added (the original 'pull the family type geometry and transform that) you can’t remove that reference from the file… so you get a whole bunch of empty lists and null references when you really dig into the geometry.
Confusing as mud? Likely. I’ve had to play with it for quite awhile on several instances before achieving clarity. The code below should hlep you interrogate the forms a bit more clearly. I suggest starting with three column instances - one concrete column unedited, one concrete column with an opening, one steel column, and one steel column with an opening. Toggling the columns to be slanted or vertical can also help if you get into stuff like invisible geometry.
#setting up the Python environment
import clr
[ clr.AddReference(i) for i in ['RevitAPI', 'RevitNodes', 'RevitServices'] ]
from Autodesk.Revit.DB import *#BuiltInCategory, Element, FilteredElementCollector, GeometryInstance, Options, Solid, ViewDetailLevel
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
#real code starts here
doc = DocumentManager.Instance.CurrentDBDocument #get the current document
structuralElements = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralColumns).WhereElementIsNotElementType().ToElements() #get the structural elements, excluding the element types
geoOptions = Options() #the options configuration for getting the geometry of elements
geoOptions.DetailLevel = ViewDetailLevel.Fine #ensure we're using fine detail level
geoOptions.ComputeReferences = False #ensure we're not computing references
dynGeo = [] #a list to hold our resulting Dynamo geometry objects
rvtGeo = [] #a list ot hold our revit geometry object
rvtVol = [] #a list to hold our revit volumes - as a sanity check
for elem in structuralElements: #start a loop over the list of elements
rvtGeometryObjects = elem.get_Geometry(geoOptions) #get the revit geometry objects from each element - a list in all cases
rvtGeo.append(rvtGeometryObjects) #append the raw Revit geometry to the revit geometry variable
rvtVolumes = [] #an empty list fo rthe Revit geometry volumes
dynamoGeoSet = [] #an empty list for our element's geometry as Dynamo geometry
for rvtGeoObj in rvtGeometryObjects: #start a loop for every revit geometry object
if rvtGeoObj.GetType() == Solid: #if the object is a solid
rvtVolumes.append(rvtGeoObj.Volume) #get the volume and append it to the rvtVolumes list
else: #otherwise
rvtVolumes.append(0) #append a zero
if not rvtGeoObj.GetType() == GeometryInstance: #if the geometry is not a GeometryInstance
dynamoGeo = rvtGeoObj.ToProtoType() #convert it to a Dynamo geometry object
dynamoGeoSet.append(dynamoGeo) #append the Dynamo geo to the dynamo geometry set
else: #if it was a Geometry instance
instanceGeo = rvtGeoObj.GetInstanceGeometry() #get the revit geometry calcualted by the geometry instance
if len([i for i in instanceGeo]) == 0: #if there isn't anything in the instance geomtery
dynamoGeoSet.append([]) #append an empty list to the Dynamo geometry
for ig in instanceGeo: #for every revit instance geometry in the list of instance geometry
dynInstGeo = ig.ToProtoType() #convert it to a Dynamo geometry object
dynamoGeoSet.append(dynInstGeo) #append the Dyanmo geo to the Dyanmo geometry set
dynGeo.append(dynamoGeoSet) #append the Dynamo geometry set to the
rvtVol.append(rvtVolumes) #append the volume list to the rvtVol list
OUT = zip(rvtGeo, dynGeo, rvtVol) #return the revit geometry, Dynamo geometry, and revit volume as sequenced lists
Hope this helps you sort it all out.