旋转矩阵给定角度和X,Y,Z点

时间:2011-03-04 02:03:10

标签: c# math matrix

我正在进行图像处理,我想根据角度,原点以及x,y和z坐标旋转xyz空间中的所有像素。

我只需要设置正确的矩阵(4x4)然后我就会很好。角度是度,而不是弧度,x,y,z都是从-1到1(浮点数)

编辑:

好的,这是我为了由原点和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));

这有点复杂,我正在使用一个自定义的Matrix库,但是没有任何东西可以用任何正常运行的Matrix lib来实现。

p,很多数学!

3 个答案:

答案 0 :(得分:8)

完整的旋转矩阵在https://sites.google.com/site/glennmurray/Home/rotation-matrices-and-formulas得出并给出。

来自论文:

5.2关于原点旋转的简化矩阵

注意这假设(u,v,w)是旋转轴的方向向量,并且u ^ 2 + v ^ 2 + w ^ 2 = 1.

Simplified 3D matrix for rotations about the origin.

如果你想要旋转一个点(x,y,z),那么我们可以得到七个变量的函数,产生旋转点:

f (x,y,z,u,v,w,theta)=

Formula for rotated point.

本文还包括关于任意轴(不一定是通过原点)的旋转的矩阵和公式,Apache许可下可用的Java代码,以及说明旋转的Web应用程序的链接。

答案 1 :(得分:1)

使用Matrix3D结构(MSDN) - 表示用于三维空间转换的4 x 4矩阵

在这里查看教程:Building a 3D Engine

基本上,矩阵是为X,Y和Z旋转构建的,然后你可以按任意顺序乘以旋转。

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;
}

答案 2 :(得分:0)

函数rotateAroundAxis()围绕3D中的任何轴旋转点。这是我使用解析几何和编程来对3D进行旋转的解决方案。代码是用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]));
}