Revit – Dynamo script to cut pipes and ducts

cut pipes and ducts

We were planning to change our current workflow to split ducts and pipes in order to include more features into the process. At the moment the suite of add-ins we use don’t suit our needs 100% and we have to go through many steps to get to the final product.
This is the reason we started building our own add-in including all our production requirements.
As part of a scope discovery process, we mocked up the different parts of the final solution using Dynamo as a sandbox to later be included into a single Revit add-in.

We would like share with you the user requirements of the pipe/duct splitting process and how we solve it using Dynamo.

revit dynamo script
revit dynamo script

Select pipes and filter by length

The first step is to collect all pipes in the model and filter them by system and the by max length. Later in the process the system selection will be done by a GUI drop down. User must be allowed to select directly from Revit’s UI.

revit dynamo script
Select all pipes, filter by System Classification, Filter by pipe length.

We need to add the length of the coupling to the total calculation. This parameter depends on the diameter of the pipe and works related to the fitting Lookup tables. We use a hard coded dictionary where the key is the diameter of the pipe (in inches) and a value with the fitting length (in feet). Diameters are doubles and need to be formatted to be used as keys. We use a small python script to do this "OUT = ['{:.2f}'.format(x) for x in IN[0]]"; where we format the length to 2 decimals.

revit dynamo script

Place a point at segment end

We create a point at the pipes curves using the segment lengths plus the couplings. Remember we need to include the coupling into the calculation because it will “steal” part of the pipe length when it’s placed later in the process.

revit dynamo script
While the segments must include a whole coupling, the first segment needs to be segment + half coupling because we already have defined the origin of the pipe an it will not change.

Split pipes

Since the Revit 2017 API we can use a method called BreakCurve which splits a MEPCurve (Duct, Pipe) into segments by a point. Note we are using PlumbingUtils.BreakCurve to split the pipes but it’s the same procedure for MechanicalUtils.BreakCurve which will split ducts.
To apply it on our workflow we call it like this:

newPipeId = BreakCurve(doc, pipe.Id, point)
newPipe = doc.GetElement(newPipeId)

This will result on a ElementId from the new pipe created.

Join pipes with fitting

Now we have two pipes and we need to get the connector we will join. We iterate over the connectors and only use the ones with coincident coordinates.

#Get the pipe connectors
newPipeConnectors = newPipe.ConnectorManager.Connectors
 
#Create connection variables
connA, connB = None, None
 
for c in pipe.ConnectorManager.Connectors:
    pc = c.Origin
    #get connectorB near to connectorA
    nearest = [x for x in newPipeConnectors if pc.DistanceTo(x.Origin) < 0.01]
    #If exists asign to variables
    if nearest:
        connA = c
        connB = nearest[0]
#doc Create fitting
takeoff = doc.Create.NewUnionFitting(connA, connB)

The results

Finally, we now got all the pipes in the model – with a length > than the max segment and with a specific System Classification – split by the segment length.

revit dynamo script

Now we can plug in the next step in our new process.

Complete python script

Here is a complete python script that splits and joins the pipes. As you can see, the code it’s quite straight forward due to the API methods exposed by Revit.

# Enable Python support and load DesignScript libraryimport clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
 
clr.AddReference("RevitAPI")clr.AddReference("RevitServices")
# import document manager
from RevitServices.Persistence import DocumentManager
# import transaction manager
from RevitServices.Transactions import TransactionManager
# instantiate current document
doc = DocumentManager.Instance.CurrentDBDocument
from Autodesk.Revit.DB.Plumbing.PlumbingUtils 
import BreakCurvefrom Autodesk.Revit.DB import XYZ
 
# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
 
#Get pipes and unwrap
pipes = UnwrapElement(IN[0])
points = IN[1]
 
# start transaction
TransactionManager.Instance.EnsureInTransaction(doc)
for i, pipe in enumerate(pipes):
    for p in points[i]:
        try:
            #Point to XYZ
            point = XYZ(p.X, p.Y, p.Z)
            newPipeId = BreakCurve(doc, pipe.Id, point)
            #Get new pipe
            newPipe = doc.GetElement(newPipeId)
            #Get new pipe connectors
            newPipeConnectors = newPipe.ConnectorManager.Connectors
            #Check
            connA = None
            connB = None
            for c in pipe.ConnectorManager.Connectors:
                pc = c.Origin
                #get connectorB near to connectorA
                    nearest = [x for x in newPipeConnectors if pc.DistanceTo(x.Origin) < 0.01]
                #If exists asign
                if nearest:
                    connA = c
                    connB = nearest[0]
            #doc Create fitting
            takeoff = doc.Create.NewUnionFitting(connA, connB)
        except:
            pass
 
# transaction done
TransactionManager.Instance.TransactionTaskDone()
# Assign your output to the OUT variable.
OUT = 0

Pablo Derendinger
Innovation Team | GeeksGang

Call us: (949) 340-6924

Subscribe to our newsletter

Sign up here to get the latest BIM news and tips, as well as ENG updates.

Related posts