math - studio - superponer graficas en r ggplot
Dada una superficie normal, encontrar rotaciĆ³n para plano 3D (2)
Algunas cosas útiles sobre las rotaciones:
- Cualquiera de los tres vectores ortonormales dispuestos como filas define una transformación en una nueva base (una rotación en esa base).
- La transposición de cualquier rotación es su inversa.
- Por lo tanto, cualquiera de los tres vectores ortonormales ordenados como columnas define una rotación de alguna base en su marco de referencia "mundial".
Entonces, el problema es encontrar cualquier conjunto de tres vectores ortonormales y organizarlos como
| x1 x2 x3 0 |
| y1 y2 y3 0 |
| z1 z2 z3 0 |
| 0 0 0 1 |
esto es exactamente lo que intenta hacer el método que describiste, si no funciona, entonces hay un problema con tu implementación.
Obviamente, podemos usar su normal como (x1, y1, z1), pero el problema es que el sistema tiene infinitas soluciones para los dos vectores restantes (aunque conocer uno de ellos le da el otro, como producto cruzado). El siguiente código debería dar un vector estable perpendicular a (x1, y1, z1):
float normal[3] = { ... };
int imin = 0;
for(int i=0; i<3; ++i)
if(std::abs(normal[i]) < std::abs(normal[imin]))
imin = i;
float v2[3] = {0,0,0};
float dt = normal[imin];
v2[imin] = 1;
for(int i=0;i<3;i++)
v2[i] -= dt*normal[i];
Básicamente, esto utiliza la ortogonalización de Gram-Schmidt con la dimensión que ya es más ortogonal al vector normal. v3 se puede obtener tomando el producto cruzado de normal
y v2
.
Es posible que deba tener cuidado al configurar la rotación, se trata del origen, por lo que debe aplicar la traslación después de la rotación y es para vectores de columna en lugar de vectores de fila. Si está usando OpenGL, observe que OpenGL toma los arreglos en orden de columna mayor (en lugar del orden de fila mayor de C), por lo que es posible que tenga que transponer.
Me temo que no he probado lo anterior, simplemente lo atrapé de un código que escribí hace un tiempo y lo adapté a tu problema. Ojalá no haya olvidado ningún detalle.
Edit: olvidé algo :)
La matriz anterior asume que su normal al polígono es a lo largo del eje x, y tengo la sospecha de que no será así, todo lo que necesita hacer es colocar el vector "normal" en la columna correcta de la matriz de rotación, y v2 / v3 en las otras dos columnas. Entonces, si lo normal a su polígono es a lo largo del eje z, entonces lo normal va en la tercera columna y v2 / v3 en las primeras dos columnas.
Lo siento si eso causa alguna confusión.
Así que tengo un plano 3D descrito por 2 vectores:
P: un punto que se encuentra en el plano.
N: la superficie normal para el plano.
Y tengo un polígono cuadrado muy grande y plano, que quiero representar para representar este plano. Puedo traducir fácilmente el polígono al punto dado, pero luego necesito encontrar la rotación adecuada que se aplique para que la normal de la superficie sea realmente la normal de la superficie.
Probé un método mencionado en otro lugar donde estaba:
1) Tome cualquier vector paralelo (V) a la normal (N), y tome el producto cruzado (W1)
2) Tome el producto cruzado de (W1) y (N) ahora (W2) y ese es un Vector (V '') que se encuentra en el Plano
Luego genero una matriz de rotación basada en (V '') tendida en el Plano, de modo que mi polígono se alinee con (V''). eso funcionó, pero está claro que este método no funciona correctamente como un todo. El polígono no es perfectamente perpendicular a la superficie normal.
¿Alguna idea sobre cómo generar la rotación adecuada?
No estoy seguro de qué método está utilizando para procesar, pero toma prestado de la matriz de OpenSceneGraph :
void Matrix_implementation::makeLookAt(const Vec3d& eye,const Vec3d& center,const Vec3d& up)
{
Vec3d f(center-eye);
f.normalize();
Vec3d s(f^up);
s.normalize();
Vec3d u(s^f);
u.normalize();
set(
s[0], u[0], -f[0], 0.0,
s[1], u[1], -f[1], 0.0,
s[2], u[2], -f[2], 0.0,
0.0, 0.0, 0.0, 1.0);
preMultTranslate(-eye);
}
inline void Matrixd::preMultTranslate( const Vec3d& v )
{
for (unsigned i = 0; i < 3; ++i)
{
double tmp = v[i];
if (tmp == 0)
continue;
_mat[3][0] += tmp*_mat[i][0];
_mat[3][1] += tmp*_mat[i][1];
_mat[3][2] += tmp*_mat[i][2];
_mat[3][3] += tmp*_mat[i][3];
}
}
Esperemos que esto te dé una idea para tu implementación. No soy muy bueno con los cuaterniones que podrían tener una solución más simple, pero este método funciona bien para mí.