Pregunta

Tengo un conjunto de puntos de datos en el espacio 3D que aparentemente todos caen en un plano específico. Yo uso PCA para calcular los parámetros del plano. El tercer componente de PCA me da el vector normal del plano (componente más débil).

Lo que quiero hacer a continuación es transformar todos los puntos en dicho plano y mirarlo en 2D.

Mi idea era hacer lo siguiente:

  • Encuentra un punto central (punto promedio) en el avión
  • Restarlo de todos los puntos de datos para organizarlos alrededor del origen
  • Rotar lo normal para que se convierta en (0,0, -1)
  • Aplicar esta rotación a todos los puntos de datos
  • Usar proyección ortogonal (básicamente, omitir el eje z)

Ahora estoy atascado en encontrar la operación de rotación correcta. Intenté trabajar con acos o atan y configurar dos matrices de rotación. Parece que ambos métodos (usando acos, usando atan) me dan el resultado incorrecto. ¡Quizás puedas ayudarme aquí!

El código de Matlab sigue:

b = atan(n(1) / n(2));
rotb = [cos(b) -sin(b) 0; sin(b) cos(b) 0; 0 0 1];
n2 = n * rotb;
a = atan(n(1) / n(3));
rota = [cos(a) 0 sin(a); 0 1 0; -sin(a) 0 cos(a)];
n3 = n2 * rotaows:

Espero que n2 tenga un componente y de cero. Sin embargo, eso ya falla para el vector (-0.6367, 0.7697, 0.0467).

¿Fue útil?

Solución

Si tiene un plano, tiene un vector normal y un origen. No haría ninguna "rotación" en absoluto. Estás a solo unas pocas operaciones vectoriales de tu respuesta.

  • Llamemos al vector normal de su avión el nuevo eje z.
  • Puede generar el nuevo eje y cruzando el antiguo eje x con el nuevo eje z (el plano es normal).
  • Genere el nuevo eje x cruzando la nueva z con la nueva y.
  • Convierta todos sus nuevos vectores de eje en vectores unitarios (longitud 1).
  • Por cada punto que tenga, cree un vector que sea desde su nuevo origen hasta el punto (resta del vector del punto - origen_plano). ¡Simplemente puntee con los nuevos vectores de unidad xy nueva y y obtendrá un par (x, y) que puede trazar!

Si ya tiene funciones de productos cruzados y de puntos, estas son solo algunas líneas de código. Sé que funciona porque la mayoría de los videojuegos en 3D que escribí funcionaron de esta manera.

Trucos:

  • Presta atención a qué direcciones apuntan tus vectores. Si apuntan en la dirección incorrecta, niegue el vector resultante o cambie el orden del producto cruzado.
  • Tiene problemas si la normalidad de su avión es exactamente la misma que su eje x original.

Otros consejos

¿Qué tal:

Descomponga el vector normal en un vector en el plano XY y un vector Z. Luego aplique una rotación alrededor del eje Z para alinear el vector XY con uno de los ejes. Luego encuentre el producto escalar de lo normal con el eje Z, y gire a lo largo de cualquier X, Y con el que se alineó.

La idea es alinear el vector normal con Z, y al hacerlo, su plano es ahora el plano XY.

Aunque hubo otras respuestas interesantes, esta es la solución que descubrimos mientras esperábamos las respuestas:

function roti = magic_cosini(n)
    b = acos(n(2) / sqrt(n(1)*n(1) + n(2)*n(2)));
    bwinkel = b * 360 / 2 / pi;
    if (n(1) >= 0)
        rotb = [cos(-b) -sin(-b) 0; sin(-b) cos(-b) 0; 0 0 1];
    else
        rotb = [cos(-b) sin(-b) 0; -sin(-b) cos(-b) 0; 0 0 1];
    end
    n2 = n * rotb;
    a = acos(n2(3) / sqrt(n2(2)*n2(2) + n2(3)*n2(3)));
    awinkel = a * 360 / 2 / pi;
    rota = [1 0 0; 0 cos(-a) -sin(-a); 0 sin(-a) cos(-a)];
    roti = rotb * rota;

(Devuelve una matriz de doble rotación con suerte correcta)

La falla que tuvimos antes y que solucionamos aquí fue esp. lidiar con el signo del componente X, que no estaba cubierto en los cálculos del coseno. Esto nos hizo rotar en la dirección incorrecta una vez (girando con un ángulo de 180 °).

¡Espero encontrar tiempo para probar la solución de Nosredna! Siempre es bueno evitar la trigonometría.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top