Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Rotating the Assembly Origin

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
DavoudMWAWD
2868 Views, 12 Replies

Rotating the Assembly Origin

Hi All,

I am trying to rotate the assembly origin for several days now, although it might seem to be an easy task it is not for me. 

The problem is when I run the code, it rotates the assembly origin but it also moves the origin! which is not desired. I just want to rotate the origin around its own axis so that the origin does not move. 

Here is the code: (the assembly includes a wall, I find the location of the wall and try to rotate the assembly origin based on this point and the axis which crosses this point and is towards Z direction, please note that I pick the element based on its face.)

 

import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB import*
from Autodesk.Revit.Exceptions import*
import math as m
import sys

uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document

ref = uidoc.Selection.PickObject(ObjectType.Face, 'Please Pick NearFace')
wall = doc.GetElement(ref)
face = wall.GetGeometryObjectFromReference(ref)

assembly_id = wall.AssemblyInstanceId
assembly = doc.GetElement(assembly_id)
line = wall.Location.Curve #Defining the line to find the mid point of the wall so I rotate based on this point
mid_point = (line.GetEndPoint(1) + line.GetEndPoint(0))/2

axis = line.CreateBound(mid_point, XYZ(mid_point.X, mid_point.Y, 1)) #Axis of rotation
assembly_origin = assembly.GetTransform() #Getting the assembly_origin
rotation = assembly_origin.CreateRotationAtPoint(axis, m.radians(90), mid_point)

t = Transaction(doc, 'ROTATION')
t.Start()

assembly.SetTransform(rotation)

t.Commit()

result: 

rotation.PNG

I have tried other ways but all result in the same thing. I also read that I have to rotate it based on its local coordination but I don't know how!

Any help would be much appreciated. 

Thanks

12 REPLIES 12
Message 2 of 13
RPTHOMAS108
in reply to: DavoudMWAWD

One of the most straightforward ways of rotating an element is via it's location property (when it has one).

 

For a wall object the below code rotates a wall by the midpoint of it's location curve 'Curve.Evaluate(0.5, True)' about the static value XYZ.Basis.Z (0,0,1).

 

LC.Rotate(Line.CreateUnbound(LC.Curve.Evaluate(0.5, True), XYZ.BasisZ), Math.PI / 2)

 

For an assembly object the below code rotates the assembly via it location point.

 

LP.Rotate(Line.CreateUnbound(LP.Point, XYZ.BasisZ), Math.PI / 2)

 

