Efficient auto-join using Dynamo

[Similar problem in C# has been presented in another post]

Joining model elements in Revit can be a tedious task. Surely it is something that most of us would like to automate with Dynamo. Hopefully we can easily find some custom nodes that can join elements. We can also do it with Python using a Revit API funtion:

JoinGeometryUtils.JoinGeometry(doc,a,b)

where doc is a current document and a and b are elements to join.

Efficiency problems will occur however, especially in case of more complex models. If we were going to create a script that eg. would try to join every possible wall with every possible floor it would take a considerate amount of time to execute and could produce numerous errors. Such a script would try to join elements that are not connected and often quite remote. This cannot be efficient 🙂

So, before we try to join elements, it is worth checking whether they intersect or not. However, objects can often have a very complex geometry and thus such a check can also be time consuming. Therefore script presented below includes one more step. A preliminary check, that can quickly determine if tested elements are close enough to potentially intersect.

Every model element in Revit has a property called BoundingBox. Exactly as the name suggests, it is a smallest box that can fit the element. It can be relatively quickly tested whether two such boxes intersect or touch. Intersections test are way quicker for boxes than for complex geometry.

The code below takes as an input two lists of elements. Then, it test every element from the first list with every element from the second list – are their BoundingBoxes intersecting or not. As a result it outputs a list of pairs of elements that have intersecting boxes.

import clr

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

def overlap1D(a1, a2, b1, b2):
  if a2>=b1 and b2>=a1:
    return True
  return False
  
def bbIntersect(bbA, bbB):
  return overlap1D(bbA.Min.X,bbA.Max.X,bbB.Min.X,bbB.Max.X) and overlap1D(bbA.Min.Y,bbA.Max.Y,bbB.Min.Y,bbB.Max.Y) and overlap1D(bbA.Min.Z,bbA.Max.Z,bbB.Min.Z,bbB.Max.Z)

#The inputs to this node will be stored as a list in the IN variables.
listA = UnwrapElement(IN[0])
listB = UnwrapElement(IN[1])

output = []

for a in listA:
  bbA = a.get_BoundingBox(None)
  if not bbA is None:
    for b in listB:
      bbB = b.get_BoundingBox(None)
      if not bbB is None:
        if bbIntersect(bbA,bbB):
          output.append([a,b])

#Assign your output to the OUT variable.
OUT = output

This way we get a list of element pairs – potentially intersecting.

Below a Dynamo definition (download at the bottom) that will join all the walls and floors in the project for us:

The last node is also a custom Python piece of code joining two lists of elements:

import clr
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
#The inputs to this node will be stored as a list in the IN variables.
list_a = UnwrapElement(IN[0])
list_b = UnwrapElement(IN[1])

doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(doc)

output = []

for a,b in zip(list_a,list_b):
	try:
		JoinGeometryUtils.JoinGeometry(doc,a,b)
		output.append("OK")
	except Exception,e:
		output.append(str(e))


TransactionManager.Instance.TransactionTaskDone()

#Assign your output to the OUT variable.
OUT = output
Posts created 30

Leave a Reply

Your email address will not be published.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top