First attempt Editing a Python script

Hi All,

The below Python script first get’s the AssemblyOrigin of an AssemblyInstance.
GetTransform
Next step is the rotation of this AssemblyOrigin.
CreateRotationAtPoint
This is the part that doesn’t work properly. The AssemblyOrigin is rotated, but it seems to take a random basepoint for this rotation. It is my goal that it rotates around its own (z)axis.
I understand what the code does, but i’m not a programmer so i don’t know how to edit the (or add) code.
I hope someone is willing to help me out.

import clr
import math
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
app = DocumentManager.Instance.CurrentUIApplication.Application

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

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

def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

elems = tolist(UnwrapElement(IN[0]))
axis = tolist(IN[1])
rot = tolist(IN[2])

outList = []

for e, a, r in zip(elems, axis, rot):
        trans = e.GetTransform()
    	transRot = trans.CreateRotationAtPoint(a.ToXyz(),math.radians(r), trans.Origin)
	try:
		TransactionManager.Instance.EnsureInTransaction(doc)
    	e.SetTransform(transRot)
		TransactionManager.Instance.TransactionTaskDone()
		outList.append(e)
	except Exception, e:
	outList.append(e.message)

OUT = outList

picture%204

Before running the Python script

picture%205

After running the Python script

picture%206

Any help is much appreciated.

Kind regards,
Mark

1 Like

HI Erik,

Maybe ik looks like it has some similarities, but this a complete new one :grinning:

Kind regards,
Mark

This is just a guess but using the Vector.ZAxis is essentially a vector(0,0,1) and which works in Dynamo but when used in Revit, you convert it to a point (0,0,1) and you would be rotating using this as the center point, right? So you are rotating the element around basically the origin of the project. Instead, you want the center point of element. I’m not good enough at API to know how to get that but I think that would be where you start?

1 Like

Hi @kennyb6,

I made an attempt to create an axis(line) at the Origin of the Assembly.
I added two lines of code (bp and axis).
In the next line of code i replaced “a.ToXyz()” by “axis”.

    for e, a, r in zip(elems, axis, rot):
	    trans = e.GetTransform()
	    bp = trans.Origin
	    axis = Line.CreateBound(bp, XYZ(bp.X, bp.Y, bp.Z+1.0))
	    transRot = trans.CreateRotationAtPoint(axis, math.radians(r), bp)
	    try:

This code results in the below error.

imageedit_1_8164289079

Does anyone have smart ideas ?

Thanks in advance,
Mark

The error says it all, pretty much. You made axis a line, but it wants a point XYZ. Have you tried using bp as the axis?

Also, read this thread: https://forums.autodesk.com/t5/revit-api-forum/cannot-figure-out-how-the-transform-createrotationatpoint-works/td-p/5663052

It looks like what you should be using is Transform.CreateRotation(XYZ axis, double angle)

To use the Transform.CreateRotationAtPoint method, it looks like you need to use axis = XYZ.BasisZ as the axis.

Yes i did, but that gives me weird results (because it don’t know in wich direction it should rotate anymore).

That way i can’t define the basepoint anymore (i want to rotate the AssemblyOrigin around it’s own axis).

That would give me the result below
imageedit_1_9765055701

I did another attempt to modify the above Python code.
It works now the way i would like it to, but only for one element.
If i feed it with a list of elements only the last one is modified :disappointed_relieved:
Can anyone tell me why the code doesn’t work for multiple elements ?

import clr
import math
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
app = DocumentManager.Instance.CurrentUIApplication.Application

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

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

def tolist(obj1):
    if hasattr(obj1,"__iter__"): return obj1
    else: return [obj1]

run = tolist(IN[0])[0]
elems = tolist(UnwrapElement(IN[1]))
Xvector = tolist(IN[2])
Yvector = tolist(IN[3])
Zvector = tolist(IN[4])

outList = []
if run:
    for e, xv, yv, zv in zip(elems, Xvector, Yvector, Zvector):

	    trans = e.GetTransform()
	    trans.BasisX = xv.ToXyz()
	    trans.BasisY = yv.ToXyz()
	    trans.BasisZ = zv.ToXyz()
	    try:
		    TransactionManager.Instance.EnsureInTransaction(doc)
		    e.SetTransform(trans)
		    TransactionManager.Instance.TransactionTaskDone()
		    outList.append(e)
	    except Exception, e:
		    outList.append(e.message)
    OUT = outList
else:
    OUT = "Please set Run to True" 

Kind regards,
Mark

Coming in late to the conversation but you can see awilliams code here. It works with just one element (my scripting is not quite there to get it to a list). It seams to be the same problem you are having but figured I wouls share since they are similar.

1 Like

Hard to tell what is wrong here without access to the Revit project or script. I am assuming you have the same number for all of the python inputs (8 of each input, except IN[0]). I don’t know if the unwrapping makes a difference as I always unwrap each element individually, not as a list. Try this script if it makes any difference:

import clr
import math
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
app = DocumentManager.Instance.CurrentUIApplication.Application

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

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

