旋转矩阵给定角度和 X、Y、Z 中的点

发布于 2024-10-20 12:23:23 字数 1096 浏览 2 评论 0原文

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

我只需要设置正确的矩阵(4x4),然后我就可以从那里开始了。角度以度为单位,而不是弧度,x、y、z 都将从 -1 到 1(浮点)

编辑:

好的,这是我编写的代码,用于围绕由 定义的给定线进行旋转原点和 X、Y、Z 坐标。

        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 库都应该不会太难实现。

唷,很多数学!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦毁影碎の 2024-10-27 12:23:23

完整的旋转矩阵是在 https://sites.google.com/site/glennmurray/glenn-murray-ph-d/rotation-matrices-and-formulas/rotation-about -三维任意轴

摘自论文:

5.2 绕原点旋转的简化矩阵

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

< img src="https://i.sstatic.net/rFtsT.png" alt="绕原点旋转的简化 3D 矩阵。">

如果您想要旋转一个点 (x, y, z),然后我们可以获得七个变量的函数,该函数产生旋转点:

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

旋转点的公式。

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

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.

Simplified 3D matrix for rotations about the origin.

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) =

Formula for rotated point.

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.

拒绝两难 2024-10-27 12:23:23

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

请查看此处的教程:构建 3D 引擎

本质上,矩阵是为 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;
}

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;
}
猫性小仙女 2024-10-27 12:23:23

函数 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]));
}

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]));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文