@@ -27,7 +27,11 @@ Quaternion::Quaternion( float* const r )
2727}
2828
2929Quaternion::Quaternion (const float xAngle, const float yAngle, const float zAngle){
30- this ->fromEulerAngles (xAngle, yAngle, zAngle);
30+ this ->fromEulerAngles (xAngle, yAngle, zAngle, RotationOrder::ZYX);
31+ }
32+
33+ Quaternion::Quaternion (const float xAngle, const float yAngle, const float zAngle, RotationOrder order){
34+ this ->fromEulerAngles (xAngle, yAngle, zAngle, order);
3135}
3236
3337Quaternion::Quaternion (const Vector3* akAxis){
@@ -163,14 +167,33 @@ void Quaternion::swap(Quaternion& other){
163167 std::swap (z, other.z );
164168}
165169
166- void Quaternion::fromEulerAngles (const float xAngle, const float yAngle, const float zAngle){
170+ void Quaternion::fromEulerAngles (const float xAngle, const float yAngle, const float zAngle, RotationOrder order ){
167171 Quaternion qx, qy, qz;
168172
169173 qx.fromAngleAxis (xAngle, Vector3 (1 ,0 ,0 ));
170174 qy.fromAngleAxis (yAngle, Vector3 (0 ,1 ,0 ));
171175 qz.fromAngleAxis (zAngle, Vector3 (0 ,0 ,1 ));
172176
173- *this = (qz * (qy * qx)); // order ZYX
177+ switch (order) {
178+ case RotationOrder::XYZ:
179+ *this = qx * (qy * qz);
180+ break ;
181+ case RotationOrder::XZY:
182+ *this = qx * (qz * qy);
183+ break ;
184+ case RotationOrder::YXZ:
185+ *this = qy * (qx * qz);
186+ break ;
187+ case RotationOrder::YZX:
188+ *this = qy * (qz * qx);
189+ break ;
190+ case RotationOrder::ZXY:
191+ *this = qz * (qx * qy);
192+ break ;
193+ case RotationOrder::ZYX:
194+ *this = qz * (qy * qx);
195+ break ;
196+ }
174197}
175198
176199void Quaternion::fromAxes (const Vector3* akAxis){
@@ -312,11 +335,127 @@ void Quaternion::fromAngleAxis (const float angle, const Vector3& rkAxis){
312335 z = fSin *rkAxis.z ;
313336}
314337
315- Vector3 Quaternion::getEulerAngles () const {
316- Quaternion q = *this ;
317- q.normalize ();
338+ Vector3 Quaternion::getEulerAngles (RotationOrder order) const {
339+ Vector3 eulerAngles;
340+
341+ switch (order) {
342+ case RotationOrder::XYZ: {
343+ // Roll (X-axis rotation)
344+ float sinr_cosp = 2 * (w * x + y * z);
345+ float cosr_cosp = 1 - 2 * (x * x + y * y);
346+ eulerAngles.x = atan2 (sinr_cosp, cosr_cosp);
347+
348+ // Pitch (Y-axis rotation)
349+ float sinp = 2 * (w * y - z * x);
350+ if (fabs (sinp) >= 1 ) // Handle gimbal lock
351+ eulerAngles.y = copysign (M_PI / 2 , sinp);
352+ else
353+ eulerAngles.y = asin (sinp);
354+
355+ // Yaw (Z-axis rotation)
356+ float siny_cosp = 2 * (w * z + x * y);
357+ float cosy_cosp = 1 - 2 * (y * y + z * z);
358+ eulerAngles.z = atan2 (siny_cosp, cosy_cosp);
359+ break ;
360+ }
361+ case RotationOrder::XZY: {
362+ // Roll (X-axis rotation)
363+ float sinr_cosp = 2 * (w * x + y * z);
364+ float cosr_cosp = 1 - 2 * (x * x + z * z);
365+ eulerAngles.x = atan2 (sinr_cosp, cosr_cosp);
366+
367+ // Yaw (Z-axis rotation)
368+ float siny = 2 * (w * z - x * y);
369+ if (fabs (siny) >= 1 ) // Handle gimbal lock
370+ eulerAngles.z = copysign (M_PI / 2 , siny);
371+ else
372+ eulerAngles.z = asin (siny);
373+
374+ // Pitch (Y-axis rotation)
375+ float sinp_cosp = 2 * (w * y + z * x);
376+ float cosp_cosp = 1 - 2 * (y * y + z * z);
377+ eulerAngles.y = atan2 (sinp_cosp, cosp_cosp);
378+ break ;
379+ }
380+ case RotationOrder::YXZ: {
381+ // Yaw (Y-axis rotation)
382+ float siny_cosp = 2 * (w * y + x * z);
383+ float cosy_cosp = 1 - 2 * (y * y + z * z);
384+ eulerAngles.y = atan2 (siny_cosp, cosy_cosp);
385+
386+ // Roll (X-axis rotation)
387+ float sinr = 2 * (w * x - y * z);
388+ if (fabs (sinr) >= 1 ) // Handle gimbal lock
389+ eulerAngles.x = copysign (M_PI / 2 , sinr);
390+ else
391+ eulerAngles.x = asin (sinr);
392+
393+ // Pitch (Z-axis rotation)
394+ float sinp_cosp = 2 * (w * z + x * y);
395+ float cosp_cosp = 1 - 2 * (z * z + x * x);
396+ eulerAngles.z = atan2 (sinp_cosp, cosp_cosp);
397+ break ;
398+ }
399+ case RotationOrder::YZX: {
400+ // Pitch (Z-axis rotation)
401+ float sinp = 2 * (w * z - x * y);
402+ if (fabs (sinp) >= 1 ) // Handle gimbal lock
403+ eulerAngles.z = copysign (M_PI / 2 , sinp);
404+ else
405+ eulerAngles.z = asin (sinp);
406+
407+ // Yaw (Y-axis rotation)
408+ float siny_cosp = 2 * (w * y + z * x);
409+ float cosy_cosp = 1 - 2 * (y * y + z * z);
410+ eulerAngles.y = atan2 (siny_cosp, cosy_cosp);
411+
412+ // Roll (X-axis rotation)
413+ float sinr_cosp = 2 * (w * x + y * z);
414+ float cosr_cosp = 1 - 2 * (x * x + z * z);
415+ eulerAngles.x = atan2 (sinr_cosp, cosr_cosp);
416+ break ;
417+ }
418+ case RotationOrder::ZXY: {
419+ // Roll (X-axis rotation)
420+ float sinr = 2 * (w * x - y * z);
421+ if (fabs (sinr) >= 1 ) // Handle gimbal lock
422+ eulerAngles.x = copysign (M_PI / 2 , sinr);
423+ else
424+ eulerAngles.x = asin (sinr);
425+
426+ // Pitch (Y-axis rotation)
427+ float sinp_cosp = 2 * (w * y + z * x);
428+ float cosp_cosp = 1 - 2 * (y * y + x * x);
429+ eulerAngles.y = atan2 (sinp_cosp, cosp_cosp);
430+
431+ // Yaw (Z-axis rotation)
432+ float siny_cosp = 2 * (w * z + x * y);
433+ float cosy_cosp = 1 - 2 * (z * z + y * y);
434+ eulerAngles.z = atan2 (siny_cosp, cosy_cosp);
435+ break ;
436+ }
437+ case RotationOrder::ZYX: {
438+ // Yaw (Z-axis rotation)
439+ float siny_cosp = 2 * (w * z + x * y);
440+ float cosy_cosp = 1 - 2 * (y * y + z * z);
441+ eulerAngles.z = atan2 (siny_cosp, cosy_cosp);
442+
443+ // Pitch (Y-axis rotation)
444+ float sinp = 2 * (w * y - z * x);
445+ if (fabs (sinp) >= 1 ) // Handle gimbal lock
446+ eulerAngles.y = copysign (M_PI / 2 , sinp);
447+ else
448+ eulerAngles.y = asin (sinp);
449+
450+ // Roll (X-axis rotation)
451+ float sinr_cosp = 2 * (w * x + y * z);
452+ float cosr_cosp = 1 - 2 * (x * x + y * y);
453+ eulerAngles.x = atan2 (sinr_cosp, cosr_cosp);
454+ break ;
455+ }
456+ }
318457
319- return Vector3 (q. getPitch ( ), q. getYaw ( ), q. getRoll ( ));
458+ return Vector3 (Angle::radToDefault (eulerAngles. x ), Angle::radToDefault (eulerAngles. y ), Angle::radToDefault (eulerAngles. z ));
320459}
321460
322461Vector3 Quaternion::xAxis (void ) const {
0 commit comments