Quaternion to EulerXYZ, how to differentiate the negative and positive quaternion - c++

I've been trying to figure out the difference between these, and why ToEulerXYZ does not get the right rotation.
Using MathGeoLib:
axisX:
x 0.80878228 float
y -0.58810818 float
z 0.00000000 float
axisY:
x 0.58811820 float
y 0.80877501 float
z 0.00000000 float
axisZ:
x 0.00000000 float
y 0.00000000 float
z 1.0000000 float
Code:
Quat aQ = Quat::RotateAxisAngle(axisX, DegToRad(30)) * Quat::RotateAxisAngle(axisY, DegToRad(60)) * Quat::RotateAxisAngle(axisZ, DegToRad(40));
float3 eulerAnglesA = aQ.ToEulerXYZ();
Quat bQ = Quat::RotateAxisAngle(axisX, DegToRad(-150)) * Quat::RotateAxisAngle(axisY, DegToRad(120)) * Quat::RotateAxisAngle(axisZ, DegToRad(-140));
float3 eulerAnglesB = bQ.ToEulerXYZ();
Both to ToEulerXYZ get {x=58.675510 y=33.600880 z=38.327244 ...} (when converted to degrees).
The only difference I can see, is the quaternions are identical, but one is negative. The ToEulerXYZ is wrong though, as one should be the negative ({x=-58.675510 y=-33.600880 z=-38.327244 ...}) (bQ)
AQ is:
x 0.52576530 float
y 0.084034257 float
z 0.40772036 float
w 0.74180400 float
While bQ is:
x -0.52576530 float
y -0.084034257 float
z -0.40772036 float
w -0.74180400 float
Is this just an error with MathGeoLib, or some weird nuance, or maybe someone can explain to me what is going on logically.
There are additional scenarios that are not even negative
axisX:
-0.71492511 y=-0.69920099 z=0.00000000
axisY:
0.69920099 y=-0.71492511 z=0.00000000
axisZ:
x=0.00000000 y=0.00000000 z=1.0000000
Code:
Quat aQ = Quat::RotateAxisAngle(axisX, DegToRad(0)) * Quat::RotateAxisAngle(axisY, DegToRad(0)) * Quat::RotateAxisAngle(axisZ, DegToRad(-90));
float3 eulerAnglesA = aQ.ToEulerXYZ();
Quat bQ = Quat::RotateAxisAngle(axisX, DegToRad(-180)) * Quat::RotateAxisAngle(axisY, DegToRad(180)) * Quat::RotateAxisAngle(axisZ, DegToRad(90));
float3 eulerAnglesB = bQ.ToEulerXYZ();
These both yield the same quaternion!
x 0.00000000 float
y 0.00000000 float
z -0.70710677 float
w 0.70710677 float

The quaternions -q and q are different; however, the rotations represented by the two quaternions are identical. This phenomenon is usually described by saying quaternions provide a double cover of the rotation group SO(3). The algebra to see this is very simple: given a vector represented by quaternion p, and a rotation represented represented by a quaternion q, the rotation is qpq^{-1}. On the other hand, -qp(-q)^{-1} = -1qp(q)^{-1}(-1) = q(-1)p(-1)q^{-1} = qp(-1)^2q^{-1} = qpq^{-1}, the same rotation. Quaternions normally don't commute, so pq != qp for general quaternions, but scalars like -1 do commute with quaternions.
I believe ToEulerXYZ should be the same in both cases, which it appears to be.

From what I remember a quaternion can be considered as a rotation around an arbitrary axis.
And this can help to understand intuitively why there will always be two quaternions to represent a given rotation.
Rotating 90° around 0,0,1 is going to be the same as rotating 270° around 0,0, -1.
I.e. A quarter turn anticlockwise around 0,0,1 is identical to a quarter turn clockwise around 0,0, -1.
You can check this out by using your thumb as the axis of rotation and do the 90° rotation in the direction your fingers curl.

