Hi Jeremy, thanks for your reply. I have been using a couple different approaches for different types of vertical cable trays (standard family and MEP Fabrication families). In both cases there is the problem of how do I know if an angle needs to be negative or positive, or perhaps add 360° to an angle to rotate it in the correct direction.
#method 1 for fabrication elements
def GetSignedAngleOnXY(basis, vec):
angle = math.atan2(vec.Y,vec.X) - math.atan2(basis.Y,basis.X)
return angle * (180/math.pi)
def GetTransformRotation(fabrication):
vector = fabrication.GetTransform().BasisZ
return GetSignedAngleOnXY(XYZ.BasisY, vector)
#method 2 for standard families
def get_service_rotation(serviceelement, link_trans):
elem_location = serviceelement.Location
options = Options()
options.DetailLevel = ViewDetailLevel.Medium
result = serviceelement.get_Geometry(options).GetTransformed(link_trans)
solids = [s for s in result]
solid = solids[0]
matchingFace = None
for face in solid.Faces:
if face.FaceNormal.IsAlmostEqualTo(elem_location.Curve.Direction):
matchingFace = face
vector = matchingFace.FaceNormal
origin = matchingFace.Origin
#direction = origin + vector
direction = XYZ(origin.X + vector.X, origin.Y + vector.Y, origin.Z + vector.Z)
min = 1e12
max = -1e12
max_edge = None
for edgeArrays in matchingFace.EdgeLoops:
for edge in edgeArrays:
si_length = edge.ApproximateLength * 304.8
if si_length > max:
max = si_length
max_edge = edge
if si_length < min:
min = si_length
is_north = XYZ.BasisY.DotProduct(max_edge.AsCurve().Direction) > 0
rotation = int(max_edge.AsCurve().Direction.AngleTo(XYZ.BasisY) * 180 / 3.14)
rotation = rotation if is_north else abs(rotation - 180)
return rotation
#get rotation angle with either method
angle_rads = #get angle with method 1 or 2
#create axis to rotate around
axis = Line.CreateBound(pnt_xyz, XYZ(pnt_xyz.X, pnt_xyz.Y, pnt_xyz.Z + 1))
#rotate the element
ElementTransformUtils.RotateElement(doc, horizfam.Id, axis, angle_rads)