2009-06-21 20 views
7

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

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:

  • Encontrar un punto central (punto medio) en el plano
  • Restar desde todos los puntos de datos para organizarlos en torno al origen
  • Girar la normalidad de modo que se convierte en (0,0, -1)
  • Aplicar esta rotación a todos los puntos de datos
  • uso proyección ortogonal (básicamente, omitir 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í!

Matlab código siguiente:

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 tener n2 y componente de cero. Sin embargo, eso ya falla para el vector (-0.6367, 0.7697, 0.0467).

+0

¿Por qué no simplemente proyecta todos los puntos en el plano y luego gira todo para que pueda dibujar los puntos usando sus coordenadas xz (o xy)? –

+0

Eso, o coloque la cámara directamente en el plano de modo que esté mirando directamente. –

+0

La idea de la cámara es buena. Mueves la cámara desde el avión desde el origen a cierta distancia a lo largo de la normal. Luego apuntas la cámara al origen. Por supuesto, esto supone que tienes un código de proyección de cámara, que se puede hacer con rotaciones o vectores. – Nosredna

Respuesta

10

Si tienes un avión, tienes un vector normal y un origen. No haría ninguna "rotación" en absoluto. Estás a unas pocas operaciones vectoriales lejos 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 de su avión).
  • Genera el nuevo eje x cruzando la nueva z con la nueva y.
  • Convierte todos tus vectores de ejes nuevos en vectores unitarios (longitud 1).
  • Para cada punto que tenga, cree un vector que sea desde su nuevo origen hasta el punto (resta vectorial del punto --original_plane). Simplemente salpique con los nuevos vectores de unidad x y nueva y obtendrá un par (x, y) ¡puede trazar!

Si ya tiene funciones de producto cross y dot, estas son solo unas pocas líneas de código. Sé que funciona porque la mayoría de los videojuegos 3D que escribí funcionaron de esta manera.

trucos:

  • Prestar atención a las direcciones que sus vectores están apuntando. Si apuntan en el sentido incorrecto, niegue el vector resultante o cambie el orden del producto cruzado.
  • Tiene problemas si la normal de su avión es exactamente la misma que su eje x original.
+0

¡Esto realmente suena muy bien! – ypnos

+1

¡Fantástica respuesta! Esto solucionó muchos problemas que he tenido (lidiar con errores rotacionales a través de trigonometría) todo este tiempo. Creo que necesito tomar un curso de álgebra lineal. – Kaiged

1

Cómo sobre: ​​

descomponer 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 de puntos de lo normal con el eje Z, y gire a lo largo de cada X, Y con que alineó.

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

0

Aunque hubo otras respuestas interesantes, esta es la solución que nos dimos a la espera de 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; 

(Es devolver una matriz de esperar una correcta rotación doble)

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

Espero que también encuentre tiempo para probar la solución de Nosredna. Siempre es bueno evitar la trigonometría.

+0

Quería mencionar que cada vez que vaya por la ruta trigonométrica en lugar de por la ruta vectorial y se encuentre utilizando atan, vea si atan2 funcionará para usted. Toma tanto x como y como argumentos en lugar de tomar un solo argumento. Coloca la respuesta en el cuadrante correcto para que pueda evitar el desorden condicional habitual. http://en.wikipedia.org/wiki/Atan2 – Nosredna

+0

Sí, atan2 es increíble y me ha ahorrado mucho tiempo antes. Una buena pista. – ypnos

Cuestiones relacionadas