Hey, I’m getting an error when trying to rotate multiple elements based on a reference element.
The issue seems to happen in the part where the script handles the XYZ vectors. (Line 116)
Does anyone know what I’m doing wrong?
import clr
import math
# Revit API
clr.AddReference("RevitAPI")
clr.AddReference("RevitServices")
from Autodesk.Revit.DB import (
FamilyInstance,
XYZ,
Line,
ElementTransformUtils
)
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
# ---------------------------------------------------------
# INPUT
# IN[0] : Select Model Elements (meerdere elementen)
# IN[1] : Select Model Element (referentie-element)
# ---------------------------------------------------------
sel_in = IN[0]
ref_in = IN[1]
# Altijd werken met een lijst
if isinstance(sel_in, list):
elements_in = sel_in
else:
elements_in = [sel_in]
def to_db(e):
"""Dynamo wrapper -> Revit DB element."""
return getattr(e, "InternalElement", e)
elements = [to_db(e) for e in elements_in]
ref_element = to_db(ref_in)
# Referentie moet een FamilyInstance zijn met FacingOrientation
if not isinstance(ref_element, FamilyInstance):
raise Exception("Referentie-element is geen FamilyInstance. Kies een loadable / host-based family instance.")
ref_vec = ref_element.FacingOrientation # XYZ
# ---------------------------------------------------------
# Helper: signed angle tussen twee Revit XYZ vectors in XY-vlak
# - gebruikt AngleTo (0..PI)
# - gebruikt CrossProduct.Z om links/rechts te bepalen
# ---------------------------------------------------------
def signed_angle_xy(from_vec, to_vec):
"""
Geeft signed rotatiehoek om Z-as om 'from_vec' naar 'to_vec' te draaien.
Return in radians, bereik ongeveer [-PI, PI].
"""
if from_vec is None or to_vec is None:
return None
# Hoekgrootte (0..PI)
angle = from_vec.AngleTo(to_vec) # radians
# Kruisproduct: richting van rotatie-as
cross = from_vec.CrossProduct(to_vec)
z = cross.Z
# Als bijna geen Z-component: hoek is 0 of PI, teken maakt niet uit
if abs(z) < 1e-9:
return angle
sign = 1.0 if z > 0.0 else -1.0
return angle * sign
rotated = []
# ---------------------------------------------------------
# TRANSACTIE
# ---------------------------------------------------------
TransactionManager.Instance.EnsureInTransaction(doc)
for e in elements:
# Alleen FamilyInstance verwerken
if not isinstance(e, FamilyInstance):
rotated.append(e)
continue
# Referentie zelf overslaan
if e.Id == ref_element.Id:
rotated.append(e)
continue
# FacingOrientation van current element
try:
cur_vec = e.FacingOrientation # XYZ
except:
rotated.append(e)
continue
angle = signed_angle_xy(cur_vec, ref_vec)
# Geen bruikbare hoek -> skip
if angle is None or abs(angle) < 1e-6:
rotated.append(e)
continue
# Locatie moet een LocationPoint hebben
loc = e.Location
if not hasattr(loc, "Point"):
rotated.append(e)
continue
pt = loc.Point # XYZ
# Rotatie-as: lijn door insertiepunt, in Z-richting
axis = Line.CreateBound(pt, pt + XYZ(0, 0, 1))
# Element roteren
ElementTransformUtils.RotateElement(doc, e.Id, axis, angle)
rotated.append(e)
TransactionManager.Instance.TransactionTaskDone()
OUT = rotated