def tolist(obj1):
    if hasattr(obj1,"__iter__"): return obj1
    else: return [obj1]

run = tolist(IN[0])[0]
elem = []
for i in IN[1]:
  elem.append(UnwrapElement[i])
elems = tolist(elem)
Xvector = tolist(IN[2])
Yvector = tolist(IN[3])
Zvector = tolist(IN[4])

outList = []
if run:
    for e, xv, yv, zv in zip(elems, Xvector, Yvector, Zvector):

	    trans = e.GetTransform()
	    trans.BasisX = xv.ToXyz()
	    trans.BasisY = yv.ToXyz()
	    trans.BasisZ = zv.ToXyz()
	    try:
		    TransactionManager.Instance.EnsureInTransaction(doc)
		    e.SetTransform(trans)
		    TransactionManager.Instance.TransactionTaskDone()
		    outList.append(e)
	    except Exception, e:
		    outList.append(e.message)
    OUT = outList
else:
    OUT = "Please set Run to True"

Hi Kenny,

Thanks a lot for your response.
I tried your code, but unfortunately it gives me the below error.

I’m a Python Newby, but my gut feeling tells me there is something missing in the for loop part.

Assemblies_ModifyOrigin_v01.dyn (8.4 KB)
Assemblies_ModifyOrigin_v01.rvt (2.3 MB)

Kind regards,
Mark

In your file, what should I be expecting when I run the script? There are no errors but it doesn’t seem like there is any change within the Revit project.

It seems like you set their transform to itself, effectively doing nothing. Unless I am missing something here.

When you run the script only the origin of the last assembly (Generic Model 008) is modified.

It is my goal to manipulate the origin of all 8 assemblies.
So it should itter thru all elements, and modify each origin accordingly to it’s input.

When I tried your script, it didn’t change any of their positions, not even the last one. Is it possible that the node LocalCoordinateSystem gets the vectors based off of the transform of the object? If it does, then it would explain what was happening to me, where the script was successful but didn’t change anything. Try supplying it with the bounding box center’s vectors, or using different vectors to see if they all move or not.

You could even shuffle the vectors you get from the LocalCoordinateSystem node and see if each assembly’s transform moves to another to confirm my suspicions.

to avoid misunderstanding…
It’s my goal to rotate the origin of the assemblies, not to move them.

To manualy do this (or check it), Autodesk is telling to do it as below.
But it would be a pain to edit all assemblies and do it manually…
image

For the rest i will follow your advise, and try different input.

I used a “List.GetItemAtIndex” node and run the script on one element at a time.
All 8 elements gave the disired result, so there is no problem with the input of the vectors.
The only thing i can think of is that the Python (for loop), doesn’t handle the lists correctly.

So it isn’t because of the for loop or Python code I think.
trans2

Python is saying that the element’s transform was changed to the vectors that were inputted. For reference, a list in the watch node consists of this structure:
0 - Element
1 - List of original transform BasisX, Y, and Z
2 - Vectors inputted from BIM4Struc package
3 - List of transform Basis X, Y, and Z after the python script

Honestly I am as stumped as you are. You are right that it works one at a time and I have had the problem before where if I edit many revit elements within a single dynamo script, only the last one will show the changes until I update the model, which might be what is happening here but even when checking and moving the object, it doesn’t update.

Hopefully someone with more knowledge can shed some light. Try asking @Kulkul or @Dimitar_Venkov about this.

2 Likes

Hi Kenny,

Thank you very much for your time and effort to help me :thumbsup:
You definitely pointed me in the right direction, and i think i found a solution…
I used “ForceCloseTransaction” in stead of “TransactionTaskDone”.
I looks like the script needs a hard break after each run.

I have to do some cleanup first, but i will post my solution for anyone who is interested.

Kind regards,
Mark

2 Likes

Hi All,

For those of you who are interested, here’s my final Dynamo script.


Assemblies_ModifyOrigin_v04.dyn (5.7 KB)
I wrapped the Python script and “Element.LocalCoordinateSystem node” inside a custom node (local package).
Assemblies.ModifyOrigin.dyf (26.0 KB)
The script reads out the orientation of the (assembly) source elements, and uses that to rotate the origin of the assemblies. If you create assembly views (after running the script) these views are aligned with the element, regardless of the rotation of the element in the project. Without running the script assembly views are always aligned with the X, and Y-axis.

@Daniel_Woodcock1: Thanks a lot for providing the initial scripts.
https://forum.dynamobim.com/t/assembly-modify-origin/11433/7?u=mjb-online
@Dieter_Vermeulen: Thanks a lot for the “Element.LocalCoordinateSystem” node.
@kennyb6, @Petar_Penchev1, @viktor_kuzev, and @Steven thanks a lot for your effort to help me, and pointing me in the right direction.

Kind regards,
Mark

14 Likes

Hi Mark! @MJB-online

I’ve been reading through your posts, I am facing a similar task. Inside your custom node, do you know what package “element.HandOrientation” belongs to?

Thanks for your help!

1 Like