transformacion sirven rotacion robotica que para obtener matriz los euler ejemplos cuaterniones como angulos math vector quaternions

math - sirven - Encontrar quaternion que representa la rotación de un vector a otro



para que sirven los cuaterniones (6)

Solución de vector de mitad de camino

Se me ocurrió la solución que creo que Imbrondir estaba tratando de presentar (aunque con un pequeño error, que probablemente fue la razón por la cual sinisterchipmunk tuvo problemas para verificarlo).

Dado que podemos construir un cuaternión que represente una rotación alrededor de un eje como ese:

q.w == cos(angle / 2) q.x == sin(angle / 2) * axis.x q.y == sin(angle / 2) * axis.y q.z == sin(angle / 2) * axis.z

Y que el producto punto y cruz de dos vectores normalizados es:

dot == cos(theta) cross.x == sin(theta) * perpendicular.x cross.y == sin(theta) * perpendicular.y cross.z == sin(theta) * perpendicular.z

Viendo que una rotación de u a v se puede lograr girando por theta (el ángulo entre los vectores) alrededor del vector perpendicular, parece que podemos construir directamente un cuaternión que represente dicha rotación a partir de los resultados del punto y productos cruzados ; sin embargo, tal como está, theta = angle / 2 , lo que significa que hacerlo daría como resultado el doble de la rotación deseada.

Una solución es calcular un vector a medio camino entre uyv , y usar el punto y el producto cruzado de uy el vector de mitad de camino para construir un cuaternión que represente una rotación del doble del ángulo entre uy el vector de mitad de camino , que nos lleva todo el camino hasta v !

Hay un caso especial en el que u == -v y un vector de mitad de camino único se vuelve imposible de calcular. Esto es esperado, dado el infinito número de rotaciones de "arco más corto" que nos pueden llevar de u a v , y simplemente debemos rotar 180 grados alrededor de cualquier vector ortogonal a u ( v ) como nuestra solución de caso especial. Esto se hace tomando el producto cruzado normalizado de u con cualquier otro vector no paralelo a u .

El pseudocódigo sigue (obviamente, en realidad, el caso especial debería tener en cuenta las imprecisiones de los puntos flotantes, probablemente verificando los productos puntos contra un cierto umbral en lugar de un valor absoluto).

También tenga en cuenta que no hay ningún caso especial cuando u == v (se produce el cuaternión de identidad; compruebe y vea por usted mismo).

// N.B. the arguments are _not_ axis and angle, but rather the // raw scalar-vector components. Quaternion(float w, Vector3 xyz); Quaternion get_rotation_between(Vector3 u, Vector3 v) { // It is important that the inputs are of equal length when // calculating the half-way vector. u = normalized(u); v = normalized(v); // Unfortunately, we have to check for when u == -v, as u + v // in this case will be (0, 0, 0), which cannot be normalized. if (u == -v) { // 180 degree rotation around any orthogonal vector return Quaternion(0, normalized(orthogonal(u))); } Vector3 half = normalized(u + v); return Quaternion(dot(u, half), cross(u, half)); }

La función orthogonal devuelve cualquier vector ortogonal al vector dado. Esta implementación utiliza el producto cruzado con el vector de base más ortogonal.

Vector3 orthogonal(Vector3 v) { float x = abs(v.x); float y = abs(v.y); float z = abs(v.z); Vector3 other = x < y ? (x < z ? X_AXIS : Z_AXIS) : (y < z ? Y_AXIS : Z_AXIS); return cross(v, other); }

Solución Half-Way Quaternion

Esta es en realidad la solución presentada en la respuesta aceptada, y parece ser marginalmente más rápida que la solución de vector de mitad de camino (~ 20% más rápido según mis mediciones, aunque no creo en mi palabra). Lo agrego aquí en caso de que otros como yo estén interesados ​​en una explicación.

Esencialmente, en lugar de calcular un cuaternión usando un vector a mitad de camino, puede calcular el cuaternión que da como resultado el doble de la rotación requerida (como se detalla en la otra solución), y encontrar el cuaternario a medio camino entre eso y cero grados.

Como expliqué antes, el quaternion para el doble de la rotación requerida es:

q.w == dot(u, v) q.xyz == cross(u, v)

Y el quaternion para la rotación cero es:

q.w == 1 q.xyz == (0, 0, 0)

