¿Cómo puedo comparar dos cuaterniones para la igualdad lógica?

9

Estoy tratando de escribir algunas pruebas unitarias y me doy cuenta de que no sé cómo comparar los cuaterniones. Necesito saber si dos cuaterniones representan la misma orientación (el objeto estaría orientado de la misma manera). Con una posición similar a un vector, simplemente compararía las partes y comprobaría que están lo suficientemente cerca, pero para los cuaterniones los valores pueden ser muy diferentes.

¿Cómo puedo comparar dos cuaterniones?

edA-qa mort-ora-y
fuente
No estoy seguro de si es una práctica estándar, pero en Java y Unity, por ejemplo, los cuaterniones se almacenan como cuatro valores flotantes. Simplemente compárelos entre sí como se describe en estas publicaciones: answers.unity3d.com/questions/288338/… stackoverflow.com/questions/5803627/quaternion-comparision
Tholle
1
@Tholle el usuario también está preocupado por el impacto de aplicar el cuaternión para transformar / rotar una entidad 3D (es decir, en pose). Dos cuaterniones diferentes pueden lograr la misma rotación (por ejemplo, qy -q). La forma ingenua (computacionalmente-wise) sería aplicar tanto a los cuaterniones el mismo vector y ver si sus resultados son diferentes de vectores ..
teodron

Respuestas:

7

Si sus dos cuaterniones son q1y q2, representan la misma rotación si se cumple alguna de estas dos condiciones:

  1. q1es sabio componente aproximadamente igual a q2OR
  2. q1 es sabio componente aproximadamente igual a -q2

Sabiendo esto, puede escribir un probador de igualdad bastante simplista que se adapte a su objetivo.

teodron
fuente
99
+1, sin embargo, qy -qrepresenta la misma orientación (que se estaba pidiendo), pero no la misma rotación. Esto es crucial al interpolar.
falstro
@falstro, creo que entiendo lo que quieres decir: los ejes de rotación están invertidos, pero el ángulo de argumento también se niega entre qy -qcuando se representa como un operador de rotación de eje de ángulo. Entonces, de hecho, técnicamente el efecto de estas rotaciones es el mismo, aunque los operadores no lo son. Y, sí, cuando SLERPING, uno debe asegurarse q1y q2acostarse en el mismo hemisferio de la hiperesfera S3 para que el slerp tome el camino más corto.
Teodron
1
Exactamente, cuando ejecutas cualquiera de las rotaciones, terminarás con la misma orientación, pero la interpolarás (ya sea que aprietes o aprendas o alguna otra interpolación sofisticada), verás que está girando de diferentes maneras. Y sí, el argumento del ángulo es negado, pero eso es lo mismo que 2pi-angle, por lo que está girando el camino largo alrededor de los ejes negados. Sin embargo, a veces esto es lo que quieres; es solo algo a tener en cuenta, q1 dot q2 > 0resulta en el turno corto, q1 dot q2 < 0toma el turno largo.
falstro
12

Solo porque no ha sido mencionado. Como los cuaterniones utilizados para la orientación espacial son siempre unidades de longitud (o deberían ser), lo siguiente también funcionará.

abs(q1.dot(q2)) > 1-EPS

donde EPS es un factor de falsificación para permitir pequeños errores debido a la precisión de coma flotante limitada. Si (y solo si) ambos cuaterniones representan la misma orientación entonces q1 = +- q2, y por lo tanto q1.dot(q2) = +- 1. Si desea asegurarse de que tengan la misma rotación (en lugar de solo orientación), elimine el abs.

falstro
fuente
@bogglez cierto. Estaba oculto en el texto tl; dr. :)
falstro
+1, bastante elegante y, tal vez, incluso más eficiente numéricamente que mi respuesta (siempre que se utilicen las operaciones SIMD :)).
Teodron
¿Cuál es la justificación matemática para esto?
fabian789
Justificación "matemática" (entre comillas porque no soy un matemático :)): dos vectores de longitud unitaria tienen un producto de puntos (también conocido como producto interno) que es 0 si están verticales entre sí, 1 * 1 = 1 si apuntan exactamente misma dirección, y 1 * 1 * cos (phi) en el caso general, con phi su ángulo ...
ntg
2

Los cuaterniones se almacenan como 4 flotadores o dobles, a menudo llamados x, y, zyw, donde los tres primeros representan un eje yw el grado de rotación alrededor de ese eje.

Un enfoque ingenuo sería simplemente comparar esos números de dos cuaterniones para la igualdad. Sin embargo, debido a que los cálculos de coma flotante implican un error, al menos debe usar un error, a menudo llamado eps (para epsilon) y comparar cada componente como

    double const eps = 1e-12; // some error threshold
    abs(quat1_x - quat2_x) < eps // similar enough?
    // repeat for other values..

Una mejor prueba sería calcular el producto escalar de los dos cuaterniones y probar si está cerca de 1.0. Debería buscar la ecuación de los cuaterniones con pecado y cos y simplemente puntear dos cuaterniones, entonces debería ver fácilmente por qué esto funciona.

bogglez
fuente
0

Basado en todas las sugerencias para usar Dot y eps, encontré que usando (en la unidad):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)

funcionó bien sin que tuviera que tomar una decisión sobre el tamaño de eps.

Sakull284
fuente