-
Notifications
You must be signed in to change notification settings - Fork 1
/
Quaternion.cpp
executable file
·190 lines (169 loc) · 4.99 KB
/
Quaternion.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "Quaternion.hpp"
Quaternion::Quaternion(const float euler_angle[3])
{
float cosPhi_2 = cosf(euler_angle[0] / 2.0f);
float sinPhi_2 = sinf(euler_angle[0] / 2.0f);
float cosTheta_2 = cosf(euler_angle[1] / 2.0f);
float sinTheta_2 = sinf(euler_angle[1] / 2.0f);
float cosPsi_2 = cosf(euler_angle[2] / 2.0f);
float sinPsi_2 = sinf(euler_angle[2] / 2.0f);
this->w =
(cosPhi_2 * cosTheta_2 * cosPsi_2 + sinPhi_2 * sinTheta_2 * sinPsi_2);
this->x =
(sinPhi_2 * cosTheta_2 * cosPsi_2 - cosPhi_2 * sinTheta_2 * sinPsi_2);
this->y =
(cosPhi_2 * sinTheta_2 * cosPsi_2 + sinPhi_2 * cosTheta_2 * sinPsi_2);
this->z =
(cosPhi_2 * cosTheta_2 * sinPsi_2 - sinPhi_2 * sinTheta_2 * cosPsi_2);
}
Quaternion::Quaternion(const float rotation_matrix[3][3])
{
float tr =
rotation_matrix[0][0] + rotation_matrix[1][1] + rotation_matrix[2][2];
float q[4];
if (tr > 0.0f)
{
float s = sqrtf(tr + 1.0f);
q[0] = s * 0.5f;
s = 0.5f / s;
q[1] = (rotation_matrix[2][1] - rotation_matrix[1][2]) * s;
q[2] = (rotation_matrix[0][2] - rotation_matrix[2][0]) * s;
q[3] = (rotation_matrix[1][0] - rotation_matrix[0][1]) * s;
}
else
{
/* Find maximum diagonal element in dcm
* store index in dcm_i */
int dcm_i = 0;
uint8_t i;
for (i = 1; i < 3; i++)
{
if (rotation_matrix[i][i] > rotation_matrix[dcm_i][dcm_i])
{
dcm_i = i;
}
}
int dcm_j = (dcm_i + 1) % 3;
int dcm_k = (dcm_i + 2) % 3;
float s = sqrtf((rotation_matrix[dcm_i][dcm_i] -
rotation_matrix[dcm_j][dcm_j] -
rotation_matrix[dcm_k][dcm_k]) +
1.0f);
q[dcm_i + 1] = s * 0.5f;
s = 0.5f / s;
q[dcm_j + 1] =
(rotation_matrix[dcm_i][dcm_j] + rotation_matrix[dcm_j][dcm_i]) * s;
q[dcm_k + 1] =
(rotation_matrix[dcm_k][dcm_i] + rotation_matrix[dcm_i][dcm_k]) * s;
q[0] =
(rotation_matrix[dcm_k][dcm_j] - rotation_matrix[dcm_j][dcm_k]) * s;
}
this->w = q[0];
this->x = q[1];
this->y = q[2];
this->z = q[3];
this->normalize();
}
Quaternion::Quaternion(const float w[3], const float dt)
{
float norm_w = sqrtf(w[0] * w[0] + w[1] * w[1] + w[2] * w[2]);
float theta = norm_w * dt;
if (theta > 0.03f)
{
this->w = cosf(theta / 2);
this->x = (w[0] / norm_w) * sinf(theta / 2);
this->y = (w[1] / norm_w) * sinf(theta / 2);
this->z = (w[2] / norm_w) * sinf(theta / 2);
}
else
{
this->w = cosf(theta / 2);
this->x = w[0] * (dt / 2);
this->y = w[1] * (dt / 2);
this->z = w[2] * (dt / 2);
}
}
float Quaternion::norm()
{
return sqrtf(this->w * this->w + this->x * this->x + this->y * this->y +
this->z * this->z);
}
void Quaternion::normalize(void)
{
float norm = this->norm();
if (norm > 0.000001f)
{
this->w /= norm;
this->x /= norm;
this->y /= norm;
this->z /= norm;
}
// TODO:
// ANCHOR need to change norm to be invNorm
}
float Quaternion::invNorm(void)
{
float num = this->w * this->w + this->x * this->x + this->y * this->y +
this->z * this->z;
float halfnum = 0.5f * num;
float temp = num;
long i = *(long *)&temp;
i = 0x5f3759df - (i >> 1);
temp = *(float *)&i;
temp = temp * (1.5f - (halfnum * temp * temp));
return temp;
}
void Quaternion::set(float w, float x, float y, float z)
{
this->w = w;
this->x = x;
this->y = y;
this->z = z;
}
void Quaternion::toEulerAngle( float *roll, float *pitch,
float *yaw) const
{
// roll (x-axis rotation)
float sinr_cosp = +2.0f * (w * x + y * z);
float cosr_cosp = +1.0f - 2.0f * (x * x + y * y);
*roll = atan2(sinr_cosp, cosr_cosp);
// pitch (y-axis rotation)
float sinp = +2.0f * (w * y - z * x);
if (fabs(sinp) >= 1)
*pitch = copysign(M_PI / 2.0f, sinp); // use 90 degrees if out of range
else
*pitch = asin(sinp);
// yaw (z-axis rotation)
float siny_cosp = +2.0f * (w * z + x * y);
float cosy_cosp = +1.0f - 2.0f * (y * y + z * z);
*yaw = atan2(siny_cosp, cosy_cosp);
}
Quaternion operator+(const Quaternion &lhs, const Quaternion &rhs)
{
Quaternion sum = lhs;
sum += rhs;
return sum;
}
Quaternion operator*(const Quaternion &lhs, const Quaternion &rhs)
{
Quaternion mult = lhs;
mult *= rhs;
return mult;
}
Quaternion operator*(const Quaternion &lhs, const float scalar)
{
Quaternion result = lhs;
result *= scalar;
return result;
}
Quaternion operator/(const Quaternion &lhs, const float scalar)
{
Quaternion result = lhs;
result /= scalar;
return result;
}
Quaternion operator*(const float scalar, const Quaternion &rhs)
{
Quaternion result = rhs;
return result *= scalar;
}