Матрица вращения задана углом и точкой в ​​X, Y, Z - PullRequest
4 голосов
/ 04 марта 2011

Я выполняю манипуляции с изображениями и хочу повернуть все пиксели в пространстве xyz на основе угла, начала координат и координат x, y и z.

Мне просто нужно настроить правильную матрицу (4x4), и тогда мне будет хорошо. Угол указывается в градусах, а не в радианах, а x, y, z будут от -1 до 1 (плавает)

EDIT:

Хорошо, вот код, который я взбил для поворота вокруг заданной строки, определяемой началом координат и координатами 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 lib.

Фу, много математики!

Ответы [ 3 ]

8 голосов
/ 04 марта 2011

Полные матрицы вращения получены и даны в 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.

Статья также включает в себя матрицы и формулы для поворотов вокруг произвольной оси (необязательно через начало координат), Javaкод, доступный по лицензии Apache, и ссылка на веб-приложение, иллюстрирующее ротацию.

1 голос
/ 04 марта 2011

Использовать структуру Matrix3D ( MSDN ) - представляет матрицу 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;
}
0 голосов
/ 12 октября 2015

Функция 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]));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...