Related

Reversing RotateAxisAngle back to angles

I'm trying to figure out how to reverse RotateAxisAngle to get back rotations around these arbitrary axes (or equivalent rotations that yield same net rotation, doesn't have to be identical). Does anyone know how to do it? I'm using MathGeoLib, but I don't see an opposite way, to return back the angles about axes, when all you have is the matrix.
Here's the forward direction code (RotateAxisAngle is from MathGeoLib):
float4x4 matrixRotation = float4x4::RotateAxisAngle(axisX, ToRadian(rotation.x));
matrixRotation = matrixRotation * float4x4::RotateAxisAngle(axisY, ToRadian(rotation.y));
matrixRotation = matrixRotation * float4x4::RotateAxisAngle(axisZ, ToRadian(rotation.z));
Now I want to get back to the degrees, about these arbitrary axes, in the same order (well, pull off Z, then Y, then X), so if I did it again, forward direction, would yield the same net rotations.
Here's the sample/matrix corresponding to that set of rotations I posted above, if it helps, on reversing back to it:
axisX:
x 0.80878228 float
y -0.58810818 float
z 0.00000000 float
Rot about that axis:
30.000000 float
axisY:
x 0.58811820 float
y 0.80877501 float
z 0.00000000 float
Rot about that axis:
60.000000 float
axisZ:
x 0.00000000 float
y 0.00000000 float
z 1.0000000 float
Rot about that axis:
40.000000 float
That forms this matrix, which is stored to a file, and need to retrieve the rotations about above axes (without any info about rotations originally used)
[4][4]
[0x0] 0.65342271 float
[0x1] -0.51652151 float
[0x2] 0.55339342 float
[0x3] 0.00000000 float
[0x0] 0.69324547 float
[0x1] 0.11467478 float
[0x2] -0.71151978 float
[0x3] 0.00000000 float
[0x0] 0.30405501 float
[0x1] 0.84856069 float
[0x2] 0.43300733 float
[0x3] 0.00000000 float
[0x0] 0.00000000 float
[0x1] 0.00000000 float
[0x2] 0.00000000 float
[0x3] 1.0000000 float
OK, I'm going to take another stab at this. My first answer was for XYZ order of rotations. This answer is for ZYX order, now that I know more about how MathGeoLib works.
MathGeoLib represents position vectors as column vectors v = [x y z 1]^T where ^T is the transpose operator which flips rows to columns (and vice versa). Rotation matrices pre-multiply column vectors. So if we have a matrix Rx(s) representing a rotation around the x-axis by s degrees, then a rotation Ry(t) representing a rotation about the y-axis by t degrees, then rotation Rz(u) representing a rotation about the z-axis by u degrees, and we combine them and multiply with v as Rx(s) Ry(t) Rz(u) v, we're actually applying the z rotation first. But we can still work out the angles from the combined matrix, it's just that the formulas are going to be different from the more common XYZ order.
We have the upper left blocks of the rotation matrices as follows. (The fourth row and column are all 0s except for the diagonal element which is 1; that never changes in the calculations that follow so we can safely ignore.) MathGeoLib appears to use left-handed coordinates, so the rotation matrices are:
[1 0 0] [ cos t 0 sin t] [ cos u -sin u 0]
Rx(s) = [0 cos s -sin s], Ry(t) = [ 0 1 0], Rz(u) = [ sin u cos u 0]
[0 sin s cos s] [-sin t 0 cos t] [ 0 0 1]
(Note the position of the - sign in Ry(t); it's there because we think of the coordinates in cyclic order. Rx(s) rotates y and z; Ry(t) rotates z and x; Rz(u) rotates x and y. Since Ry(t) rotates z and x not in alphabetical order but in cyclic order, the rotation is opposite in direction from what you expect for alphabetical order.
Now we multiply the matrices in the correct order. Rx(s) Ry(t) is
[1 0 0][ cos t 0 sin t] [ cos t 0 sin t]
[0 cos s -sin s][ 0 1 0] = [ sin s*sin t cos s -sin s*cos t]
[0 sin s cos s][-sin t 0 cos t] [-cos s*sin t sin s cos s*cos t]
The product of that with Rz(u) is
[ cos t 0 sin t][ cos u -sin u 0]
[ sin s*sin t cos s -sin s*cos t][ sin u cos u 0] =
[-cos s*sin t sin s cos s*cos t][ 0 0 1]
[ cos t*cos u -cos t*sin u sin t]
[ sin s*sin t*cos u+cos s*sin u -sin s*sin t*sin u+cos s*cos u -sin s*cos t]
[-cos s*sin t*cos u+sin s*sin u cos s*sin t*sin u+sin s*cos u cos s*cos t]
So we can figure out the angles as follows:
tan s = -(-sin s * cos t)/(cos s * cos t) = M23/M33 => s = -arctan2(M23,M33)
sin t = M13 => t = arcsin(M13)
tan u = -(-cos t * sin u)/(cos t * cos u) = M12/M11 => u = -arctan2(M12,M11)
If we are to implement those calculations, we need understand how the matrix is indexed in MathGeoLib. The indexing is row major, just like the mathematical notation, but indexing starts at 0 (computer style) rather than at 1 (math style) so the C++ formulas you want are
s = -atan2(M[1][2],M[2][2]);
t = asin(M[0][2]);
u = -atan2(M[0][1],M[0][0]);
The angles are returned in radians so will need to be converted to degrees if desired. You should test that result in the case when axes for the rotations Z, Y, and X are in standard position (001), (010), and (100).
If we are to reverse a rotation about non-standard axes, as in your example, the problem becomes more difficult. However, I think it can be done by a "change of coordinates". So if our rotation mystery matrix is matrixRotation, I believe you can just form the "conjugate" matrix
M = coordinateChangeMatrix*matrixRotation*coordinateChangeMatrix^{-1}
and then use the above formulas. Here coordinateChangeMatrix would be the matrix
[Xaxis0 Xaxis1 Xaxis2 0]
[Yaxis0 Yaxis1 Yaxis2 0]
[Zaxis0 Zaxis1 Zaxis2 0]
[ 0 0 0 1]
where the rotation X-axis is (Xaxis0,Xaxis1,Xaxis2). In your example those numbers would be (0.808...,-0.588...,0). You should make sure that the rotation matrix is orthonormal, i.e., the dot product of Xaxis with itself is 1, the dot product of Xaxis with another axis is 0, and the same for any other axis. If the coordinate change matrix is not orthonormal, the calculation might still work, but I don't know for sure.
The inverse of the coordinate change matrix can be calculated using float4x4::inverseOrthonormal or if it's not orthonormal you can use float4x4::inverse but as I mentioned I don't know how well that will work.
If you just want a rotation that reverses the rotation you've got in one step, you can invert the rotation matrix. float4x4::InverseOrthonormal should work, and it's fast and accurate. float4x4::Inverse will also work but it's slower and less accurate.
If you really want to recover the angles, it goes something like this. (There are numerous different conventions, even for X-Y-Z; I think this one matches, but you may have to take the transpose of the matrix or make some other modification. If this doesn't work I can suggest alternatives.) First we follow the Wikipedia article for a description of the Euler Angles to Matrix conversion. In the resulting matrix, we have
A11 = cos theta cos psi
A21 = -cos theta sin psi
A31 = sin theta
A32 = -sin phi cos theta
A33 = cos phi cos theta
where phi is the rotation around the x-axis, theta is the rotation around the y-axis, and psi is rotation around the z-axis. To recover the angles, we do
phi = -arctan2(A32,A33)
theta = arcsin(A31)
psi = -arctan2(A21,A11)
The angles may not match the original angles exactly, but the rotations should match. arctan2 is the two-argument form of the arctan function, which takes into account the quadrant of the point represented by the argument, and deals correctly with 90 degree angles.
Given the way your rotations are represented, I think you may have to use the transpose instead. That's easy: you just swap the indices in the above formulas:
phi = -arctan2(A23,A33)
theta = arcsin(A13)
psi = -arctan2(A12,A11)
If neither of those work, I could take a closer look at the MathGeoLib library and figure out what they're doing.
Update
I neglected to take into account information about the axes of rotation in my previous answer. Now I think I have a plan for dealing with them.
The idea is to "change coordinates" then do the operations as above in the new coordinates. I'm a little hazy on the details, so the process is a little "alchemical" at the moment. The OP should try various combinations of my suggestions and see if any of them work ... there aren't too many (just 4 ... for the time being).
The idea is to form a coordinate change matrix using the coordinates of the rotation axes. We do it like this:
axisX: 0.80878228 -0.58810818 0.00000000 0.00000000
axisY: 0.58811820 0.80877501 0.00000000 0.00000000
axisZ: 0.00000000 0.00000000 1.0000000 0.00000000
and..: 0.00000000 0.00000000 0.00000000 1.0000000
I have just taken the three 3-vectors axisX, axisY, axisZ, padded them with 0 at the end, and added the row [0 0 0 1] at the bottom.
I also need the inverse of that matrix. Since the coordinate system is an orthonormal frame, the inverse is the transpose. You can use the InverseOrthonormal function in the library; all it does is form the transpose.
Now take your mystery matrix, and pre-multiply it by the coordinate change matrix, and post-multiply it by the inverse of the coordinate change matrix. Then apply one of the two calculations above using inverse trig functions. Crossing my fingers, I think that's it ...
If that doesn't work, then pre-multiply the mystery matrix by the inverse of the coordinate change matrix, and post-multiply by the coordinate change matrix. Then apply one or the other of the sets of trig formulas.
Does it work?

rotating around objects

I've been trying to make one object orbiting another:
//childX,childY,childZ are my starting coordinates
//here I count distance to the middle of my coordinate plane
float r = (float) Math.sqrt(Math.pow(childX, 2)+Math.pow(childY, 2)+Math.pow(childZ,2));
//here i convert my angles to radians
float alphaToRad = (float) Math.toRadians(findParent(figure.parentId).rotate[1]);//up_down
float betaToRad = (float) Math.toRadians(findParent(figure.parentId).rotate[0]);//left_right
float newX = (float) (r*Math.cos(betaToRad)*Math.cos(alphaToRad));
float newY = (float) (r*Math.cos(betaToRad)*Math.sin(alphaToRad));
float newZ = (float) (r*Math.sin(betaToRad));'
I have coordinates of my starting point(5,5,0) and angles 0° and 0°, so it means, that coordinates shouldn't change after calculating the new ones. But the result is:
newX: 7.071068 newY: 0.0 newZ: 0.0
Every method I try to calculate new coordinates there is always this strange result. What is that 7.07 and how can I get correct result?
#edit
To make my new point relative to the old one I just added angles of old point to the new one:
float alphaToRad = (float) Math.toRadians(findParent(figure.parentId).rotate[1]) + Math.atan(childY/childX);
float betaToRad = (float) Math.toRadians(findParent(figure.parentId).rotate[0]) + Math.asin(childZ/r);
Everything now works like it should have. Solved
7.07 is the value of r in your code, which is the distance of your point from the origin:
sqrt(5 * 5 + 5 * 5) = sqrt(50) = 7.0711
With both angles being zero, all the cos() values will be 1.0, and the sin() values 0.0. Which means that newX becomes r, which is 7.07, and both newY and newZ become 0.0. Which is exactly what you got, so there is no mystery in this result.
What you're basically doing is place the point at a given direction and distance from the origin. The distance is the same as the original distance. The direction is given by the two angles, where both angles being 0.0 corresponds to the x-axis direction.
In other words, what you're missing is that you're not taking the original direction of the point relative to the origin into account. You're placing the point at an absolute direction, based on the two angles, instead of at a direction relative to the original direction of the point.
To rotate the point by the given angles, the easiest approach is to build rotation matrices from the angles, and apply them to your points.

Need rotation matrix for opengl 3D transformation

The problem is I have two points in 3D space where y+ is up, x+ is to the right, and z+ is towards you. I want to orientate a cylinder between them that is the length of of the distance between both points, so that both its center ends touch the two points. I got the cylinder to translate to the location at the center of the two points, and I need help coming up with a rotation matrix to apply to the cylinder, so that it is orientated the correct way. My transformation matrix for the entire thing looks like this:
translate(center point) * rotateX(some X degrees) * rotateZ(some Z degrees)
The translation is applied last, that way I can get it to the correct orientation before I translate it.
Here is what I have so far for this:
mat4 getTransformation(vec3 point, vec3 parent)
{
float deltaX = point.x - parent.x;
float deltaY = point.y - parent.y;
float deltaZ = point.z - parent.z;
float yRotation = atan2f(deltaZ, deltaX) * (180.0 / M_PI);
float xRotation = atan2f(deltaZ, deltaY) * (180.0 / M_PI);
float zRotation = atan2f(deltaX, deltaY) * (-180.0 / M_PI);
if(point.y < parent.y)
{
zRotation = atan2f(deltaX, deltaY) * (180.0 / M_PI);
}
vec3 center = vec3((point.x + parent.x)/2.0, (point.y + parent.y)/2.0, (point.z + parent.z)/2.0);
mat4 translation = Translate(center);
return translation * RotateX(xRotation) * RotateZ(zRotation) * Scale(radius, 1, radius) * Scale(0.1, 0.1, 0.1);
}
I tried a solution given down below, but it did not seem to work at all
mat4 getTransformation(vec3 parent, vec3 point)
{
// moves base of cylinder to origin and gives it unit scaling
mat4 scaleFactor = Translate(0, 0.5, 0) * Scale(radius/2.0, 1/2.0, radius/2.0) * cylinderModel;
float length = sqrtf(pow((point.x - parent.x), 2) + pow((point.y - parent.y), 2) + pow((point.z - parent.z), 2));
vec3 direction = normalize(point - parent);
float pitch = acos(direction.y);
float yaw = atan2(direction.z, direction.x);
return Translate(parent) * Scale(length, length, length) * RotateX(pitch) * RotateY(yaw) * scaleFactor;
}
After running the above code I get this:
Every black point is a point with its parent being the point that spawned it (the one before it) I want the branches to fit into the points. Basically I am trying to implement the space colonization algorithm for random tree generation. I got most of it, but I want to map the branches to it so it looks good. I can use GL_LINES just to make a generic connection, but if I get this working it will look so much prettier. The algorithm is explained here.
Here is an image of what I am trying to do (pardon my paint skills)
Well, there's an arbitrary number of rotation matrices satisfying your constraints. But any will do. Instead of trying to figure out a specific rotation, we're just going to write down the matrix directly. Say your cylinder, when no transformation is applied, has its axis along the Z axis. So you have to transform the local space Z axis toward the direction between those two points. I.e. z_t = normalize(p_1 - p_2), where normalize(a) = a / length(a).
Now we just need to make this a full 3 dimensional coordinate base. We start with an arbitrary vector that's not parallel to z_t. Say, one of (1,0,0) or (0,1,0) or (0,0,1); use the scalar product ·(also called inner, or dot product) with z_t and use the vector for which the absolute value is the smallest, let's call this vector u.
In pseudocode:
# Start with (1,0,0)
mindotabs = abs( z_t · (1,0,0) )
minvec = (1,0,0)
for u_ in (0,1,0), (0,0,1):
dotabs = z_t · u_
if dotabs < mindotabs:
mindotabs = dotabs
minvec = u_
u = minvec_
Then you orthogonalize that vector yielding a local y transformation y_t = normalize(u - z_t · u).
Finally create the x transformation by taking the cross product x_t = z_t × y_t
To move the cylinder into place you combine that with a matching translation matrix.
Transformation matrices are effectively just the axes of the space you're "coming from" written down as if seen from the other space. So the resulting matrix, which is the rotation matrix you're looking for is simply the vectors x_t, y_t and z_t side by side as a matrix. OpenGL uses so called homogenuous matrices, so you have to pad it to a 4×4 form using a 0,0,0,1 bottommost row and rightmost column.
That you can load then into OpenGL; if using fixed functio using glMultMatrix to apply the rotation, or if using shader to multiply onto the matrix you're eventually pass to glUniform.
Begin with a unit length cylinder which has one of its ends, which I call C1, at the origin (note that your image indicates that your cylinder has its center at the origin, but you can easily transform that to what I begin with). The other end, which I call C2, is then at (0,1,0).
I'd like to call your two points in world coordinates P1 and P2 and we want to locate C1 on P1 and C2 to P2.
Start with translating the cylinder by P1, which successfully locates C1 to P1.
Then scale the cylinder by distance(P1, P2), since it originally had length 1.
The remaining rotation can be computed using spherical coordinates. If you're not familiar with this type of coordinate system: it's like GPS coordinates: two angles; one around the pole axis (in your case the world's Y-axis) which we typically call yaw, the other one is a pitch angle (in your case the X axis in model space). These two angles can be computed by converting P2-P1 (i.e. the local offset of P2 with respect to P1) into spherical coordinates. First rotate the object with the pitch angle around X, then with yaw around Y.
Something like this will do it (pseudo-code):
Matrix getTransformation(Point P1, Point P2) {
float length = distance(P1, P2);
Point direction = normalize(P2 - P1);
float pitch = acos(direction.y);
float yaw = atan2(direction.z, direction.x);
return translate(P1) * scaleY(length) * rotateX(pitch) * rotateY(yaw);
}
Call the axis of the cylinder A. The second rotation (about X) can't change the angle between A and X, so we have to get that angle right with the first rotation (about Z).
Call the destination vector (the one between the two points) B. Take -acos(BX/BY), and that's the angle of the first rotation.
Take B again, ignore the X component, and look at its projection in the (Y, Z) plane. Take acos(BZ/BY), and that's the angle of the second rotation.

Calculate the absolute position of the point having the position before rotation and rotation angles

How can I rotate the point (x, y, z) by angles (rx, ry, rz) about their respective axes?
That is, how do I determine the point (x1, y1, z1) resulting from the rotation of (x, y, z) by rotation angles (rx, ry, rz)?
Are there any DirectX routines which accomplish this?
What you are asking about is how to use Euler Angles for performing rotations. There are several conventions you can choose from, but it looks to me like you are interested in applying rotation about the Z axis, followed by rotation about Y and then rotation about X. For this you would post multiply by the matrix
where
c1 = cos(rx) s1 = sin(rx)
c2 = cos(ry) s2 = sin(ry)
cs = cos(rz) s3 = sin(rz)
There are several problems with this approach, one of the more common being gimbal lock. The preferred approach is to use one of the angle-axis formulations. The two most common of those are Unit Quaternion Rotations and Euler-Rodreigues Rotation Matrices. These can be composed to generate any of the 12 Euler Rotation matrices by explicitly defining three rotation axes and their associated rotation angles and then multiplying the resulting rotation representation in the reverse order they are to be applied to the vectors to be rotated.
DirectX uses Quaternions for performing rotations.
During my electronics(EM) classes I learnt converting cartesian to polar cordinates using the formula
x = r sinq cosf, y = r sinq sinf, z = r cosq
More Info Here
q is theta, f is phi.

How to convert mathematical matrix to Direct3D matrix?

When representing a mathematical matrix, rotations are performed as follows:
http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
Rx(θ) = 1 0 0
0 cos θ -sin θ
0 sin θ cos θ
Ry(θ) = cos θ 0 sin θ
0 1 0
-sin θ 0 cos θ
Rz(θ) = cos θ -sin θ 0
sin θ cos θ 0
0 0 1
However, I've discovered that Direct3D uses the transpose of these rotation matrices.
In my app I have a generic Matrix class which uses the standard mathematical rotation representations. With a simple rotation about 1 axis, it is easy to convert to a Direct3D matrix, as you can just do the transposition. However, if you rotate about x, y and then z you cannot simply get the transposed matrix.
My question is, how can I convert a mathematical matrix in to a Direct3D matrix?
Here is an example:
Matrix matrix;
matrix.RotateX(1.0f);
matrix.RotateY(1.0f);
matrix.RotateZ(1.0f);
Mathematical matrix =
m_11 0.29192656 float
m_12 -0.45464867 float
m_13 0.84147096 float
m_14 0.00000000 float
m_21 0.83722234 float
m_22 -0.30389664 float
m_23 -0.45464867 float
m_24 0.00000000 float
m_31 0.46242565 float
m_32 0.83722234 float
m_33 0.29192656 float
m_34 0.00000000 float
m_41 0.00000000 float
m_42 0.00000000 float
m_43 0.00000000 float
m_44 1.0000000 float
Direct3D matrix =
_11 0.29192656 float
_12 0.45464867 float
_13 -0.84147096 float
_14 0.00000000 float
_21 -0.072075009 float
_22 0.88774973 float
_23 0.45464867 float
_24 0.00000000 float
_31 0.95372111 float
_32 -0.072075009 float
_33 0.29192656 float
_34 0.00000000 float
_41 0.00000000 float
_42 0.00000000 float
_43 0.00000000 float
_44 1.0000000 float
Edit: Here are some examples of individual rotations.
X-Axis rotation by 1 radian
My matrix class:
1.0000000 0.00000000 0.00000000 0.00000000
0.00000000 0.54030228 -0.84147096 0.00000000
0.00000000 0.84147096 0.54030228 0.00000000
0.00000000 0.00000000 0.00000000 1.0000000
Direct3D:
1.0000000 0.00000000 0.00000000 0.00000000
0.00000000 0.54030228 0.84147096 0.00000000
0.00000000 -0.84147096 0.54030228 0.00000000
0.00000000 0.00000000 0.00000000 1.0000000
As you can see, the Direct3D matrix is exactly the transpose of my matrix class (my class gives the same results as the examples given by Wikipedia at the top of this question).
I've always traced this confusion back to the late 80s. As I remember it, there were two particularly influential books on graphics at the time. One of them wrote vectors as row vectors on the left of matrices; the book was quite hardware oriented - conceptually you thought of the vectors as flowing left-to-right through a pipeline of transform matrices. Rendermorphics (which was later picked up by Microsoft to become Direct3D) went down this route. The other book wrote vectors as column vectors on the right of matrices, which is the way OpenGL does it (and I think most mathematicians would naturally gravitate towards this, although I have met exceptions).
However, both approaches are entirely equally valid mathematics! If you're confused by Direct3D, start thinking in terms of writing row vectors on the left of matrices, not in terms of transposing the matrices.
You're not the first person to be confused by this (see also).
The DirectX matrix classes are an implementation of a mathematical matrix.
The handedness only exhibits itself when you do operations on it such as rotation.
The transpose should give you the result you are looking for as long as the same operations are done on both the DIrectX matrix and your 'mathematical matrix'. My guess is that there's a difference in the implementations of rotation, or the order the rotations are being done differs.
Given that the only terms off of the prime diagonal are of the form ±sin ( θ ) and that sin ( -θ ) = - sin ( θ ) but cos ( -θ ) = cos ( θ ), the relationship between Direct3D and the Wikipedia maths can also be seen as an opposite interpretation of the direction of the angle.