Hello everyone. I’m not a programmer, but I’m trying to automize floor and wall openings in revit.
So basically I took a script but it didnt work for me.The script works in communication model with architectural model linked.I found that it doesn’t look right, like it doesn’t take all the stuff from a link. So I used python script to get the linked document (in[10]) It was able to pick up walls and floors. However I couldn’t identify further issues. The current Error I get: The level does not exist in the given document. (in createOpenings function). Thats my current code
I’m pretty sure its due to mess with a linked document.
#-------------------------------------------------------------------------------------------------------------------------
DOWNLOAD LIBRARIES
#-------------------------------------------------------------------------------------------------------------------------
import clr
import math
from System.Collections.Generic import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
# Define options Revit API
options = Options()
intersectionOptions = SolidCurveIntersectionOptions() # find intersection
nonStructural = Autodesk.Revit.DB.Structure.StructuralType.NonStructural # for pasting a family to a host
#Communication categories
pipeCategory = BuiltInCategory.OST_PipeCurves
ductCategory = BuiltInCategory.OST_DuctCurves
conduitCategory = BuiltInCategory.OST_Conduit
cableTrayCategory = BuiltInCategory.OST_CableTray
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
#-------------------------------------------------------------------------------------------------------------------------
# INPUT
#-------------------------------------------------------------------------------------------------------------------------
# Openings families
rectangularFamilyForWall = UnwrapElement(IN[0]) # rectangular for walls
roundFamilyForWall = UnwrapElement(IN[1]) # round for walls
rectangularFamilyForFloor = UnwrapElement(IN[2]) # rectangular for floors
roundFamilyForFloor = UnwrapElement(IN[3]) # round for floors
# Selected construction elements
selectElements = UnwrapElement(IN[4])
try:
selectElements.Count
except:
if selectElements is not None:
selectElements = [UnwrapElement(IN[4])]
# Openings margin
isReservByCoefficient = IN[5] # ByCoefficient?
if isReservByCoefficient:
reserv = IN[6] # margin by sides proportion
else:
reserv = IN[6] / 304.8 # margin in mm
# Condition for round openings
maxAspectRatio = IN[7] # max comminication dimension ratio
maxDiameter = IN[8] / 304.8 # max diameter
# Linked files
isLinkDocument = IN[9] # constructions in linked file?
nameLinkDocument = IN[10] # a part of a linked file name
# Constructions processing
includeWalls = IN[11] # walls ?
includeFloors = IN[12] # floors?
# Parameter values for openings
comment = IN[13] # date or other comment
disciplineName = IN[14] # opening discipline
# Opening parameters names
disciplineParameter = IN[15]
diameterParameter = IN[16]
widthParameter = IN[17]
heightParameter = IN[18]
commentParameter = IN[19]
#-------------------------------------------------------------------------------------------------------------------------
# EXTRACTING DATA
#-------------------------------------------------------------------------------------------------------------------------
# Current file
currentDoc = DocumentManager.Instance.CurrentDBDocument
# File with construction
docWithConstruction = UnwrapElement(IN[10])
#-------------------------------------------------------------------------------------------------------------------------
# CREATING CLASSES AND FUNCTIONS
#-------------------------------------------------------------------------------------------------------------------------
# Wall class
class WallObject:
# Properties
def __init__(self, instance, width, A, B, solid, level):
self.instance = instance
self.width = width
self.A = A
self.B = B
self.solid = solid
self.level = level
# Floors
class FloorObject:
def __init__(self, instance, solid, level):
self.instance = instance
self.solid = solid
self.level = level
# Communications
class CommunicationObject:
def __init__(self, width, height, A, B, C, direction, centerPoint):
self.width = width
self.height = height
self.A = A
self.B = B
self.C = C
self.direction = direction
self.centerPoint = centerPoint
# Getting coordinates of starting and ending point of a line
def getLineCoordinates(line):
endPoint0 = line.GetEndPoint(0)
endPoint1 = line.GetEndPoint(1)
x0 = endPoint0.X; y0 = endPoint0.Y; z0 = endPoint0.Z
x1 = endPoint1.X; y1 = endPoint1.Y; z1 = endPoint1.Z
coordinates = x0, y0, z0, x1, y1, z1
return coordinates
# Getting a construction volume geometry
def getSolid(construction):
geometry = construction.get_Geometry(options)
for object in geometry:
solid = object
return solid
# Creating Wall class object
def createWallObject(wall):
width = wall.Width
x0, y0, z0, x1, y1, z1 = getLineCoordinates(wall.Location.Curve)
A = y0 - y1
B = x1 - x0
solid = getSolid(wall)
level = docWithConstruction.GetElement(wall.LevelId)
wallObject = WallObject(wall, width, A, B, solid, level)
return wallObject
# # Creating Floor class object
def createFloorObject(floor):
solid = getSolid(floor)
level = docWithConstruction.GetElement(floor.LevelId)
floorObject = FloorObject(floor, solid, level)
return floorObject
# Getting model Instanses of different classes
def getInstances(revitClass):
instances = FilteredElementCollector(docWithConstruction).OfClass(revitClass).WhereElementIsNotElementType().ToElements()
return instances
# Create openings in construction element
def createOpenings(category, constructionObject):
# Create Communication
def createCommunication(communication):
# Getting communication section measurements
def getCommunicationSize():
# For pipes
if category == pipeCategory:
diameter = communication.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER).AsDouble()
width = diameter
height = diameter
# For ducts
elif category == ductCategory:
try:
diameter = communication.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).AsDouble()
width = diameter
height = diameter
except:
width = communication.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).AsDouble()
height = communication.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).AsDouble()
# For Conduit
elif category == conduitCategory:
diameter = communication.get_Parameter(BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM).AsDouble()
width = diameter
height = diameter
# For cables
else:
width = communication.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).AsDouble()
height = communication.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).AsDouble()
return width, height
# Getting coordinates of starting and ending point of a communication line
def getCommunicationLineCoordinates():
curve = communication.Location.Curve
lines = constructionObject.solid.IntersectWithCurve(curve, intersectionOptions)
try:
line = lines.GetCurveSegment(0)
except:
line = curve
coordinates = getLineCoordinates(line)
return coordinates
# Defining communication direction
def getCommunicationDirection():
# Defining the normal to a communication line for floor openings
def getFaceNormal():
geometry = communication.get_Geometry(options)
for object in geometry:
solid = object
faces = solid.Faces
for face in faces:
_faceNormal = face.FaceNormal
if _faceNormal.Z == 0:
faceNormal = _faceNormal
return faceNormal
if constructionObject.__class__.__name__ == 'FloorObject':
if category == ductCategory:
try:
diameter = communication.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).AsDouble()
direction = XYZ(0, 0, 0)
except:
direction = getFaceNormal()
elif category == cableTrayCategory:
faceNormal = getFaceNormal()
direction = XYZ(faceNormal.Y, -faceNormal.X, faceNormal.Z)
else:
direction = XYZ(0, 0, 0)
return direction
width, height = getCommunicationSize()
x0, y0, z0, x1, y1, z1 = getCommunicationLineCoordinates()
A = y0 - y1
B = x1 - x0
C = z1 - z0
direction = getCommunicationDirection()
centerPoint = XYZ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2)
# Communication create
communicationObject = CommunicationObject(width, height, A, B, C, direction, centerPoint)
return communicationObject
# Opening create
def createOpening(rectangularFamily, roundFamily, minWidth, minHeight, centerPoint, direction):
# Create opnings element and set parameters
def _createOpening(maxSide, minSide, openingWidth, openingHeight):
# Set diameter
if maxSide / minSide <= maxAspectRatio and maxSide <= maxDiameter:
if constructionObject.__class__.__name__ == 'WallObject':
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, roundFamily, constructionObject.instance, constructionObject.level, nonStructural)
else:
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, roundFamily, direction, constructionObject.instance, nonStructural)
_opening.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).Set(constructionObject.level.Id)
_opening.LookupParameter(diameterParameter).Set(maxSide)
# Set height width parameters
else:
if constructionObject.__class__.__name__ == 'WallObject':
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, rectangularFamily, constructionObject.instance, constructionObject.level, nonStructural)
else:
_opening = currentDoc.Create.NewFamilyInstance(centerPoint, rectangularFamily, direction, constructionObject.instance, nonStructural)
_opening.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).Set(constructionObject.level.Id)
_opening.LookupParameter(widthParameter).Set(openingWidth)
_opening.LookupParameter(heightParameter).Set(openingHeight)
return _opening
# Round opening check
if minWidth is not None and minHeight is not None:
# Margin account
if isReservByCoefficient: # если допуск задан коэффициентом
openingWidth = minWidth * reserv
openingHeight = minHeight * reserv
else: # если допуск задан в миллиметрах
openingWidth = minWidth + reserv
openingHeight = minHeight + reserv
# Round to cm
openingWidth = round(openingWidth * 304.8, -1) / 304.8
openingHeight = round(openingHeight * 304.8, -1) / 304.8
# Create opening
if openingHeight > openingWidth:
opening = _createOpening(openingHeight, openingWidth, openingWidth, openingHeight) # случай, если высота больше ширины
else:
opening = _createOpening(openingWidth, openingHeight, openingWidth, openingHeight) # случай, если ширина больше высоты
# Set other parameters
opening.LookupParameter(disciplineParameter).Set(disciplineName)
opening.LookupParameter(commentParameter).Set(comment)
return opening
# If could not create
else:
message = 'Communication is inside the construction'
return message
# Create opening in walls
def createWallOpening(communicationObject):
# Calculating min opening side
def getMinSide(cosin, communicationSide):
angle = round(math.degrees(math.acos(cosin)))
if angle > 90:
angle = 180 - angle
angleRad = math.radians(angle)
if angle != 180 and angle != 0:
#
minSide = constructionObject.width / math.tan(angleRad) + communicationSide / math.sin(angleRad)
return minSide
# Getting cosin of construction and communication intersection
try:
cosin = (constructionObject.A * communicationObject.A + constructionObject.B * communicationObject.B) / ((constructionObject.A**2 + constructionObject.B**2)**0.5 * (communicationObject.A**2 + communicationObject.B**2)**0.5)
except:
cosin = 1
minWidth = getMinSide(cosin, communicationObject.width)
# Getting intersection angle (between the pipe and horizontal plane)
cosin = communicationObject.C / ((communicationObject.A**2 + communicationObject.B**2 + communicationObject.C**2)**0.5)
minHeight = getMinSide(cosin, communicationObject.height) # min opening height
rectangularFamily = rectangularFamilyForWall # opening family
roundFamily = roundFamilyForWall # round opening family
# Create opening
wallOpening = createOpening(rectangularFamily, roundFamily, minWidth, minHeight, communicationObject.centerPoint, None)
return wallOpening
# Create floor openings
def createFloorOpening(communicationObject):
minWidth = communicationObject.width
minHeight = communicationObject.height
direction = communicationObject.direction
rectangularFamily = rectangularFamilyForFloor
roundFamily = roundFamilyForFloor
# Создание проёма
floorOpening = createOpening(rectangularFamily, roundFamily, minWidth, minHeight, communicationObject.centerPoint, direction)
return floorOpening
# Getting model communications
communications = FilteredElementCollector(currentDoc).OfCategory(category).WhereElementIsNotElementType()
# Gettting only intersected comminication
intersectingCommunications = communications.WherePasses(ElementIntersectsSolidFilter(constructionObject.solid)).ToElements()
# Forming openings list
openings = []
for communication in intersectingCommunications:
communicationObject = createCommunication(communication)
# For walls
if constructionObject.__class__.__name__ == 'WallObject':
opening = createWallOpening(communicationObject)
# For floors
else:
opening = createFloorOpening(communicationObject)
openings.append([communication, opening])
return openings
#-------------------------------------------------------------------------------------------------------------------------
# TRANSACTION
#-------------------------------------------------------------------------------------------------------------------------
# Getting constructions
walls = getInstances(Wall)
floors = getInstances(Floor)
TransactionManager.Instance.EnsureInTransaction(currentDoc)
if includeWalls:
rectangularFamilyForWall.Activate()
roundFamilyForWall.Activate()
wallOpenings = []
for wall in walls:
wallObject = createWallObject(wall)
for category in [pipeCategory, ductCategory, conduitCategory, cableTrayCategory]:
openings = createOpenings(category, wallObject)
wallOpenings.append(openings)
else:
wallOpenings = 'Walls processing disabled'
if includeFloors:
rectangularFamilyForFloor.Activate()
roundFamilyForFloor.Activate()
floorOpenings = []
for floor in floors:
floorObject = createFloorObject(floor)
for category in [pipeCategory, ductCategory, conduitCategory, cableTrayCategory]:
openings = createOpenings(category, floorObject)
wallOpenings.append(openings)
else:
floorOpenings = 'Floors processing disabled
TransactionManager.Instance.TransactionTaskDone()
#-------------------------------------------------------------------------------------------------------------------------
# OUT
#-------------------------------------------------------------------------------------------------------------------------
OUT = wallOpenings, floorOpenings