Author Topic: Reading 3D rotation properties  (Read 3251 times)

0 Members and 1 Guest are viewing this topic.

silveroak

  • Guest
Reading 3D rotation properties
« on: October 27, 2008, 09:38:54 AM »
Greetings, all

I have a piece of code that reads back Rotation property of blockreferences in drawings. Now I need to be able to look at rotation of a blockreference in all three planes.  I always understood the Rotation property as around the insertion point in XY plane in WCS. How would one go about reading back XZ and YZ rotation relatively the insertion point?

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Reading 3D rotation properties
« Reply #1 on: October 27, 2008, 10:22:35 AM »
If you can follow matricies I could post the rest of the code
Code: [Select]
Function BlockRefMatrix(oBref As AcadBlockReference) As Variant

    Dim V, m(3, 3) As Double, M1, M2
    Dim j As Integer
    Dim x, y, Z, ins
    Dim Rot As Double
   
    Rot = oBref.Rotation
    Z = oBref.Normal
    V = GetOcsFromNormal(Z)
    x = V(0): y = V(1)

    ins = oBref.InsertionPoint
   
    M1 = RotZ(-Rot)
    For j = 0 To 2
        m(0, j) = x(j)
        m(1, j) = y(j)
        m(2, j) = Z(j)
        m(3, j) = ins(j)
    Next j
    m(3, 3) = 1

    If Rot = 0 Then
        BlockRefMatrix = m
    Else
        M2 = M4xM4(m, M1)
        BlockRefMatrix = M2
    End If
   
   
End Function




Function GetOcsFromNormal(N As Variant) As Variant
    'Arbitrary Axis Algorithm in dxf help
    'N is the normal vector.
    'Wy is the world Y axis, which is always (0,1,0).
    'Wz is the world Z axis, which is always (0,0,1).
    Dim Wy(2) As Double
    Dim Wz(2) As Double
    Dim Nx As Double, Ny As Double
    Dim Ax, Ay, Ocs(1) As Variant
   
    N = NormaliseVector(N)
    Wy(0) = 0: Wy(1) = 1: Wy(2) = 0
    Wz(0) = 0: Wz(1) = 0: Wz(2) = 1
    Nx = N(0): Ny = N(1)
    If (Abs(Nx) < 1 / 64) And (Abs(Ny) < 1 / 64) Then
         'Ax = Wy X N (where “X” is the cross-product operator).
         Ax = Crossproduct(Wy, N)
    Else
         Ax = Crossproduct(Wz, N)
    End If
    Ocs(0) = Ax
 
    Ay = Crossproduct(N, Ax)
    Ocs(1) = Ay
    GetOcsFromNormal = Ocs

End Function

silveroak

  • Guest
Re: Reading 3D rotation properties
« Reply #2 on: October 27, 2008, 12:19:57 PM »
Bryco, the 4x4 that we get back from BlocRefMatrix, is it rotation and translation from 0,0,0? It would be great if you posted the rest of the functions.
What I will have to do from there is to orient a number of block references the same way, could you point me to or post a source on applying the rotation component to a block reference?

Or something that can apply the 4x4 transformation will work as well, I can get my blockreferences to origin and they will not be rotated.

I am very new to all this and not sure where to start in AutoCAD. In the tool I am working on our blocks and locations were always 3d but only xy rotation has ever been used which is conveniently in a property. My knowledge of 3d transformation in CAD is 0 and the theory is almost forgotten.  If I can get the transformation from the rest of your code and then a way to apply it to something else I will be well on my way to recovery!

Thanks!
« Last Edit: October 27, 2008, 12:37:32 PM by silveroak »

silveroak

  • Guest
Re: Reading 3D rotation properties
« Reply #3 on: October 27, 2008, 05:06:19 PM »
I was reading the documention and realized that we've got TransformBy,

as stated above I need to orient unrotated block references the same way.  Their insertion point should stay where it is.

if I take the 4x4 from BlockRefMatrix, set translation xyz information in the last row to 0 and TransformBy desired blocks with it, will it result in desired same orientation? Please let me know if I am on the right track.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Reading 3D rotation properties
« Reply #4 on: October 27, 2008, 10:27:08 PM »
I'm still not quite sure what you are doing, but here is the rest.
Yes this gives both a transformation and a rotation in x,y & z

If you have your immediatewindow up (ctrl+G) you will see the matrix print out (the way I like it printed out)
I think you will find what you need, I'm not sure how to translate them directly into angles as the order is important

Code: [Select]
Option Explicit

Sub TEST()
    Dim b As AcadBlockReference, ent As AcadEntity, V, m
    ThisDrawing.Utility.GetEntity ent, V, "Pick"
    If ent Is Nothing Then Exit Sub
    If Not TypeOf ent Is AcadBlockReference Then Exit Sub
    Set b = ent
    m = BlockRefMatrix(b)
    PrintM m
   
