* limitations under the License.
*
*/
-
-#include <fusion_util.h>
+#include <errno.h>
#include <math.h>
#include <stdlib.h>
+#include "fusion_util.h"
+
+#define RAD2DEGREE (180/M_PI)
+#define QUAT (M_PI/4)
+#define HALF (M_PI/2)
+#define ARCTAN(x, y) ((x) == 0 ? 0 : (y) != 0 ? atan2((x), (y)) : (x) > 0 ? M_PI/2.0 : -M_PI/2.0)
+
+static float clamp(float v)
+{
+ return (v < 0) ? 0.0 : v;
+}
+
int quat_to_matrix(const float *quat, float *R)
{
if(quat == NULL || R == NULL)
- return -1;
+ return -EINVAL;
float q0 = quat[3];
float q1 = quat[0];
return 0;
}
+
+int matrix_to_quat(const float *R, float *quat)
+{
+ if (R == NULL || quat == NULL)
+ return -EINVAL;
+
+ const float Hx = R[0];
+ const float My = R[4];
+ const float Az = R[8];
+ quat[0] = sqrtf(clamp(Hx - My - Az + 1) * 0.25f);
+ quat[1] = sqrtf(clamp(-Hx + My - Az + 1) * 0.25f);
+ quat[2] = sqrtf(clamp(-Hx - My + Az + 1) * 0.25f);
+ quat[3] = sqrtf(clamp(Hx + My + Az + 1) * 0.25f);
+ quat[0] = copysignf(quat[0], R[7] - R[5]);
+ quat[1] = copysignf(quat[1], R[2] - R[6]);
+ quat[2] = copysignf(quat[2], R[3] - R[1]);
+
+ return 0;
+}
+
+int calculate_rotation_matrix(float *accel, float *geo, float *R, float *I)
+{
+ if (accel == NULL || geo == NULL || R == NULL || I == NULL)
+ return -EINVAL;
+
+ float Ax = accel[0];
+ float Ay = accel[1];
+ float Az = accel[2];
+ float Ex = geo[0];
+ float Ey = geo[1];
+ float Ez = geo[2];
+ float Hx = Ey*Az - Ez*Ay;
+ float Hy = Ez*Ax - Ex*Az;
+ float Hz = Ex*Ay - Ey*Ax;
+ float normH = (float)sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
+ if (normH < 0.1f)
+ return -EINVAL;
+
+ float invH = 1.0f / normH;
+ Hx *= invH;
+ Hy *= invH;
+ Hz *= invH;
+ float invA = 1.0f / (float)sqrt(Ax*Ax + Ay*Ay + Az*Az);
+ Ax *= invA;
+ Ay *= invA;
+ Az *= invA;
+ float Mx = Ay*Hz - Az*Hy;
+ float My = Az*Hx - Ax*Hz;
+ float Mz = Ax*Hy - Ay*Hx;
+
+ R[0] = Hx; R[1] = Hy; R[2] = Hz;
+ R[3] = Mx; R[4] = My; R[5] = Mz;
+ R[6] = Ax; R[7] = Ay; R[8] = Az;
+
+ float invE = 1.0 / (float)sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
+ float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
+ float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
+
+ I[0] = 1; I[1] = 0; I[2] = 0;
+ I[3] = 0; I[4] = c; I[5] = s;
+ I[6] = 0; I[7] = -s; I[8] = c;
+
+ return 0;
+}
+
+int quat_to_orientation(const float *quat, float &azimuth, float &pitch, float &roll)
+{
+ int error;
+ float g[3];
+ float R[9];
+
+ error = quat_to_matrix(quat, R);
+
+ if (error < 0)
+ return error;
+
+ float xyz_z = ARCTAN(R[3], R[0]);
+ float yxz_x = asinf(R[7]);
+ float yxz_y = ARCTAN(-R[6], R[8]);
+ float yxz_z = ARCTAN(-R[1], R[4]);
+
+ float a = fabs(yxz_x / HALF);
+ a = a * a;
+
+ float p = (fabs(yxz_y) / HALF - 1.0);
+
+ if (p < 0)
+ p = 0;
+
+ float v = 1 + (1 - a) / a * p;
+
+ if (v > 20)
+ v = 20;
+
+ if (yxz_x * yxz_y > 0) {
+ if (yxz_z > 0 && xyz_z < 0)
+ xyz_z += M_PI * 2;
+ } else {
+ if (yxz_z < 0 && xyz_z > 0)
+ xyz_z -= M_PI * 2;
+ }
+
+ g[0] = (1 - a * v) * yxz_z + (a * v) * xyz_z;
+ g[0] *= -1;
+
+ float tmp = R[7];
+
+ if (tmp > 1.0f)
+ tmp = 1.0f;
+ else if (tmp < -1.0f)
+ tmp = -1.0f;
+
+ g[1] = -asinf(tmp);
+ if (R[8] < 0)
+ g[1] = M_PI - g[1];
+
+ if (g[1] > M_PI)
+ g[1] -= M_PI * 2;
+
+ if ((fabs(R[7]) > QUAT))
+ g[2] = (float) atan2f(R[6], R[7]);
+ else
+ g[2] = (float) atan2f(R[6], R[8]);
+
+ if (g[2] > HALF)
+ g[2] = M_PI - g[2];
+ else if (g[2] < -HALF)
+ g[2] = -M_PI - g[2];
+
+ g[0] *= RAD2DEGREE;
+ g[1] *= RAD2DEGREE;
+ g[2] *= RAD2DEGREE;
+
+ if (g[0] < 0)
+ g[0] += 360;
+
+ azimuth = g[0];
+ pitch = g[1];
+ roll = g[2];
+
+ return 0;
+}
+