Reputation: 7259
I am doing image manipulation and I want to rotate all of the pixels in xyz space based on an angle, the origin, and an x,y, and z coordinate.
I just need to setup the proper matrix (4x4) and then I will be good from there. The Angle is in degrees, not radians and the x,y,z are all going to be from -1 to 1 (floats)
EDIT:
Ok, here is the code that I whipped up to do the rotation about a given line defined by the origin and an X, Y, Z coorinate.
float ang = angD * (float)(Math.PI / 180); // from degrees to radians, if needed
//U = n*n(t) + cos(a)*(I-n*n(t)) + sin(a)*N(x).
var u = MatrixDouble.Identity(4); // 4x4 Identity Matrix
u = u.Multiply(Math.Cos(ang));
var n = new MatrixDouble(1, 4, new List<double> { x, y, z, 0 });
var nt = n.Transpose();
// This next part is the N(x) matrix. The data is inputted in Column
// first order and fills in the 4x4 matrix with the given 16 Doubles
var nx = new MatrixDouble(4, 4, new List<double> { 0, z, -y, 0, -z, 0, x, 0, y, -x, 0, 0, 0, 0, 0, 1 });
nx = nx.Multiply(Math.Sin(ang));
var ret = nt.Multiply(n);
ret[3, 3] = 1;
u = u.Subtract(ret);
u = ret.Add(u.Add(nx));
It's a little complicated and I'm using a custom Matrix library, but nothing up there should be too hard to implement with any functioning Matrix lib.
Phew, lots of math!
Upvotes: 5
Views: 20577
Reputation: 6573
The complete rotation matrices are derived and given at https://sites.google.com/site/glennmurray/glenn-murray-ph-d/rotation-matrices-and-formulas/rotation-about-an-arbitrary-axis-in-3-dimensions.
From the paper:
5.2 The simplified matrix for rotations about the origin
Note this assumes that (u, v, w) is a direction vector for the axis of rotation and that u^2 + v^2 + w^2 = 1.
If you have a point (x, y, z) that you want to rotate, then we can obtain a function of of seven variables that yields the rotated point:
f(x, y, z, u, v, w, theta) =
The paper also includes matrices and formulas for rotations about an arbitrary axis (not necessarily through the origin), Java code available under the Apache license, and a link to a web app that illustrates rotations.
Upvotes: 11
Reputation: 59
Function rotateAroundAxis()
rotates point around any axis in 3D. It is my solution to the rotation in 3D using analytic geometry and programming to model the process. The code is in JavaScript.
function rotateAroundAxis(A, B, C, alpha, precision) {
// A is rotated point, BC is axis, alpha is angle
// A, B, C are points in format [Ax, Ay, Az], alpha is float, precision is int
// A2 is output in format [A2x, A2y, A2z]
if((A[0] - B[0])*(A[1] - C[1]) == (A[1] - B[1])*(A[0] - C[0]) && (A[1] - B[1])*(A[2] - C[2]) == (A[1] - C[1])*(A[2] - B[2]) && (A[0] - B[0])*(A[2] - C[2]) == (A[0] - C[0])*(A[2] - B[2])) {
return A
}// Return the original point if it is on the axis.
var D = findClosestPoint(A, B, C, precision);
var w = crossProduct(new Array(C[0] - B[0], C[1] - B[1], C[2] - B[2]), new Array(C[0] - A[0], C[1] - A[1], C[2] - A[2]));
var W = pointPlusVector(A, w);
var sizeAW = vectorSize(A, W);
var sizeDA = vectorSize(D, A);
var sizeAE = sizeDA*(Math.sin(0.5*alpha))/(Math.cos(0.5*alpha));
var E = new Array(A[0] + (W[0] - A[0])*sizeAE/sizeAW, A[1] + (W[1] - A[1])*sizeAE/sizeAW, A[2] + (W[2] - A[2])*sizeAE/sizeAW);
var sizeDE = vectorSize(D, E);
var sizeEF = sizeAE*Math.sin(alpha/2);
var F = new Array(D[0] + (E[0] - D[0])*(sizeDE - sizeEF)/sizeDE, D[1] + (E[1] - D[1])*(sizeDE - sizeEF)/sizeDE, D[2] + (E[2] - D[2])*(sizeDE - sizeEF)/sizeDE);
var A2 = new Array(A[0] + 2*(F[0] - A[0]), A[1] + 2*(F[1] - A[1]), A[2] + 2*(F[2] - A[2]))
return A2;
}
function angleSize(A, S, B) {
ux = A[0] - S[0]; uy = A[1] - S[1]; uz = A[2] - S[2];
vx = B[0] - S[0]; vy = B[1] - S[1]; vz = B[2] - S[2];
if((Math.sqrt(ux*ux + uy*uy + uz*uz)*Math.sqrt(vx*vx + vy*vy + vz*vz)) == 0) {return 0}
return Math.acos((ux*vx + uy*vy + uz*vz)/(Math.sqrt(ux*ux + uy*uy + uz*uz)*Math.sqrt(vx*vx + vy*vy + vz*vz)));
}
function findClosestPoint(N, B, C, precision) {
// We will devide the segment BC into many tiny segments and we will choose the point F where the |NB F| distance is the shortest.
if(B[0] == C[0] && B[1] == C[1] && B[2] == C[2]) {return B}
var shortest = 0;
for(var i = 0; i <= precision; i++) {
var Fx = Math.round(precision*precision*(B[0] + (C[0] - B[0])*i/precision))/(precision*precision);
var Fy = Math.round(precision*precision*(B[1] + (C[1] - B[1])*i/precision))/(precision*precision);
var Fz = Math.round(precision*precision*(B[2] + (C[2] - B[2])*i/precision))/(precision*precision);
var sizeF = vectorSize(new Array(N[0], N[1], N[2]), new Array(Fx, Fy, Fz));
if(i == 0 || sizeF < shortest) { // first run or condition
shortest = sizeF;
F = new Array(Fx, Fy, Fz);
}
}
// recursion, if it is an outer point return findClosestPoint(we mirror further point in the closer one)
if(F[0] == Math.round(precision*precision*(B[0]))/(precision*precision) && F[1] == Math.round(precision*precision*(B[1]))/(precision*precision) && F[2] == Math.round(precision*precision*(B[2]))/(precision*precision)) { // F == B
if(Math.round(precision*precision*180*angleSize(C, B, N)/Math.PI)/(precision*precision) <= 90){return F} else {return findClosestPoint(N, new Array(2*B[0] - C[0], 2*B[1] - C[1], 2*B[2] - C[2]), B, precision)}
} else if (F[0] == Math.round(precision*precision*(C[0]))/(precision*precision) && F[1] == Math.round(precision*precision*(C[1]))/(precision*precision) && F[2] == Math.round(precision*precision*(C[2]))/(precision*precision)) { // F == C
if(Math.round(precision*precision*180*angleSize(B, C, N)/Math.PI)/(precision*precision) <= 90) {return F} else {return findClosestPoint(N, C, new Array(2*C[0] - B[0], 2*C[1] - B[1], 2*C[2] - B[2]), precision)}
} else {return F;}
}
function vectorSize(A, B) {
var ux = A[0] - B[0];
var uy = A[1] - B[1];
var uz = A[2] - B[2];
return Math.sqrt(ux*ux + uy*uy + uz*uz);
}
function crossProduct(u, v) {
return (new Array(u[1]*v[2] - u[2]*v[1], u[2]*v[0] - u[0]*v[2], u[0]*v[1] - u[1]*v[0]));
}
function pointPlusVector (A, v) {
return (new Array(A[0] + v[0], A[1] + v[1], A[2] + v[2]));
}
Upvotes: 1
Reputation: 49423
Use the Matrix3D Structure (MSDN) - Represents a 4 x 4 matrix used for transformations in 3-D space
Take a look here for a tutorial: Building a 3D Engine
Essentially, matrices are built for X, Y, and Z rotations and then you can multiply the rotations in any order.
public static Matrix3D NewRotateAroundX(double radians)
{
var matrix = new Matrix3D();
matrix._matrix[1, 1] = Math.Cos(radians);
matrix._matrix[1, 2] = Math.Sin(radians);
matrix._matrix[2, 1] = -(Math.Sin(radians));
matrix._matrix[2, 2] = Math.Cos(radians);
return matrix;
}
public static Matrix3D NewRotateAroundY(double radians)
{
var matrix = new Matrix3D();
matrix._matrix[0, 0] = Math.Cos(radians);
matrix._matrix[0, 2] = -(Math.Sin(radians));
matrix._matrix[2, 0] = Math.Sin(radians);
matrix._matrix[2, 2] = Math.Cos(radians);
return matrix;
}
public static Matrix3D NewRotateAroundZ(double radians)
{
var matrix = new Matrix3D();
matrix._matrix[0, 0] = Math.Cos(radians);
matrix._matrix[0, 1] = Math.Sin(radians);
matrix._matrix[1, 0] = -(Math.Sin(radians));
matrix._matrix[1, 1] = Math.Cos(radians);
return matrix;
}
Upvotes: 2