13 using FLOATING = FLOATING_TYPE;
14 static constexpr ::i32 DIMENSION = 4;
23 FLOATING m_coordinatea[4];
26 quaternion_type() : w(1), x(0), y(0), z(0) {}
27 quaternion_type(FLOATING _w, FLOATING _x, FLOATING _y, FLOATING _z) : w(_w), x(_x), y(_y), z(_z) {}
29 template<prototype_number FLOATING1>
30 quaternion_type(
const FLOATING1 *p) :
31 w((FLOATING)p[0]), x((FLOATING)p[1]), y((FLOATING)p[2]), z((FLOATING)p[3])
37 quaternion_type(const ::sequence_type<FLOATING, 3> &euler)
39 FLOATING cx = std::cos(euler.x * 0.5f);
40 FLOATING sx = std::sin(euler.x * 0.5f);
42 FLOATING cy = std::cos(euler.y * 0.5f);
43 FLOATING sy = std::sin(euler.y * 0.5f);
45 FLOATING cz = std::cos(euler.z * 0.5f);
46 FLOATING sz = std::sin(euler.z * 0.5f);
49 w = cx * cy * cz + sx * sy * sz;
50 x = sx * cy * cz - cx * sy * sz;
51 y = cx * sy * cz + sx * cy * sz;
52 z = cx * cy * sz - sx * sy * cz;
58 auto q = this->normalized();
59 return {q._pitch(), q._yaw(), q._roll()};
63 quaternion_type & set_euler_angles(
const sequence_type <FLOATING, 3 > eulerAngles)
66 auto c = (eulerAngles * (FLOATING)(0.5)).cos();
68 auto s = (eulerAngles * (FLOATING)(0.5)).sin();
70 this->w = c.x * c.y * c.z + s.x * s.y * s.z;
71 this->x = s.x * c.y * c.z - c.x * s.y * s.z;
72 this->y = c.x * s.y * c.z + s.x * c.y * s.z;
73 this->z = c.x * c.y * s.z - s.x * s.y * c.z;
81 constexpr FLOATING dotted(
const quaternion_type &q)
const
84 return this->w * q.w + this->x * q.x + this->y * q.y + this->z * q.z;
89 constexpr FLOATING squared_modulus()
const
92 return this->dotted(*
this);
96 FLOATING modulus()
const
99 return ::std::sqrt(this->squared_modulus());
104 quaternion_type normalized()
const
107 auto modulus = this->modulus();
109 if (modulus <= (FLOATING)0)
110 return {(FLOATING)1, (FLOATING)0, (FLOATING)0, (FLOATING)0};
112 auto inversedModulus = (FLOATING)1 / modulus;
114 return {this->w * inversedModulus, this->x * inversedModulus, this->y * inversedModulus,
115 this->z * inversedModulus};
120 quaternion_type crossed(
const quaternion_type &q2)
const
122 const auto &q1 = *
this;
124 q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
125 q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x};
128 inline quaternion_type slerp(
const quaternion_type &q2, FLOATING t)
const
130 const auto &q1 = *
this;
132 FLOATING dot = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
134 quaternion_type q2c = q2;
137 if (dot < (FLOATING)0)
147 const FLOATING EPS = 1e-6f;
148 if (dot > (FLOATING)1 - EPS)
151 quaternion_type result;
152 result.w = q1.w + t * (q2c.w - q1.w);
153 result.x = q1.x + t * (q2c.x - q1.x);
154 result.y = q1.y + t * (q2c.y - q1.y);
155 result.z = q1.z + t * (q2c.z - q1.z);
159 (FLOATING)1 / sqrtf(result.w * result.w + result.x * result.x + result.y * result.y + result.z * result.z);
169 FLOATING theta = acosf(dot);
170 FLOATING sinTheta = sinf(theta);
172 FLOATING w1 = sinf(((FLOATING)1 - t) * theta) / sinTheta;
173 FLOATING w2 = sinf(t * theta) / sinTheta;
175 quaternion_type result;
176 result.w = w1 * q1.w + w2 * q2c.w;
177 result.x = w1 * q1.x + w2 * q2c.x;
178 result.y = w1 * q1.y + w2 * q2c.y;
179 result.z = w1 * q1.z + w2 * q2c.z;
205 inline quaternion_type & normalize()
208 return *
this = this->normalized();
242 auto cosp = (pitch * (FLOATING)0.5).cos();
243 auto sinp = (pitch * (FLOATING)0.5).sin();
244 auto cosy = (yaw * (FLOATING)0.5).cos();
245 auto siny = (yaw * (FLOATING)0.5).sin();
247 this->w = cosp * cosy;
248 this->x = sinp * cosy;
249 this->y = cosp * siny;
250 this->z = - sinp * siny;
264 FLOATING half_yaw = yaw.m_fAngle * FLOATING(0.5);
265 FLOATING half_pitch = pitch.m_fAngle * FLOATING(0.5);
266 FLOATING half_roll = roll.m_fAngle * FLOATING(0.5);
269 ::f64 cr = cos(half_roll);
270 ::f64 sr = sin(half_roll);
271 ::f64 cp = cos(half_pitch);
272 ::f64 sp = sin(half_pitch);
273 ::f64 cy = cos(half_yaw);
274 ::f64 sy = sin(half_yaw);
277 q.w = cr * cp * cy + sr * sp * sy;
278 q.x = sr * cp * cy - cr * sp * sy;
279 q.y = cr * sp * cy + sr * cp * sy;
280 q.z = cr * cp * sy - sr * sp * cy;
287angle_type < FLOATING > _roll()
const
289 auto const y = (FLOATING)(2) * (this->x * this->y + this->w * this->z);
290 auto const x = this->w * this->w + this->x * this->x - this->y * this->y - this->z * this->z;
293 if (::std::abs(x) < std::numeric_limits<FLOATING>::epsilon() &&
294 ::std::abs(y) < std::numeric_limits<FLOATING>::epsilon())
295 return ::radians((FLOATING) 0);
297 return ::geometry::atan2(y, x);
301 {
return this->normalized()._roll();
316 constexpr angle_type < FLOATING > _pitch()
const
319 auto const y = (FLOATING)(2) * (this->y * this->z + this->w * this->x);
320 auto const x = this->w * this->w - this->x * this->x
321 - this->y * this->y + this->z * this->z;
323 if (::std::abs(x) < std::numeric_limits<FLOATING>::epsilon() &&
324 ::std::abs(y) < std::numeric_limits<FLOATING>::epsilon())
327 return (FLOATING)(2) * ::geometry::atan2(this->x, this->w);
329 return ::geometry::atan2(y, x);
353 return this->normalized()._pitch();
381 return ::geometry::asin(
382 (FLOATING)(-2) * (this->x * this->z - this->w * this->y));
390 return this->normalized()._yaw();
395 quaternion_type & offset_yaw_and_pitch_with_constraints(
396 const ::angle_type<FLOATING> & angleΔYaw,
397 const ::angle_type<FLOATING> & angleΔPitch,
398 const ::angle_type<FLOATING> & angleMinimumPitch,
399 const ::angle_type<FLOATING> & angleMaximumPitch
405 auto eulerAngles = this->euler_angles();
407 eulerAngles.x += angleΔPitch.m_fAngle;
409 eulerAngles.y += angleΔYaw.m_fAngle;
411 eulerAngles.x = ::geometry::clamp(eulerAngles.x, angleMinimumPitch.m_fAngle, angleMaximumPitch.m_fAngle);
413 this->set_euler_angles(eulerAngles);
420 constexpr sequence_type < FLOATING, 3 > front()
const
425 front.x = (FLOATING)2 * (this->x * this->z + this->w * this->y);
426 front.y = (FLOATING)2 * (this->y * this->z - this->w * this->x);
427 front.z = (FLOATING)1 - (FLOATING)2 * (this->x * this->x + this->y * this->y);