Vertical cable tray loaded in wrong direction

Hello.
I loaded cable tray data(start & end point) from PDMS and created on Revit through Dynamo and I thought that I made it until I found some vertical cable trays loaded in wrong way as below.
Not all the trays were not created in wrong way but, what’s the difference between them?
And how can I solve this problem?

Here’s my code.

Hi @hejeon00,

The problem will probably be in the Custom node at the end, from which package is it?

I don’t have much experience with Cable trays, but it seems that the wrong ones cant figure how they should be oriented. I figure Revit normally looks at the previous cable tray and it should follow that direction

Thanks for you reply Joelmick. The “Custom node” you mentioned is MEPover Package.
You can download it from Dynamo library.
But i don’t think there’s no problem with the node at the end. :frowning:

The cable trays are created perpendicular to the curve normal. To find out the curve’s normal you can use the node ‘Curve.NormalAtParameter’. This will at least give you some insight into why the cable trays are positioned the way that they are.

1 Like

Hi,

I checked your graph and that one is fine. The only problem is the vertical lines which the CableTray.ByLines was not designed for. A vertical line doesn’t have a clear “normal”, because it can be in any direction. The normal of a line tells Revit where the Cable Tray should be facing and since a vertical line doesn’t have a good normal, Revit uses a Default direction (facing north). This causes the weird rotation.

A quick and dirty solution is to make the vertical line slightly slanted:

I would be nice for the futher is the owner of MEPOver would tackle this problem, since this can be fixed in in the Cable Tray node

It’s been a while since I used the node for vertical cable tray creation, but I think I solved it by figuring out the curve normal for the lines. The normal should be on the same plane, but will vary depending on the direction of the line (up or down). When you’ve figured out the normal direction of the curve you can compare it to the desired rotation of the cable tray. After creating the cable trays you can then rotate the vertical cable trays by the difference in curve normal direction and the desired cable tray direction.

I have added a function to the python. You can copy the code into the MEPOver Node and it will work.
It checks if the Line is vertical and if it is vertical it will look at the previous curve for its direction (since you will never have 2 vertical lines after each other, cuz that would be very special I think). It also gets the right direction when the previous curve is horizontal.

import clr

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

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

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def FixVerticalCurve(line, guideLine = None):
    startX = round(line.StartPoint.X)
    startY = round(line.StartPoint.Y)
    endX = round(line.EndPoint.X)
    endY = round(line.EndPoint.Y)
    if guideLine != None:
        if startX == endX and startY == endY:
            debug = []
            normal = guideLine.CoordinateSystemAtParameter(0.5).ZAxis
            direction = guideLine.Direction
            if round(normal.X) == 0 and round(normal.Y) == 0:
                vector = direction
            else:
                vector = Autodesk.DesignScript.Geometry.Vector.ByCoordinates(normal.X, normal.Y, 0)
        else:
            vector = line.CoordinateSystemAtParameter(0.5).ZAxis
    else:
        vector = line.CoordinateSystemAtParameter(0.5).ZAxis
    return vector

toggle = ""

if isinstance(IN[0], list):
    lines = IN[0]
else:
    lines = [IN[0]]
FirstPoint = [x.StartPoint for x in lines]
SecondPoint = [x.EndPoint for x in lines]
cabletraytype = UnwrapElement(IN[1])
if isinstance(IN[2], list):
    level = UnwrapElement(IN[2])
    toggle += "0"
else:
    level = [UnwrapElement(IN[2])]
if isinstance(IN[3], list):
    width = IN[3]
    toggle += "1"
else:
    width = [IN[3]]
if isinstance(IN[4], list):
    height = IN[4]
    toggle += "1"
else:
    height = [IN[4]]

elements = []
vectors = []

# Calculate the Direction of the Cable Trays
for i in range(len(lines)):
    line = lines[i]
    if i == 0:
        guideLine = None
    else:
        guideLine = lines[i-1]
    vector = FixVerticalCurve(line, guideLine)
    vectors.append(vector.ToXyz())

if toggle == "":
    TransactionManager.Instance.EnsureInTransaction(doc)
    for i,x in enumerate(FirstPoint):
        tray = Autodesk.Revit.DB.Electrical.CableTray.Create(doc,cabletraytype.Id,FirstPoint[i].ToXyz(),SecondPoint[i].ToXyz(),level[0].Id)
        
        param = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM)
        param.SetValueString(width[0].ToString())
        
        param2 = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM)
        param2.SetValueString(height[0].ToString())
        
        #Set the Right Rotation
        tray.CurveNormal = vectors[i]

        elements.append(tray.ToDSType(False))

    TransactionManager.Instance.TransactionTaskDone()
    
