Revit: Report mirrored doors orientation on nested linked files

Here is a new cool problem to solve, how to deal with mirrored doors on series of nested buildings.

When we flip a door using the flipping controls, the parameters HandFlipped  & FacingFlipped are settled to true. This creates 4 states of door positions.

The Revit API also exposes the parameter “Mirror” to let us know if an specific element has been mirrored using Mirror tool. In the case of the doors note that a Mirrored door reports the same parameters values as if we used the Flip controls

So we can know a door orientation by reading HandFlipped & FacingFlipped parameters.

But what if the doors are hosted on a linked model that had been placed mirrored from its original position?

Follow me on this. If I place a link mirror on my model, all the information we read from doors is inverted – e.g. a HandFlipped = True is actually False regarding the actual location in the main model.  Makes sense?

To make it a little more complicated, each building is hosted on a Neighborhood (Consorcio in Spanish).

An our main link has several neighborhoods  placed around the site.

 

The code

Disclaimer : Please be aware this may not work on your model as it’s custom made for our project. We advice you to copy concepts and ideas and implement on your specific use case.

To solve this problem we made a python script – running in Revit Python Shell – to export the information into a csv file. Remember we can’t write information to link and we don’t want to. Some links were placed twice to represent a mirrored building so the parameters in door are useless.

Remember we can’t write information to link and we don’t want to. Some links were placed twice to represent a mirrored building so the parameters in door are useless.

First got a list of linked files (“Neighborhood”) in the model

# Build list of RevitLinkInstances
docs = FilteredElementCollector(doc)\
.OfCategory(BuiltInCategory.OST_RvtLinks)\
.WhereElementIsNotElementType()\
.ToElements()

For each Link/Neighborhood we call the function DoorCollector():

doors = [ DoorCollector(x) for x in docs]

 

DoorCollector retrieves general information from each door contained on the link, like category,  level, height, width, etc but also the building model name, if the door is reflected and if the building is reflected.

def DoorCollector(document):
    '''Search doors in linked model
    
    document -- OST_RvtLinks
    
    '''
    docL = document.GetLinkDocument()
    builtInCats = List[BuiltInCategory]()
    builtInCats.Add(BuiltInCategory.OST_Doors)
    builtInCats.Add(BuiltInCategory.OST_Windows)

    CatFilter = ElementMulticategoryFilter(builtInCats)

    doors = FilteredElementCollector(docL)\
    .WherePasses(CatFilter)\
    .WhereElementIsNotElementType()\
    .ToElements()
	
    #TODO: change to one line per loop
    category= [x.Category.Name for x in doors]
    names = [x.Name for x in doors]
    ids = [x.Id.ToString() for x in doors]
    level = [getDoorLevel(x) for x in doors]
    Height = [getDoorHeight(x) for x in doors]
    Width = [getDoorWidth(x) for x in doors]
    Neighborhood= [ Neighborhood(document) for x in doors ]
    Building=[ x.Document.Title for x in doors]
    BuildingFlipped = [IsModelReflected(docL) for x in doors]
    Mirror = [x.Mirrored for x in doors]
    comment = [x\
.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)\
.AsValueString() for x in doors]

	
    output =zip(
        category, 
        names,
        ids,
        level,
        Height ,
        Width,
        Neighborhood,
        Building,
        BuildingFlipped,
        Mirror,
        comment
        )

    print(output)
    return output

 

The most interesting functions are Neighborhood, which looks for the neighborhood model name, and IsModelReflected which returns true if the building is reflected.

#Query the parent model name
def Neighborhood(document):
	'''Gets the parent link model name

    Args: 
    document -- OST_RvtLinks
    '''
	output = 'Error'
	typeDoc =doc.GetElement(document.GetTypeId())
	LinkDoc =doc.GetElement(typeDoc.GetParentId())
	output = LinkDoc\
        .get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM)\
        .AsString()

	return output

def IsModelReflected(docL):
    '''Returns bool for model reflection
    
    Args:
    docL -- Linked Document
    '''
    models = FilteredElementCollector(docL)\
    .OfCategory(BuiltInCategory.OST_RvtLinks)\
    .WhereElementIsNotElementType()\
    .ToElements()

    collector = {GetDocTitle(x) : x  for x in models }
    transform = None
    if collector.get(docL.Title, False):
        docInstance = collector[docL.Title]
        transform = docInstance.GetTransform()
        transform = transform.HasReflection
    return transform

 

All this information is saved on a CSV file located on the Desktop of the user

