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