End Sub

Function RotZ(ang As Double) As Variant
   'Rotate by an angle around the z axis
    Dim m
    Dim CosAng As Double, sinAng As Double
   
    CosAng = Cos(ang): sinAng = Sin(ang)
    m = IDMatrix
    m(0, 0) = CosAng
    m(0, 1) = -sinAng
    m(1, 0) = sinAng
    m(1, 1) = CosAng
     
    RotZ = m

End Function


Function M4xM4(M1, M2) As Variant
    'Matrix x matrix
    Dim m(3, 3) As Double
    Dim I As Integer, j As Integer
    Dim k As Integer
    Dim Sum As Double
   
    For I = 0 To 3
        For j = 0 To 3
            For k = 0 To 3
                Sum = Sum + M1(k, j) * M2(I, k)
            Next k
            m(I, j) = Sum
            Sum = 0
        Next j
    Next I
    M4xM4 = m
   
End Function


Function NormaliseVector(V As Variant) As Variant
    Dim Unit As Double
    Dim Vn(2) As Double
    Unit = Sqr(V(0) * V(0) + V(1) * V(1) + V(2) * V(2))
    Vn(0) = V(0) / Unit: Vn(1) = V(1) / Unit: Vn(2) = V(2) / Unit
    NormaliseVector = Vn
End Function


Function Crossproduct(a, b) As Variant

    Dim Ax As Double, Ay As Double, Az As Double
    Dim Bx As Double, By As Double, Bz As Double
    Dim Unit As Double
    Dim c(2) As Double
    'get CrossProduct
    Ax = a(0): Ay = a(1): Az = a(2)
    Bx = b(0): By = b(1): Bz = b(2)
   
    c(0) = Ay * Bz - Az * By
    c(1) = Az * Bx - Ax * Bz
    c(2) = Ax * By - Ay * Bx
   
    'Convert to unit normal
    Unit = Sqr(c(0) * c(0) + c(1) * c(1) + c(2) * c(2))
    c(0) = c(0) / Unit: c(1) = c(1) / Unit: c(2) = c(2) / Unit
    Crossproduct = c

End Function


Function IDMatrix()
    Dim m(3, 3) As Double
    Dim I As Integer, j As Integer
    m(0, 0) = 1
    m(1, 1) = 1
    m(2, 2) = 1
    m(3, 3) = 1
    IDMatrix = m
   
End Function


Sub PrintM(m)

    Dim I As Integer
    Dim j As Integer
    Debug.Print
    If UBound(m, 2) > 3 Then
        For I = 0 To 3
             Debug.Print m(I, 0), m(I, 1), m(I, 2), m(I, 3), m(I, 4), m(I, 5), m(I, 6), m(I, 7)
        Next
    Else
        For I = 0 To 3
             Debug.Print m(I, 0), m(I, 1), m(I, 2), m(I, 3)
        Next
    End If
   
End Sub

silveroak

  • Guest
Re: Reading 3D rotation properties
« Reply #5 on: October 28, 2008, 08:50:56 AM »
Thanks again, Bryco,
your code is a great place to start for me. I am going to have to convert it to C# as that's what I use to drive AutoCAD, but from there I will see what can be done with the matrix.

The most important part for me is copying orientation of one block to another. I was thinking about extracting angles and applying Rotate3D but like you said I don't know the order.  I might be able to achieve the same by using the rotational component of your matrix and applying it through TransformBy to another block reference.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Reading 3D rotation properties
« Reply #6 on: October 28, 2008, 09:33:39 AM »
Matricies are very easy in C#, if you post the rotation part of your code in the net part of code red you should get some help

silveroak

  • Guest
Re: Reading 3D rotation properties
« Reply #7 on: October 29, 2008, 09:33:35 PM »
I finally got it to work after conversion to C# and trying to apply it with TransformBy,
it turns out the resulting block matrix must be transposed or rebuilt column-first to work with TransformBy.  It will fully recreate a block's position and orientation if applied to unrotated block at 0,0,0.
If it is not transposed, it will do strangest things including wild scaling and making blocks disappear (maybe become tiny, not sure)  :ugly:

I noticed the difference when it dawned on me that the transform matrix examples in AutoCAD help have the unused 0,0,0 in the bottom row as opposed to rightmost as in the test output.

I am wondering why is this so and what would this code build it like that (just curiosity)?

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Reading 3D rotation properties
« Reply #8 on: October 29, 2008, 11:06:42 PM »
I personally hate the way matricies are built in cad and the code I supplied is the way it makes sense to me.
I found out by back tracking the cad matrix supplied with getsubentity, which gives you the matrix to put the subentity from the blockref back to the 0,0 blockdef. This was 180 degrees from what  I wanted so you may need an inverse and a transposing.