with open(os.path.expanduser("~/Desktop") + r"/doors.csv" ,'wb') as out:
    csv_out=csv.writer(out)
    csv_out.writerow([
        'Category',
        'Type',
        'id',
        'Level',
        'Height ', 
        'Width',
        'Neighborhood',
        'Building',
        'Building mirror',
        'Door mirror',
        'comment'])
    for row in doors:
        csv_out.writerows(row)

 

Below is the complete code of the script.

import csv
import os
#Revit libraries
app = __revit__.Application
doc = __revit__.ActiveUIDocument.Document
clr.AddReference('RevitAPI') 
clr.AddReference('RevitAPIUI') 
from Autodesk.Revit.DB import * 
from System.Collections.Generic import *

#Query the parent model name
def Neighborhood(document):
	'''Gets the parent link model name

    Args: 
    document -- OST_RvtLinks
    '''
	output = 'Error'
	typeDoc =doc.GetElement(document.GetTypeId())
	LinkDoc =doc.GetElement(typeDoc.GetParentId())
	output = LinkDoc\
        .get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM)\
        .AsString()

	return output

def GetDocTitle(document):
    '''Returns document Name
    
    Args:
    document -- OST_RvtLinks
    '''
    Title = document.Document.Title
    return Title

def IsModelReflected(docL):
    '''Returns bool for model reflection
    
    Args:

    '''
    models = FilteredElementCollector(docL)\
    .OfCategory(BuiltInCategory.OST_RvtLinks)\
    .WhereElementIsNotElementType()\
    .ToElements()

    collector = {GetDocTitle(x) : x  for x in models }
    transform = None
    if collector.get(docL.Title, False):
        docInstance = collector[docL.Title]
        transform = docInstance.GetTransform()
        transform = transform.HasReflection
    return transform

def getDoorLevel(element):

    level = element.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM)\
    .AsValueString()
    return level

def getDoorWidth(element):
    Type = element.Symbol
    return Type.get_Parameter(BuiltInParameter.DOOR_WIDTH)\
    .AsValueString()

def getDoorHeight(element):
    Type = element.Symbol
    return Type.get_Parameter(BuiltInParameter.GENERIC_HEIGHT)\
    .AsValueString()

def DoorCollector(document):
    '''Search doors in linked model
    
    document -- OST_RvtLinks
    
    '''
    docL = document.GetLinkDocument()
    builtInCats = List[BuiltInCategory]()
    builtInCats.Add(BuiltInCategory.OST_Doors)
    builtInCats.Add(BuiltInCategory.OST_Windows)

    CatFilter = ElementMulticategoryFilter(builtInCats)

    doors = FilteredElementCollector(docL)\
    .WherePasses(CatFilter)\
    .WhereElementIsNotElementType()\
    .ToElements()
	
    #TODO: change to one line per loop
    category= [x.Category.Name for x in doors]
    names = [x.Name for x in doors]
    ids = [x.Id.ToString() for x in doors]
    level = [getDoorLevel(x) for x in doors]
    Height = [getDoorHeight(x) for x in doors]
    Width = [getDoorWidth(x) for x in doors]
    Neighborhood= [ Neighborhood(document) for x in doors ]
    Building=[ x.Document.Title for x in doors]
    BuildingFlipped = [IsModelReflected(docL) for x in doors]
    Mirror = [x.Mirrored for x in doors]
    comment = [x\
.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)\
.AsValueString() for x in doors]

	
    output =zip(
        category, 
        names,
        ids,
        level,
        Height ,
        Width,
        Neighborhood,
        Building,
        BuildingFlipped,
        Mirror,
        comment
        )

    print(output)
    return output

#region Run
# Build list of RevitLinkInstances
docs = FilteredElementCollector(doc)\
.OfCategory(BuiltInCategory.OST_RvtLinks)\
.WhereElementIsNotElementType()\
.ToElements()


doors = [ DoorCollector(x) for x in docs]

with open(os.path.expanduser("~/Desktop") + r"/doors.csv" ,'wb') as out:
    csv_out=csv.writer(out)
    csv_out.writerow([
        'Category',
        'Type',
        'id',
        'Level',
        'Height ', 
        'Width',
        'Neighborhood',
        'Building',
        'Building mirror',
        'Door mirror',
        'comment'])
    for row in doors:
        csv_out.writerows(row)
#endregion

 

The idea is to show you can handle door orientations on nested documents. This was not a normal job, but the idea remains the same no matter how many levels of nesting you may have.

We hope you find it useful!

Leave a Reply

Your email address will not be published. Required fields are marked *