Yesterday, I needed to print out all the floor types in a Revit document along with their function (Interior/Exterior). Obviously, I decided to write a quick RevitPythonShell script, but ran into some snags along the way that I would like to share.
This should really be as easy as:
collector = FilteredElementCollector(doc)
for floor_type in collector.OfClass(FloorType):
print floor_type.Name, floor_type.Function
But, well, nothing is ever easy, is it? What I ended up doing was this:
from System import Enum
collector = FilteredElementCollector(doc)
collector.OfClass(FloorType)
for floor_type in collector:
name = Element.Name.GetValue(floor_type)
function_param = Element.get_Parameter(floor_type, BuiltInParameter.FUNCTION_PARAM)
if function_param:
function = Enum.ToObject(WallFunction, function_param.AsInteger()).ToString()
else:
function = 'None'
print '%(name)-25s\t%(function)s' % locals()
Let's go through this line by line...
from System import Enum
Uh... I'll explain that later on...
collector = FilteredElementCollector(doc)
collector.OfClass(FloorType)
for floor_type in collector:
Nothing unusual here - this is how to get a list of elements from a Revit document using a FilteredElementCollector and iterating over that list.
name = Element.Name.GetValue(floor_type)
What?! Shouldn't that just have been floor_type.Name? I thought so too. But somehow, whenever I do that, I get an error like this:
>>> # note how ugly one-liners get ;)
>>> ft = list(FilteredElementCollector(doc).OfClass(FloorType))[0].Name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Name
This AttributeError is somehow related to IronPython not being able to figure out that it needs to use the base method inherited from Autodesk.Revit.DB.Element. So, I tell it to use that explicitly by referencing the property explicitly with Element.Name - and then retrieving its value: .GetValue. It needs to be told for which instance to retrieve the value, which is why I then plug in the floor_type object.
So... now we have the name of the FloorType. What about its function? That isn't a property, but rather a parameter, that can be found using the Revit Lookup tool: BuiltInParameter.FUNCTION_PARAM. Retrieving parameters is easy:
function_param = Element.get_Parameter(floor_type, BuiltInParameter.FUNCTION_PARAM)
Note again, how I use the base method Element.get_Parameter, as it doesn't seem to work on FloorType directly - my guess is that the definition of FloorType somehow isn't what IronPython is used to...
if function_param:
function = Enum.ToObject(WallFunction, function_param.AsInteger()).ToString()
else:
function = 'None'
The parameter may be null or, in python None, which will evaluate to False in a condition. In that case, we just set the text of the variable function to 'None'`. But the other line is a lot more interesting! This is why we did the from System import Enum earlier on: The (integer) value of the FUNCTION_PARAM is actually a member of an enumeration. As far as I can tell, it is equivalent to the WallFunction enumeration. With Enum.ToObject(WallFunction, function_param.AsInteger()), we can an the appropriate instance of this enumeration, which we then convert to a string (ToString()).
The last line:
print '%(name)-25s\t%(function)s' % locals()
Prints out the name and function nicely, using pythons string formatting: Left-alined name with a minimum width of 25 characters, a tab and then the function.
Try the script!