Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
Quaternion.cpp
1/*
2Copyright (C) 2017-2019,2025 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
19#include "aeongames/Vector3.hpp"
20#include <cassert>
21#include <cmath>
22#include <cstring>
23
24namespace AeonGames
25{
27 = default;
28 Quaternion::Quaternion ( float w, float x, float y, float z ) :
29 mQuaternion{w, x, y, z}
30 {
31 }
32
33 Quaternion::Quaternion ( const float* aData ) :
34 mQuaternion{aData[0], aData[1], aData[2], aData[3]}
35 {
36 }
37
39 = default;
41 {
42 // Products
43 float p1 = mQuaternion[0] * mQuaternion[1];
44 float p2 = mQuaternion[0] * mQuaternion[2];
45 float p3 = mQuaternion[0] * mQuaternion[3];
46
47 float p4 = mQuaternion[1] * mQuaternion[1];
48 float p5 = mQuaternion[1] * mQuaternion[2];
49 float p6 = mQuaternion[1] * mQuaternion[3];
50
51 float p7 = mQuaternion[2] * mQuaternion[2];
52 float p8 = mQuaternion[2] * mQuaternion[3];
53
54 float p9 = mQuaternion[3] * mQuaternion[3];
55
56 return Matrix4x4
57 {
58 // First row
59 1.0f - 2.0f * ( p7 + p9 ),
60 2.0f * ( p5 + p3 ),
61 2.0f * ( p6 - p2 ),
62 0.0f,
63 // Second row
64 2.0f * ( p5 - p3 ),
65 1.0f - 2.0f * ( p4 + p9 ),
66 2.0f * ( p8 + p1 ),
67 0.0f,
68 // Third row
69 2.0f * ( p6 + p2 ),
70 2.0f * ( p8 - p1 ),
71 1.0f - 2.0f * ( p4 + p7 ),
72 0.0f,
73 // Fourth row
74 0, 0, 0, 1};
75 }
76
78 {
79 // Products
80 float p1 = mQuaternion[0] * mQuaternion[1];
81 float p2 = mQuaternion[0] * mQuaternion[2];
82 float p3 = mQuaternion[0] * mQuaternion[3];
83
84 float p4 = mQuaternion[1] * mQuaternion[1];
85 float p5 = mQuaternion[1] * mQuaternion[2];
86 float p6 = mQuaternion[1] * mQuaternion[3];
87
88 float p7 = mQuaternion[2] * mQuaternion[2];
89 float p8 = mQuaternion[2] * mQuaternion[3];
90
91 float p9 = mQuaternion[3] * mQuaternion[3];
92
93 return Matrix3x3
94 {
95 // First row
96 1.0f - 2.0f * ( p7 + p9 ),
97 2.0f * ( p5 + p3 ),
98 2.0f * ( p6 - p2 ),
99 // Second row
100 2.0f * ( p5 - p3 ),
101 1.0f - 2.0f * ( p4 + p9 ),
102 2.0f * ( p8 + p1 ),
103 // Third row
104 2.0f * ( p6 + p2 ),
105 2.0f * ( p8 - p1 ),
106 1.0f - 2.0f * ( p4 + p7 ),
107 };
108 }
109
110 Quaternion& Quaternion::operator= ( const float* aLhs )
111 {
112 memcpy ( mQuaternion, aLhs, sizeof ( float ) * 4 );
113 return *this;
114 }
115
117 {
118 float local[4] { mQuaternion[0], mQuaternion[1], mQuaternion[2], mQuaternion[3] };
119 mQuaternion[0] = ( local[0] * lhs.mQuaternion[0] - local[1] * lhs.mQuaternion[1] - local[2] * lhs.mQuaternion[2] - local[3] * lhs.mQuaternion[3] );
120 mQuaternion[1] = ( local[0] * lhs.mQuaternion[1] + local[1] * lhs.mQuaternion[0] + local[2] * lhs.mQuaternion[3] - local[3] * lhs.mQuaternion[2] );
121 mQuaternion[2] = ( local[0] * lhs.mQuaternion[2] - local[1] * lhs.mQuaternion[3] + local[2] * lhs.mQuaternion[0] + local[3] * lhs.mQuaternion[1] );
122 mQuaternion[3] = ( local[0] * lhs.mQuaternion[3] + local[1] * lhs.mQuaternion[2] - local[2] * lhs.mQuaternion[1] + local[3] * lhs.mQuaternion[0] );
123 return *this;
124 }
125
126 const Quaternion operator* ( const Quaternion& lhs, const Quaternion& rhs )
127 {
128 return Quaternion ( lhs ) *= rhs;
129 }
130
131 const Vector3 operator* ( const Quaternion & lhs, const Vector3 & rhs )
132 {
133
134 float t1 = ( -lhs[1] * rhs[0] - lhs[2] * rhs[1] - lhs[3] * rhs[2] );
135 float t2 = ( lhs[0] * rhs[0] + lhs[2] * rhs[2] - lhs[3] * rhs[1] );
136 float t3 = ( lhs[0] * rhs[1] + lhs[3] * rhs[0] - lhs[1] * rhs[2] );
137 float t4 = ( lhs[0] * rhs[2] + lhs[1] * rhs[1] - lhs[2] * rhs[0] );
138 return Vector3
139 {
140 t1 * -lhs[1] + t2 * lhs[0] + t3 * -lhs[3] - t4 * -lhs[2],
141 t1 * -lhs[2] + t3 * lhs[0] + t4 * -lhs[1] - t2 * -lhs[3],
142 t1 * -lhs[3] + t4 * lhs[0] + t2 * -lhs[2] - t3 * -lhs[1]
143 };
144 }
145
146 bool operator== ( const Quaternion & lhs, const Quaternion & rhs )
147 {
148 return
149 lhs[0] == rhs[0] &&
150 lhs[1] == rhs[1] &&
151 lhs[2] == rhs[2] &&
152 lhs[3] == rhs[3];
153 }
154
155 const Quaternion LerpQuats ( const Quaternion & q1, const Quaternion & q2, double interpolation )
156 {
157 if ( interpolation <= 0.0f )
158 {
159 return Quaternion ( q1 );
160 }
161 else if ( interpolation >= 1.0f )
162 {
163 return Quaternion ( q2 );
164 }
165 return Quaternion
166 {
167 static_cast<float> ( ( q1[0] * ( 1.0 - interpolation ) ) + ( q2[0] * interpolation ) ),
168 static_cast<float> ( ( q1[1] * ( 1.0 - interpolation ) ) + ( q2[1] * interpolation ) ),
169 static_cast<float> ( ( q1[2] * ( 1.0 - interpolation ) ) + ( q2[2] * interpolation ) ),
170 static_cast<float> ( ( q1[3] * ( 1.0 - interpolation ) ) + ( q2[3] * interpolation ) )
171 };
172 }
173
174 const Quaternion NlerpQuats ( const Quaternion & q1, const Quaternion & q2, double interpolation )
175 {
176 return Quaternion ( LerpQuats ( q1, q2, interpolation ) ).Normalize();
177 }
178
179 const Quaternion SlerpQuats ( const Quaternion & q1, const Quaternion & q2, float interpolation )
180 {
181 {
182 if ( interpolation <= 0.0f )
183 {
184 return Quaternion ( q1 );
185 }
186 else if ( interpolation >= 1.0f )
187 {
188 return Quaternion ( q2 );
189 }
190 float dot = ( q1[0] * q2[0] ) + ( q1[1] * q2[1] ) + ( q1[2] * q2[2] ) + ( q1[3] * q2[3] );
191 float sign = 1.0f;
192 if ( std::fabs ( dot ) > 0.9999f )
193 {
194 return Quaternion ( q1 );
195 }
196 else if ( dot < 0.0f )
197 {
198 dot = -dot;
199 sign = -1.0;
200 }
201 float theta = acosf ( dot );
202 float sinT = 1.0f / sinf ( theta );
203 float newFactor = sinf ( interpolation * theta ) * sinT;
204 float invFactor = sinf ( ( 1.0f - interpolation ) * theta ) * sinT;
205
206 return Quaternion
207 {
208 invFactor * q1[0] + newFactor * q2[0] * sign,
209 invFactor * q1[1] + newFactor * q2[1] * sign,
210 invFactor * q1[2] + newFactor * q2[2] * sign,
211 invFactor * q1[3] + newFactor * q2[3] * sign
212 };
213 }
214 }
215
216 float Quaternion::operator [] ( const size_t aIndex ) const
217 {
218 assert ( aIndex < 4 );
219 return mQuaternion[aIndex];
220 }
221
222 float& Quaternion::operator [] ( const size_t aIndex )
223 {
224 assert ( aIndex < 4 );
225 return mQuaternion[aIndex];
226 }
227
228 const Quaternion Quaternion::GetFromAxisAngle ( float angle, float x, float y, float z )
229 {
230 float radians = ( angle / 180.0f ) * static_cast<float> ( M_PI );
231 float result = sinf ( radians / 2.0f );
232 return Quaternion
233 {
234 cosf ( radians / 2.0f ),
235 x * result,
236 y * result,
237 z * result
238 } .Normalize();
239 }
240
242 {
243 return Quaternion{} .SetEuler ( aEuler );
244 }
245
247 {
248 float length = sqrtf (
249 ( mQuaternion[0] * mQuaternion[0] ) +
250 ( mQuaternion[1] * mQuaternion[1] ) +
251 ( mQuaternion[2] * mQuaternion[2] ) +
252 ( mQuaternion[3] * mQuaternion[3] ) );
253 // do nothing if length = 0
254 if ( length )
255 {
256 float oneoverlength = 1.0f / length;
257 mQuaternion[0] *= oneoverlength;
258 mQuaternion[1] *= oneoverlength;
259 mQuaternion[2] *= oneoverlength;
260 mQuaternion[3] *= oneoverlength;
261 }
262 return *this;
263 }
264
265 void Quaternion::Get ( float* aData ) const
266 {
267 memcpy ( aData, mQuaternion, sizeof ( float ) * 4 );
268 }
269
271 {
272 double sqw = mQuaternion[0] * mQuaternion[0];
273 double sqx = mQuaternion[1] * mQuaternion[1];
274 double sqy = mQuaternion[2] * mQuaternion[2];
275 double sqz = mQuaternion[3] * mQuaternion[3];
276 double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
277 double test = mQuaternion[1] * mQuaternion[2] + mQuaternion[3] * mQuaternion[0];
278 if ( test > 0.499 * unit )
279 {
280 // singularity at north pole
281 return Vector3 (
282 0.0f,
283 static_cast<float> ( ( 2.0 * std::atan2 ( mQuaternion[1], mQuaternion[0] ) ) * ( 180.0 / M_PI ) ),
284 static_cast<float> ( ( M_PI / 2 ) * ( 180 / M_PI ) ) );
285 }
286 if ( test < -0.499 * unit )
287 {
288 // singularity at south pole
289 return Vector3 (
290 0.0f,
291 static_cast<float> ( ( -2 * std::atan2 ( mQuaternion[1], mQuaternion[0] ) ) * ( 180 / M_PI ) ),
292 static_cast<float> ( ( -M_PI / 2 ) * ( 180 / M_PI ) ) );
293 }
294 return Vector3 (
295 static_cast<float> ( std::atan2 ( 2 * mQuaternion[1] * mQuaternion[0] - 2 * mQuaternion[2] * mQuaternion[3], -sqx + sqy - sqz + sqw ) * ( 180 / M_PI ) ),
296 static_cast<float> ( std::atan2 ( 2 * mQuaternion[2] * mQuaternion[0] - 2 * mQuaternion[1] * mQuaternion[3], sqx - sqy - sqz + sqw ) * ( 180 / M_PI ) ),
297 static_cast<float> ( std::asin ( 2 * test / unit ) * ( 180 / M_PI ) ) );
298 }
299
301 {
302 // Euler must be given in Degrees
303 double rad_pitch_over_2 = ( ( M_PI / 180 ) * aEuler[0] ) / 2;
304 double rad_roll_over_2 = ( ( M_PI / 180 ) * aEuler[1] ) / 2;
305 double rad_yaw_over_2 = ( ( M_PI / 180 ) * aEuler[2] ) / 2;
306 double c3 = std::cos ( rad_pitch_over_2 );
307 double s3 = std::sin ( rad_pitch_over_2 );
308 double c1 = std::cos ( rad_roll_over_2 );
309 double s1 = std::sin ( rad_roll_over_2 );
310 double c2 = std::cos ( rad_yaw_over_2 );
311 double s2 = std::sin ( rad_yaw_over_2 );
312 double c1c2 = c1 * c2;
313 double s1s2 = s1 * s2;
314 mQuaternion[0] = static_cast<float> ( c1c2 * c3 - s1s2 * s3 );
315 mQuaternion[1] = static_cast<float> ( c1c2 * s3 + s1s2 * c3 );
316 mQuaternion[2] = static_cast<float> ( s1 * c2 * c3 + c1 * s2 * s3 );
317 mQuaternion[3] = static_cast<float> ( c1 * s2 * c3 - s1 * c2 * s3 );
318 Normalize();
319 return *this;
320 }
321}
Header for 3x3 matrix class.
Header for 4x4 matrix class.
Header for the quaternion class.
Header for the 3D vector class.
3 by 3 matrix in colum mayor order.
Definition Matrix3x3.hpp:33
4 by 4 matrix in colum mayor order.
Definition Matrix4x4.hpp:35
Quaternion class.
DLL Quaternion & operator=(const float *aLhs)
Assign from a raw float array.
DLL Vector3 GetEuler() const
Get the Euler angle representation of this quaternion.
DLL ~Quaternion()
destructor.
static DLL const Quaternion GetFromEuler(const Vector3 &aEuler)
Create a quaternion from Euler angles.
DLL Quaternion & operator*=(const Quaternion &lhs)
Multiply this quaternion by another quaternion.
static DLL const Quaternion GetFromAxisAngle(float angle, float x, float y, float z)
Create a quaternion from an axis-angle representation.
DLL Matrix4x4 GetMatrix4x4() const
Convert the quaternion to a 4x4 rotation matrix.
DLL Matrix3x3 GetMatrix3x3() const
Convert the quaternion to a 3x3 rotation matrix.
DLL Quaternion & SetEuler(const Vector3 &aEuler)
Set the quaternion from Euler angles.
DLL Quaternion & Normalize()
Normalize this quaternion in place.
DLL void Get(float *aData) const
Copy the quaternion components to a float array.
DLL Quaternion()
Default constructor.
DLL float operator[](const size_t aIndex) const
Access a quaternion component by index (const).
3D vector class.
Definition Vector3.hpp:32
<- This is here just for the literals
Definition AABB.hpp:31
DLL const Matrix3x3 operator*(const Matrix3x3 &lhs, const Matrix3x3 &rhs)
Multiplies two 3x3 matrices. Multiplies two 3x3 matrices.
DLL const Quaternion NlerpQuats(const Quaternion &q1, const Quaternion &q2, double interpolation)
Linearly interpolate between two quaternions return the normalized result.
DLL const Quaternion LerpQuats(const Quaternion &q1, const Quaternion &q2, double interpolation)
Linearly interpolate between two quaternions.
DLL const Quaternion SlerpQuats(const Quaternion &q1, const Quaternion &q2, float interpolation)
Spherical Linear interpolation between two quaternions.
DLL const bool operator==(const Matrix3x3 &lhs, const Matrix3x3 &rhs)
Compare two 3x3 matrices for equality.