TheSwamp
Code Red => VB(A) => Topic started by: silveroak 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?
-
If you can follow matricies I could post the rest of the code
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
-
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!
-
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.
-
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
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
-
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.
-
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
-
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)?
-
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.