Note that for newly created elements you must Regenerate the document (or commit transaction that added the elements) to make use of the location property this way. The location will have incorrect values until regeneration e.g. a location point is initialised with a value of 0,0,0 until after Regeneration, where the value is updated to reflect actual location. This would make a rotation based upon this similar to what you show (about the model origin). This is likely unrelated to your issue but important to remember.

 

 

 Private Function TObj156(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result

        Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
        If UIDoc Is Nothing Then Return Result.Cancelled Else
        Dim IntDoc As Document = UIDoc.Document
        Dim R As Reference = Nothing
        Try
            R = UIDoc.Selection.PickObject(Selection.ObjectType.Element)
        Catch ex As Exception
        End Try
        If R Is Nothing Then Return Result.Cancelled Else

        Dim El As Element = IntDoc.GetElement(R)
        If El.Location Is Nothing Then Return Result.Cancelled Else

        Using Tx As New Transaction(IntDoc, "Rotate 90")
            If Tx.Start = TransactionStatus.Started Then
                Select Case El.Location.GetType
                    Case = GetType(LocationPoint)
                        Dim LP As LocationPoint = El.Location
                        LP.Rotate(Line.CreateUnbound(LP.Point, XYZ.BasisZ), Math.PI / 2)
                    Case = GetType(LocationCurve)
                        Dim LC As LocationCurve = El.Location
                        LC.Rotate(Line.CreateUnbound(LC.Curve.Evaluate(0.5, True), XYZ.BasisZ), Math.PI / 2)
                End Select
            End If
            Tx.Commit()
        End Using

        Return Result.Succeeded
    End Function

 

 

 

 

 

 

 

Message 3 of 13
DavoudMWAWD
in reply to: RPTHOMAS108

Thanks RPTHOMAS108,

I actually tried to rotate the assembly origin using ''Rotate()'' function, but the problem is this function is not defined for assembly origin (you can actually rotate the whole assembly but not just its origin). 

 

Even the ElementTransformUtils.RotateElement doesn't work here as the assembly origin does not have Id.

 

So basically the only way I could find to rotate the assembly origin was by defining the transformation/rotation first and then rotate it using Element.SetTransform(rotation)

 

Kind Regards,

 

 

Message 4 of 13
DavoudMWAWD
in reply to: DavoudMWAWD

Hi @jeremytammik

 

Message 5 of 13
jeremy_tammik
in reply to: DavoudMWAWD

First of all, it costs me effort to ignore the title of this thread and understand what you wish to achieve.

 

The origin is a single point and infinitely small, zero-dimensional. Rotating a point makes no sense.

 

Do you mean 'rotate the assembly around its origin'?

 

No, apparently that is not what you are after either.

 

Furthermore, I know nothing of Dynamo or the packages you mention.

 

Actually, re-reading your entire post, I still do not understand what you are trying to achieve.

 

Furthermore, I trust Richard's judgement and experience much more than my own, so I do not see anything I can add to the answer he so kindly already provided.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 6 of 13
mhannonQ65N2
in reply to: DavoudMWAWD

The method CreateRotationAtPoint is a static method, not an instance method. Calling it on a Transform instance does not use any of that instance's data, you are creating an entirely new Transform.

 

I think what you want to do is apply the rotation transform that you are creating to the assembly's transform. You can do that with the Multiply method. Because matrix multiplication is not commutative, the order of multiplying the transforms matters. I'm pretty sure the correct order of operations is 

rotation.Multiply(assembly_origin)

 .

 

For a brief explanation, assembly_origin describes how to move the assembly from the origin to its current position and orientation. The rotation transform describes how to rotate something about an axis at a point. The result of the multiplication should describe moving something from the origin to the assembly's original position & orientation then rotating it about an axis at a point.

Message 7 of 13
RPTHOMAS108
in reply to: mhannonQ65N2

I found this link on assembly origin, which illuminates the situation:

Work with an Assembly | Revit Products 2020 | Autodesk Knowledge Network

 

So partly it makes sense but as noted rotation of a point about itself doesn't make sense. I can understand why the code translates and rotates it as it does but I'm not understanding is what point @DavoudMWAWD wants to rotate the origin about? Seems like it is the centre of the wall which should be starting point for origin.

 

Also there needs to be distinction between CreateRotationAtPoint and CreateRotation one changes origin the other just changes the basis with origin being zero. 

 

There is property AssemblyInstance.GetCenter perhaps this is what they want to rotate origin around but first it has to be remote from that.

Message 8 of 13
DavoudMWAWD
in reply to: DavoudMWAWD

Hi All,

I apologize if I couldn't describe the issue clearly. Please see the image below.

Assembly origin.png

I simply want to do this. 

Thanks  @mhannonQ65N2 for your suggestion, I tried it, it seems that it does not work either. 

Thanks @RPTHOMAS108. It is true that assembly origin is just a point as Jeremy described but how can I control the direction of arrows (those red and green arrows that are bound to this point)? I think it is beyond my knowledge to understand why 'assembly origin' is defined as an instance of Transform Class, but looking at the link you sent me it kinda makes sense. 

 

Anyway, thanks for helping, I appreciate your efforts.

 

 

Message 9 of 13
mhannonQ65N2
in reply to: DavoudMWAWD

The assembly's origin is more than just a point. It also describes the orientation of the assembly (i.e. those colored arrows). It is in fact a coordinate system (to get technical, it is (probably) a right handed orthonormal coordinate system).

This coordinate system can be represented as a 4x4 matrix where the columns of the upper left 3x3 matrix are its x, y, and z basis vectors, the upper 3 values of the 4rth column is the coordinate system's origin, and the bottom row is [0, 0, 0, 1].

| x1 y1 z1 t1|
| x2 y2 z2 t2|
| x3 y3 z3 t3|
| 0  0  0  1 |

where t is the origin (or translation) of the coordinate system.

Here's a decent explanation of transforms/coordinate systems Affine transformation - Wikipedia. You could read some articles and/or books about 3D geometry relevant to computer graphics/gaming/CAD if you want to learn more or get a better explanation than I can provide.

Message 10 of 13
jeremy_tammik
in reply to: DavoudMWAWD

I see now that the assembly origin is more than just a point, so it does indeed make sense to manipulate its orientation, which is in fact a transform, just as you guys so helpfully explain.

 

In your before-after image, it looks to me as if you wish to modify both the location and the orientation.

 

How is this assembly created?

 

I would assume that you create it yourself. 

 

In the creation process, you might start off by specifying the location and the orientation first, and then adding components to it, such as the wall you show.

 

If that is the case, I still see no problem.

 

If that is not the case, I still don't understand what might be causing the problem, i.e., causing an unwanted origin orientation.

 

Where does the origin orientation come from, who sets this up?

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 11 of 13
RPTHOMAS108
in reply to: DavoudMWAWD

You want to do this?

 

Transform.CreateRotation not Transform.CreateRotationAtPoint otherwise will go wrong when you multiply with existing. Mathematically during multiplication operation you want zero origin added to existing transform origin.

 

 Private Function TObj158(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result

        Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
        If UIDoc Is Nothing Then Return Result.Cancelled Else
        Dim IntDoc As Document = UIDoc.Document
        Dim R As Reference = Nothing
        Try
            R = UIDoc.Selection.PickObject(Selection.ObjectType.Element)
        Catch ex As Exception
        End Try
        If R Is Nothing Then Return Result.Cancelled Else

        Dim El As AssemblyInstance = TryCast(IntDoc.GetElement(R), AssemblyInstance)
        Dim RTr As Transform = Transform.CreateRotation(XYZ.BasisZ, Math.PI / 2) 'rotate with no origin

        Dim TransformAsIs = El.GetTransform
        Dim Rotated As Transform = TransformAsIs.Multiply(RTr)

        Using Tx As New Transaction(IntDoc, "Rotate")
            If Tx.Start = TransactionStatus.Started Then
                El.SetTransform(Rotated)
                Tx.Commit()
            End If
        End Using
        Return Result.Succeeded

    End Function

 

 

 

Message 12 of 13
DavoudMWAWD
in reply to: DavoudMWAWD

Hi @jeremy_tammik, Thanks for your time, I just want to rotate it (I mistakenly moved it a bit in the image, that was not my intention). So at first I create the wall and all the elements attached to it (this is a precast concrete wall which has many cast-ins and components like ferrules and steel plates and ..., these components are generally face-based families which I put them manually on the wall, after creating the wall and all its attached components I create an assembly by selecting the wall and all its attached components. So the assembly origin that you see in the image is created automatically based on what Revit decide, I don't have any control over it. But after the assembly is created, I can select the assembly and rotate or move its origin.). So basically this is the issue: The assembly origin is placed automatically (based on Revit predefined orientation) as you see in the first image. If I create the front view based on this orientation (the green arrow in the first image), the people in the factory won't be able to understand how to create this wall unless I change the orientation of the origin to the second image (green arrow in the second image). 

Hi @RPTHOMAS108, Thank you for your time. I will definitely try this and keep you all posted. 

 

I appreciate everyone's help.

Message 13 of 13
DavoudMWAWD
in reply to: DavoudMWAWD

Hi All,

So finally thanks to all of you I achieved what I wanted to do:

I slightly changed the code that @RPTHOMAS108 kindly wrote for me and it works fine. It was as @mhannonQ65N2  suggested, using Multiply was the key here.

 

from Autodesk.Revit.DB import*
from Autodesk.Revit.UI.Selection import*
import sys

uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document

try:
ref = uidoc.Selection.PickObject(ObjectType.Face, 'Please Pick NF')
except OperationCanceledException:
sys.exit()
wall_from_ref = doc.GetElement(ref)
face = wall_from_ref.GetGeometryObjectFromReference(ref)

#We could have selected the assembly itself from the start but I prefered to select the face
assembly_instance_id = wall_from_ref.AssemblyInstanceId
assembly = doc.GetElement(assembly_instance_id)

rotation = Transform.CreateRotation(XYZ.BasisZ, 90)

assembly_origin = assembly.GetTransform()
transform = assembly_origin.Multiply(rotation)

t = Transaction(doc, 'ROTATION')
t.Start()
assembly.SetTransform(transform)
t.Commit()

 I don't know how can I thank you people, but you really helped a lot.

Cheers,

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report