Calcular el cuaternión a mitad de camino es simplemente una cuestión de sumar los cuaterniones y normalizar el resultado, al igual que con los vectores. Sin embargo, como es también el caso con los vectores, los cuaterniones deben tener la misma magnitud, de lo contrario el resultado se sesgará hacia el cuaternión con una magnitud mayor.

Un cuaternión construido a partir del producto punto y cruz de dos vectores tendrá la misma magnitud que esos productos: length(u) * length(v) . En lugar de dividir los cuatro componentes por este factor, podemos ampliar el cuaternión de identidad. Y si se preguntaba por qué la respuesta aceptada aparentemente complica las cosas al usar sqrt(length(u) ^ 2 * length(v) ^ 2) , es porque la longitud cuadrada de un vector es más rápida de calcular que la longitud, por lo que podemos guardar un cálculo sqrt . El resultado es:

q.w = dot(u, v) + sqrt(length_2(u) * length_2(v)) q.xyz = cross(u, v)

Y luego normaliza el resultado. El pseudo código sigue:

Quaternion get_rotation_between(Vector3 u, Vector3 v) { float k_cos_theta = dot(u, v); float k = sqrt(length_2(u) * length_2(v)); if (k_cos_theta / k == -1) { // 180 degree rotation around any orthogonal vector return Quaternion(0, normalized(orthogonal(u))); } return normalized(Quaternion(k_cos_theta + k, cross(u, v))); }

Tengo dos vectores uy v. ¿Hay alguna manera de encontrar un cuaternión que represente la rotación de u a v?


¿Por qué no representar el vector usando cuaterniones puros? Es mejor si los normalizas primero quizás.
q 1 = (0 u x u y u z ) ''
q 2 = (0 v x v y v z ) ''
q 1 q putrefacción = q 2
Pre-multiplicar con q 1 -1
q rot = q 1 -1 q 2
donde q 1 -1 = q 1 norma conj / q
Esto se puede considerar como "división izquierda". La división correcta, que no es lo que quieres es:
q putrefacción, derecha = q 2 -1 q 1


Desde el punto de vista del algoritmo, la solución más rápida se ve en pseudocódigo

Quaternion shortest_arc(const vector3& v1, const vector3& v2 ) { // input vectors NOT unit Quaternion q( cross(v1, v2), dot(v1, v2) ); // reducing to half angle q.w += q.magnitude(); // 4 multiplication instead of 6 and more numerical stable // handling close to 180 degree case //... code skipped return q.normalized(); // normalize if you need UNIT quaternion }

Asegúrese de que necesita unidades de cuaterniones (por lo general, se requiere para la interpolación).

NOTA: los cuaterniones no unitarios se pueden usar con algunas operaciones más rápido que la unidad.


El problema tal como se establece no está bien definido: no hay una rotación única para un par de vectores dado. Considere el caso, por ejemplo, donde u = <1, 0, 0> y v = <0, 1, 0> . Una rotación de u a v sería una rotación pi / 2 alrededor del eje z. Otra rotación de u a v sería una rotación pi alrededor del vector <1, 1, 0> .


No soy muy bueno en Quaternion. Sin embargo, luché durante horas con esto y no pude hacer que la solución Polaris878 funcionara. Intenté prenormalizar v1 y v2. Normalizando q. Normalizando q.xyz. Sin embargo, todavía no lo entiendo. El resultado todavía no me dio el resultado correcto.

Al final, aunque encontré una solución que sí lo hizo. Si ayuda a alguien más, aquí está mi código de trabajo (python):

def diffVectors(v1, v2): """ Get rotation Quaternion between 2 vectors """ v1.normalize(), v2.normalize() v = v1+v2 v.normalize() angle = v.dot(v2) axis = v.cross(v2) return Quaternion( angle, *axis )

Se debe hacer un caso especial si v1 y v2 son paralelos a v1 == v2 o v1 == -v2 (con cierta tolerancia), donde creo que las soluciones deben ser Quaternion (1, 0,0,0) (sin rotación) o Quaternion (0, * v1) (rotación de 180 grados)


Quaternion q; vector a = crossproduct(v1, v2); q.xyz = a; q.w = sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + dotproduct(v1, v2);

No te olvides de normalizar q.

Richard tiene razón al decir que no hay una rotación única, pero lo anterior debe dar el "arco más corto", que es probablemente lo que necesita.