1 /** 2 Quaternion. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.core.quat; 14 15 import godot.core.defs; 16 import godot.core.vector3; 17 import godot.core.basis; 18 19 import std.math; 20 21 /** 22 A 4-dimensional vector representing a rotation. 23 24 The vector represents a 4 dimensional complex number where multiplication of the basis elements is not commutative (multiplying i with j gives a different result than multiplying j with i). 25 26 Multiplying quaternions reproduces rotation sequences. However quaternions need to be often renormalized, or else they suffer from precision issues. 27 28 It can be used to perform SLERP (spherical-linear interpolation) between two rotations. 29 */ 30 struct Quat 31 { 32 @nogc nothrow: 33 34 real_t x = 0; 35 real_t y = 0; 36 real_t z = 0; 37 real_t w = 1; 38 39 void set(real_t p_x, real_t p_y, real_t p_z, real_t p_w) 40 { 41 x=p_x; y=p_y; z=p_z; w=p_w; 42 } 43 44 this(real_t p_x, real_t p_y, real_t p_z, real_t p_w) 45 { 46 x=p_x; y=p_y; z=p_z; w=p_w; 47 } 48 49 50 real_t length() const 51 { 52 return sqrt(lengthSquared()); 53 } 54 55 void normalize() 56 { 57 this /= length(); 58 } 59 60 Quat normalized() const 61 { 62 return this / length(); 63 } 64 65 Quat inverse() const 66 { 67 return Quat( -x, -y, -z, w ); 68 } 69 70 void setEuler(in Vector3 p_euler) 71 { 72 real_t half_a1 = p_euler.x * 0.5; 73 real_t half_a2 = p_euler.y * 0.5; 74 real_t half_a3 = p_euler.z * 0.5; 75 76 // R = X(a1).Y(a2).Z(a3) convention for Euler angles. 77 // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-2) 78 // a3 is the angle of the first rotation, following the notation in this reference. 79 80 real_t cos_a1 = cos(half_a1); 81 real_t sin_a1 = sin(half_a1); 82 real_t cos_a2 = cos(half_a2); 83 real_t sin_a2 = sin(half_a2); 84 real_t cos_a3 = cos(half_a3); 85 real_t sin_a3 = sin(half_a3); 86 87 set(sin_a1*cos_a2*cos_a3 + sin_a2*sin_a3*cos_a1, 88 -sin_a1*sin_a3*cos_a2 + sin_a2*cos_a1*cos_a3, 89 sin_a1*sin_a2*cos_a3 + sin_a3*cos_a1*cos_a2, 90 -sin_a1*sin_a2*sin_a3 + cos_a1*cos_a2*cos_a3); 91 } 92 93 Quat slerp(in Quat q, in real_t t) const 94 { 95 Quat to1; 96 real_t omega, cosom, sinom, scale0, scale1; 97 // calc cosine 98 cosom = dot(q); 99 100 // adjust signs (if necessary) 101 if( cosom <0.0 ) 102 { 103 cosom = -cosom; 104 to1.x = - q.x; 105 to1.y = - q.y; 106 to1.z = - q.z; 107 to1.w = - q.w; 108 } 109 else 110 { 111 to1.x = q.x; 112 to1.y = q.y; 113 to1.z = q.z; 114 to1.w = q.w; 115 } 116 // calculate coefficients 117 if ( (1.0 - cosom) > CMP_EPSILON ) 118 { 119 // standard case (slerp) 120 omega = acos(cosom); 121 sinom = sin(omega); 122 scale0 = sin((1.0 - t) * omega) / sinom; 123 scale1 = sin(t * omega) / sinom; 124 } 125 else 126 { 127 // "from" and "to" quaternions are very close 128 // ... so we can do a linear interpolation 129 scale0 = 1.0 - t; 130 scale1 = t; 131 } 132 // calculate final values 133 return Quat( 134 scale0 * x + scale1 * to1.x, 135 scale0 * y + scale1 * to1.y, 136 scale0 * z + scale1 * to1.z, 137 scale0 * w + scale1 * to1.w 138 ); 139 } 140 141 Quat slerpni(in Quat q, in real_t t) const 142 { 143 Quat from = this; 144 145 real_t dot = from.dot(q); 146 147 if (fabs(dot) > 0.9999) return from; 148 149 real_t theta = acos(dot), 150 sinT = 1.0 / sin(theta), 151 newFactor = sin(t * theta) * sinT, 152 invFactor = sin((1.0 - t) * theta) * sinT; 153 154 return Quat(invFactor * from.x + newFactor * q.x, 155 invFactor * from.y + newFactor * q.y, 156 invFactor * from.z + newFactor * q.z, 157 invFactor * from.w + newFactor * q.w); 158 } 159 160 Quat cubicSlerp(in Quat q, in Quat prep, in Quat postq, in real_t t) const 161 { 162 //the only way to do slerp :| 163 real_t t2 = (1.0-t)*t*2; 164 Quat sp = this.slerp(q,t); 165 Quat sq = prep.slerpni(postq,t); 166 return sp.slerpni(sq,t2); 167 } 168 169 void getAxisAndAngle(out Vector3 r_axis, out real_t r_angle) const 170 { 171 r_angle = 2 * acos(w); 172 r_axis.x = x / sqrt(1-w*w); 173 r_axis.y = y / sqrt(1-w*w); 174 r_axis.z = z / sqrt(1-w*w); 175 } 176 177 178 179 Quat opBinary(string op : "*")(in Vector3 v) const 180 { 181 return Quat( w * v.x + y * v.z - z * v.y, 182 w * v.y + z * v.x - x * v.z, 183 w * v.z + x * v.y - y * v.x, 184 -x * v.x - y * v.y - z * v.z); 185 } 186 187 Vector3 xform(in Vector3 v) const 188 { 189 Quat q = this * v; 190 q *= this.inverse(); 191 return Vector3(q.x,q.y,q.z); 192 } 193 194 this(in Vector3 axis, in real_t angle) 195 { 196 real_t d = axis.length(); 197 if (d==0) 198 set(0,0,0,0); 199 else 200 { 201 real_t sin_angle = sin(angle * 0.5); 202 real_t cos_angle = cos(angle * 0.5); 203 real_t s = sin_angle / d; 204 set(axis.x * s, axis.y * s, axis.z * s, 205 cos_angle); 206 } 207 } 208 209 this(in Vector3 v0, in Vector3 v1) // shortest arc 210 { 211 Vector3 c = v0.cross(v1); 212 real_t d = v0.dot(v1); 213 214 if (d < -1.0 + CMP_EPSILON) 215 { 216 x=0; 217 y=1; 218 z=0; 219 w=0; 220 } 221 else 222 { 223 real_t s = sqrt((1.0 + d) * 2.0); 224 real_t rs = 1.0 / s; 225 226 x=c.x*rs; 227 y=c.y*rs; 228 z=c.z*rs; 229 w=s * 0.5; 230 } 231 } 232 233 234 real_t dot(in Quat q) const 235 { 236 return x * q.x+y * q.y+z * q.z+w * q.w; 237 } 238 239 real_t lengthSquared() const 240 { 241 return dot(this); 242 } 243 244 void opOpAssign(string op : "+")(in Quat q) 245 { 246 x += q.x; y += q.y; z += q.z; w += q.w; 247 } 248 249 void opOpAssign(string op : "-")(in Quat q) 250 { 251 x -= q.x; y -= q.y; z -= q.z; w -= q.w; 252 } 253 254 void opOpAssign(string op : "*")(in Quat q) 255 { 256 x *= q.x; y *= q.y; z *= q.z; w *= q.w; 257 } 258 259 260 void opOpAssign(string op : "*")(in real_t s) 261 { 262 x *= s; y *= s; z *= s; w *= s; 263 } 264 265 266 void opOpAssign(string op : "/")(in real_t s) 267 { 268 this *= 1.0 / s; 269 } 270 271 Quat opBinary(string op : "+")(in Quat q2) const 272 { 273 Quat q1 = this; 274 return Quat( q1.x+q2.x, q1.y+q2.y, q1.z+q2.z, q1.w+q2.w ); 275 } 276 277 Quat opBinary(string op : "-")(in Quat q2) const 278 { 279 Quat q1 = this; 280 return Quat( q1.x-q2.x, q1.y-q2.y, q1.z-q2.z, q1.w-q2.w); 281 } 282 283 Quat opBinary(string op : "*")(in Quat q2) const 284 { 285 Quat q1 = this; 286 q1 *= q2; 287 return q1; 288 } 289 290 291 Quat opUnary(string op : "-")() const 292 { 293 return Quat(-x, -y, -z, -w); 294 } 295 296 Quat opBinary(string op : "*")(in real_t s) const 297 { 298 return Quat(x * s, y * s, z * s, w * s); 299 } 300 301 Quat opBinary(string op : "/")(in real_t s) const 302 { 303 return this * (1.0 / s); 304 } 305 306 307 308 Vector3 getEuler() const 309 { 310 Basis m = Basis(this); 311 return m.getEuler(); 312 } 313 } 314