elif toggle == "0":
    TransactionManager.Instance.EnsureInTransaction(doc)
    for i,x in enumerate(FirstPoint):
        tray = Autodesk.Revit.DB.Electrical.CableTray.Create(doc,cabletraytype.Id,FirstPoint[i].ToXyz(),SecondPoint[i].ToXyz(),level[i].Id)
        
        param = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM)
        param.SetValueString(width[0].ToString())
        
        param2 = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM)
        param2.SetValueString(height[0].ToString())
        
        #Set the Right Rotation
        tray.CurveNormal = vectors[i]
        
        elements.append(tray.ToDSType(False))

    TransactionManager.Instance.TransactionTaskDone()
    
elif toggle == "11":
    TransactionManager.Instance.EnsureInTransaction(doc)
    for i,x in enumerate(FirstPoint):
        tray = Autodesk.Revit.DB.Electrical.CableTray.Create(doc,cabletraytype.Id,FirstPoint[i].ToXyz(),SecondPoint[i].ToXyz(),level[0].Id)
        
        param = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM)
        param.SetValueString(width[i].ToString())
        
        param2 = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM)
        param2.SetValueString(height[i].ToString())
        
        #Set the Right Rotation
        tray.CurveNormal = vectors[i]

        elements.append(tray.ToDSType(False))

    TransactionManager.Instance.TransactionTaskDone()
    
elif toggle == "011":
    TransactionManager.Instance.EnsureInTransaction(doc)
    for i,x in enumerate(FirstPoint):
        tray = Autodesk.Revit.DB.Electrical.CableTray.Create(doc,cabletraytype.Id,FirstPoint[i].ToXyz(),SecondPoint[i].ToXyz(),level[i].Id)
        
        param = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM)
        param.SetValueString(width[i].ToString())
        
        param2 = tray.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM)
        param2.SetValueString(height[i].ToString())
        
        #Set the Right Rotation
        tray.CurveNormal = vectors[i]

        elements.append(tray.ToDSType(False))

    TransactionManager.Instance.TransactionTaskDone()


OUT = elements
2 Likes

Ah, that’s really nice Joel, I did not know that the CurveNormal property of the CableTray can also be set.
Mind if I use your code for the CableTray.ByLines node?

1 Like

Nope not at all, I tailor made it for the node, I hope it keeps working😬

Great, thanks. I’ll double check it to be sure, I’ll make a comment in the code to mention you :slight_smile:

2 Likes

I solved the problem!! Thank you so much!
But now I have one more problem.
I mean…I can’t understand the python code you uploaded at all.
What have you done with the codes???
I need to study very hard to catch up with you as soon as possible.

Anyway thanks too much!

Hi,

I would suggest that you now focus on Dynamo itself (which is already going smoothly looking at you graph). The next step would be Python and after that Python + Revit API.

My python code is the original Python code of the CableTrays.ByLines + 1 extra function. The input for this function is 2 things: A line (the one we are evaluating) and another Line (which is a guideLine)

We use the function in a Loop, so we Loop over a List Line by Line. We check if the Line is vertical and we calculate the right rotation for the cable tray using the GuideLine. For the GuideLine we use the previous line in the list for that)
The guideLine has a default value of null if we don’t have a guideLine (the first line doens’t have a previous line)

the step by step is:

  1. We get the X and Y values for the StartPoint and the EndPoint of the Line we are evaluating.
  2. We check if there is a GuideLine. If there is not, we use the default rotation (Facing North).
  3. If there is a GuideLine, we check if both X’s and Y’s are the same, because if this is true, the line is vertical, which means Revit will rotate the cable tray to the north automatially.
  4. If the line is vertical, we have to look at the previous line (the guideline) to see which direction we need the cable tray to face. For this we use the direction of the line (A Vector).
def FixVerticalCurve(line, guideLine = None):
    startX = round(line.StartPoint.X)
    startY = round(line.StartPoint.Y)
    endX = round(line.EndPoint.X)
    endY = round(line.EndPoint.Y)
    if guideLine != None:
        if startX == endX and startY == endY:
            debug = []
            normal = guideLine.CoordinateSystemAtParameter(0.5).ZAxis
            direction = guideLine.Direction
            if round(normal.X) == 0 and round(normal.Y) == 0:
                vector = direction
            else:
                vector = Autodesk.DesignScript.Geometry.Vector.ByCoordinates(normal.X, normal.Y, 0)
        else:
            vector = line.CoordinateSystemAtParameter(0.5).ZAxis
    else:
        vector = line.CoordinateSystemAtParameter(0.5).ZAxis
    return vector

I hope this is a bit clearer for you, I could probably also do this with Dynamo Nodes, but it was easier and cleaner with Python :sweat_smile: