Circular rotation around an arbitrary axis
Asked Answered
3d
M

8

34

I am programming Starcraft 2 custom maps and got some proglems with math in 3D. Currently I am trying to create and rotate a point around an arbitrary axis, given by x,y and z (the xyz vector is normalized).

I've been trying around a lot and read through a lot of stuff on the internet, but I just cant get how it works correctly. My current script (you probably dont know the language, but it's nothing special) is the result of breaking everything for hours (doesn't work correctly):

    point CP;
fixed AXY;
point D;
point DnoZ;
point DXY_Z;
fixed AZ;
fixed LXY;
missile[Missile].Angle = (missile[Missile].Angle + missile[Missile].Acceleration) % 360.0;
missile[Missile].Acceleration += missile[Missile].AirResistance;
if (missile[Missile].Parent > -1) {
    D = missile[missile[Missile].Parent].Direction;
    DnoZ = Point(PointGetX(D),0.0);
    DXY_Z = Normalize(Point(SquareRoot(PointDot(DnoZ,DnoZ)),PointGetHeight(D)));
    AZ = MaxF(ACos(PointGetX(DXY_Z)),ASin(PointGetY(DXY_Z)))+missile[Missile].Angle;
    DnoZ = Normalize(DnoZ);
    AXY = MaxF(ACos(PointGetX(DnoZ)),ASin(PointGetY(DnoZ)));
    CP = Point(Cos(AXY+90),Sin(AXY+90));
    LXY = SquareRoot(PointDot(CP,CP));
    if (LXY > 0) {
        CP = PointMult(CP,Cos(AZ)/LXY);
        PointSetHeight(CP,Sin(AZ));
    } else {
        CP = Point3(0.0,0.0,1.0);
    }
} else {
    CP = Point(Cos(missile[Missile].Angle),Sin(missile[Missile].Angle));
}
missile[Missile].Direction = Normalize(CP);
missile[Missile].Position = PointAdd(missile[Missile].Position,PointMult(missile[Missile].Direction,missile[Missile].Distance));

I just cant get my mind around the math. If you can explain it in simple terms that would be the best solution, a code snipped would be good as well (but not quite as helpful, because I plan to do more 3D stuff in the future).

Marius answered 17/7, 2011 at 2:21 Comment(0)
S
37

http://en.wikipedia.org/wiki/Rotation_matrix. Look under the section Rotation matrix from axis and angle. For your convenience, here's the matrix you need. It's a bit hairy. theta is the angle, and ux, uy, and uz are the x, y, and z components of the normalized axis vector

Here's the rotation matrix

If you don't understand matrices and vectors, post back and I'll help you.

Strohl answered 17/7, 2011 at 2:54 Comment(7)
I found that matrix too, my problem is that I do not understand how to use it. What I do not understand either is how to create the point that I want to rotate. Thanks for your help.Marius
After thinking a lot more about it, the rotation isn't the problem, I think I do understand the rotation. What I just cannot do is finding an perpendicular vector to my axis, at least none that rotates with the axis (the axis changes every 0.0625 seconds and I want a rotation around it with a constant distance).Marius
It works now, I use an UP vector that I have to compute on every rotation etc. Would be better if there was a way to compute it when needed.Marius
I realize there may be many reasons you're using an up vector, but the matrix I posted has all the necessary information to accomplish the rotation. Do you have the coordinates of the point you're rotating? Do you have the axis in (x, y, z) form? Do you have theta and can compute sin(theta) and cos(theta)? If so, this formula should be sufficient to achieve what you want.Strohl
No, I do not have the coordinates. I wanted them to be computed and then rotated by the angle. And I have no idea how to compute a point that is always in the same direction from my axis (if I turn my axis and display the point, it should look like it is connected).Marius
I didn't mean you have them at compile time. I'm saying that ONCE you have the points, applying the transform is just a matter of coding a matrix multiply and doesn't require any information beyond what you already have.Strohl
Doesn't the axis of rotation need to have a constant point? a vector as axis of rotation can be anywhere in the globe, at any distance from rotated point, So the result will be different.Personalize
C
17

A useful method for doing such rotations is to do them with quaternions. In practice, I've found them to be easier to use and have the added bonus of avoiding Gimbal lock.

Here is a nice walk through that explains how and why they are used for rotation about an arbitrary axis (it's the response to the user's question). It's a bit higher level and would be good for someone who is new to the idea, so I recommend starting there.

Update to avoid link corrosion

The text from the linked site:

As you have no doubt already concluded, rotation around the axis passing through the origin and a point (a,b,c) on the unit sphere in three-dimensions is a linear transformation, and hence can be represented by matrix multiplication. We will give a very slick method for determining this matrix, but to appreciate the compactness of the formula it will be wise to start with a few remarks.

Rotations in three-dimensions are rather special linear transformations, not least because they preserve the lengths of vectors and also (when two vectors are rotated) the angles between the vectors. Such transformations are called "orthogonal" and they are represented by orthogonal matrices:

M M' = I

where we conveniently denote the transpose by '. In other words the transpose of an orthogonal matrix is its inverse.

Consider the data which is needed to define the transformation. You've already given notation for the axis of rotation, ai + bj + ck, conveniently assumed to be a unit vector. The only other datum is the angle of rotation, which for lack of a more natural character I will denote by r (for rotation?) and which we will assume to be given in radians.

Now the rotations are actually a bit special even among orthogonal transformations, and in fact they are also called special orthogonal transformations (or matrices) in virtue of their property of being "orientation preserving". Compare them with reflections, which are also length and angle preserving, and you will find that the geometric characteristic of preserving orientation (or "handedness" if you prefer) has a numerical counterpart in the determinant of the matrix. A rotation's matrix has determinant 1, while a reflection's matrix has determinant -1. It turns out that the product (or composition) of two rotations is again a rotation, which agrees with the fact that the determinant of a product is the product of the determinants (or 1 in the case of a rotation).

Now we can describe a step by step approach that one might follow to construct the desired matrix (before we shortcut the whole process and jump to the Answer!). Consider first a step in which we rotate the unit vector:

u = ai + bj + ck

so that it coincides with one of the "standard" unit vectors, perhaps k (the positve z-axis). Now we know how to rotate around the z-axis; it's a matter of doing the usual 2x2 transformation on the x,y coordinates alone:

       cos(r) sin(r)   0
M  =  -sin(r) cos(r)   0
         0      0      1

Finally we need to "undo" that initial rotation that took u to k, which is easy because the inverse of that transformation is (we recall) represented by the matrix transpose. In other words, if matrix R represents a rotation taking u to k, then R' takes k to u, and we can write out the composition of transformations like this:

R' M R

It is easily verified that this product of matrices, when multiplied times u, gives u back again:

R' M R u = R' M k = R' k = u

Therefore this is indeed rotation about the axis defined by u.

One advantage of this expression is that it cleanly separates out the dependence of M on the angle r from the dependence of Q and Q' on the "axis" vector u. However if we have to carry out the computations in detail, we will obviously have a lot of matrix multiplication to do.

So, to the shortcut. It turns out when all the dust settles that the multiplication among rotations is isomorphic to multiplication of unit quaternions. Quaternions, in case you've not seen them before, are a kind of four-dimensional generalization of complex numbers. They were "invented" by William Hamilton in 1843:

[Sir William Rowan Hamilton] http://www-gap.dcs.st-and.ac.uk/~history/Mathematicians/Hamilton.html

and today's 3D graphics programmers are greatly in his debt.

Each unit quaternion q = q0 + q1*i + q2*j + q3*k then defines a rotation matrix:

     (q0² + q1² - q2² - q3²)      2(q1q2 - q0q3)          2(q1q3 + q0q2)

Q  =      2(q2q1 + q0q3)     (q0² - q1² + q2² - q3²)      2(q2q3 - q0q1)

          2(q3q1 - q0q2)          2(q3q2 + q0q1)     (q0² - q1² - q2² + q3²)

To verify that Q is an orthogonal matrix, ie. that Q Q' = I, means in essence that the rows of Q form an orthonormal basis. So, for example, the first row should have length 1:

(q0² + q1² - q2² - q3²)² + 4(q1q2 - q0q3)² + 4(q1q3 + q0q2)²

  = (q0² + q1² - q2² - q3²)² + 4(q1q2)² + 4(q0q3)² + 4(q1q3)² + 4(q0q2)²

  = (q0² + q1² + q2² + q3²)²

  =  1

and the first two rows should have dot product zero:

  [ (q0² + q1² - q2² - q3²), 2(q1q2 - q0q3), 2(q1q3 + q0q2) ]

   * [ 2(q2q1 + q0q3), (q0² - q1² + q2² - q3²), 2(q2q3 - q0q1) ]

 = 2(q0² + q1² - q2² - q3²)(q2q1 + q0q3)

   + 2(q1q2 - q0q3)(q0² - q1² + q2² - q3²)

   + 4(q1q3 + q0q2)(q2q3 - q0q1)

 = 4(q0²q1q2 + q1²q0q3 - q2²q0q3 - q3²q2q1)

   + 4(q3²q1q2 - q1²q0q3 + q2²q0q3 - q0²q2q1)

 =  0

It can also be shown in general that det(Q) = 1, and thus that Q is really a rotation.

But around what axis is Q the rotation? And by what angle? Well, given angle r and unit vector:

u = ai + bj + ck

as before, the corresponding quaternion is:

q = cos(r/2) + sin(r/2) * u

  = cos(r/2) + sin(r/2) ai + sin(r/2) bj + sin(r/2) ck

Thus with:

q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c,

we are able to get the desired property that multiplication by Q "fixes" u:

Q u = u

Rather than chug through the long-winded algebra, let's do a simple example.

Let u = 0i + 0.6j + 0.8k be our unit vector and r = pi be our angle of rotation.

Then the quaternion is:

q = cos(pi/2) + sin(pi/2) * u

  = 0 + 0i + 0.6j + 0.8k

and the rotation matrix:

        -1     0     0

Q =      0  -0.28  0.96

         0   0.96  0.28

In this concrete case it is easy to verify that Q Q' = I and det(Q) = 1.

Also we compute that:

Q u = [ 0, -0.28*0.6 + 0.96*0.8, 0.96*0.6 + 0.28*0.8 ]'

    = [ 0, 0.6, 0.8 ]'

    =  u

ie. the unit vector u defines the axis of rotation because it is "fixed" by Q.

Finally we illustrate that the angle of rotation is pi (or 180 degrees) by considering how Q acts on the unit vector in the direction of the positive x-axis, which is perpendicular to u:

i + 0j + 0k,  or as a vector, [ 1, 0, 0 ]'

Then Q [ 1, 0, 0 ]' = [-1, 0, 0 ]' which is the rotation of [ 1, 0, 0 ]' through angle pi about u.

As a reference for this representation of rotations by quaternions and some additional methods of representation (and what they are good for), see the details here:

[Representing 3D rotations] http://gandalf-library.sourceforge.net/tutorial/report/node125.html

SUMMARY

Given angle r in radians and unit vector u = ai + bj + ck or [a,b,c]', define:

q0 = cos(r/2),  q1 = sin(r/2) a,  q2 = sin(r/2) b,  q3 = sin(r/2) c

and construct from these values the rotation matrix:

     (q0² + q1² - q2² - q3²)      2(q1q2 - q0q3)          2(q1q3 + q0q2)

Q  =      2(q2q1 + q0q3)     (q0² - q1² + q2² - q3²)      2(q2q3 - q0q1)

          2(q3q1 - q0q2)          2(q3q2 + q0q1)     (q0² - q1² - q2² + q3²)

Multiplication by Q then effects the desired rotation, and in particular:

Q u = u
Collette answered 30/3, 2013 at 0:47 Comment(0)
N
6

A very neat way to program this, especially if you are able to operate with matrices (like in Matlab) is the Rodrigues' Rotation Formula.

The formula creates a rotation matrix R around an axis defined by the unit vector \hat{u} = [u_x,u_y,u_z] by an angle phi using a very simple equation:

R=I+sin(phi)·W + (1-cos(phi))·W²

Where I is the identity matrix and W is a matrix given by the components of the unit vector u:

W= [0 -uz uy; uz 0 -ux; -uy ux 0];

Note that it is very important that the vector u is a unit vector, i.e. the norm of u must be 1.

You can check that for the euclidean axis, the formula is exact as those found on Wikipedia and published here by Aakash Anuj.

I only use this formula for rotations since I discovered it. Hope it helps to anyone.

Nervy answered 21/11, 2018 at 14:40 Comment(0)
B
5

To perform a 3D rotation, you simply need to offset the point of rotation to the origin and sequentially rotate around each axis, storing the results between each axis rotation for use with the next rotation operation. The algorithm looks like as follows:

Offset the point to the origin.

Point of Rotation = (X1, Y1, Z1)
Point Location    = (X1+A, Y1+B, Z1+C)

(Point Location - Point of Rotation) = (A, B, C).

Perform rotation about the Z Axis.

    A' = A*cos ZAngle - B*sin ZAngle
    B' = A*sin ZAngle + B*cos ZAngle
    C' = C.

Next, perform a rotation about the Y Axis.

    C'' = C'*cos YAngle - A'*sin YAngle
    A'' = C'*sin YAngle + A'*cos YAngle
    B'' = B'   

Now perform the last rotation, about the X Axis.

    B''' = B''*cos XAngle - C''*sin XAngle
    C''' = B''*sin XAngle + C''*cos XAngle
    A''' = A''

Finally, add these values back to the original point of rotation.

Rotated Point = (X1+A''', Y1+B''', Z1+C''');

I found this link to be very helpful. It defines how to perform individual rotations about the X, Y and Z axes.

Mathematically, you can define the set of operations like so:

enter image description here

Basilbasilar answered 15/2, 2014 at 4:0 Comment(0)
A
4

Here is what you can use to rotate about any axis, be it x,y or z. Rx, Ry and Rz denote rotation about the aces x,y,z respectively.

enter image description here

Atherton answered 15/8, 2013 at 12:57 Comment(1)
That image is from here, right? You should probably cite that.Ailina
E
4

For rotations about an arbitrary axis in three dimensions with matrices, I have a page here. The linked explanation and derivation of the matrices (here) includes the following rotation/translation matrix. This is the matrix that yields the result of rotating the point (x,y,z) about the line through (a,b,c) with direction vector ⟨u,v,w⟩ by the angle theta.

matrix of rotation about an arbitrary axis

The result is this point in three dimensions:

rotated point

The page includes a link to a source code download. If you want to interactively do rotations, you can do so at this site. Try the sample rotation link to get a feel for what's going on.

Twist and Shout!

Endermic answered 21/3, 2018 at 3:35 Comment(0)
C
2

Axis-angle converts directly to quaternion; given that the axis is a unit vector, and the angle is the spin around that axis. The axis is given regular (x,y,z) direction coordinates. The quaternion is (cos(theta),sin(theta)*x, sin(theta)*y, sin(theta)*z) then multiply as appropriate.

The basis can be formed by rotating (1,0,0),(0,1,0),(0,0,1) around the axis-angle using Rodrigues Rotation Formula which results in the following... and then the forward, right, and up vectors can be used to scale the point to the correct location. (This is just a matrix, but essentially transposed so that axii are immediately extractable themselves, giving you the relative 'up' at any particular point)

    const nt = q.θ * del;  // scaled angle by some dT
    const s  = Math.sin( nt ); // sin/cos are the function of exp()
    const c1 = Math.cos( nt );
    const c = 1- c1;

    const qx = /*Axis unit vector X*/;
    const qy = /*Axis unit vector Y*/;
    const qz = /*Axis unit vector Z*/;

    const cnx = c*qx;
    const cny = c*qy;
    const cnz = c*qz;

    const xy = cnx*qy;  // x * y / (xx+yy+zz) * (1 - cos(2t))
    const yz = cny*qz;  // y * z / (xx+yy+zz) * (1 - cos(2t))
    const xz = cnz*qx;  // x * z / (xx+yy+zz) * (1 - cos(2t))

    const wx = s*qx;     // x / sqrt(xx+yy+zz) * sin(2t)
    const wy = s*qy;     // y / sqrt(xx+yy+zz) * sin(2t)
    const wz = s*qz;     // z / sqrt(xx+yy+zz) * sin(2t)

    const xx = cnx*qx;  // y * y / (xx+yy+zz) * (1 - cos(2t))
    const yy = cny*qy;  // x * x / (xx+yy+zz) * (1 - cos(2t))
    const zz = cnz*qz;  // z * z / (xx+yy+zz) * (1 - cos(2t))

    const basis = { right  :{ x : c1 + xx, y : wz + xy, z : xz - wy }
                  , up     :{ x : xy - wz, y : c1 + yy, z : wx + yz }
                  , forward:{ x : wy + xz, y : yz - wx, z : c1 + zz }
                  };

Concertino answered 14/4, 2021 at 18:9 Comment(0)
S
0

There are some libraries like SciPy or transforms3d that can be used to perform rotations in 3D space around an arbitrary axes. All you need to specify is the rotation axis and the amount of rotation and they will output a rotation matrix which can then be applied to a point. transforms3d has the function transforms3d.axangles.axangle2mat() and sci.py has the function scipy.spatial.transform.Rotation.from_rotvec(). These functions perform the mathematical operations described by others on this forum but suing a library can help minimise the risk of typos.

Shan answered 29/4 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.