1 /**
2 *   Copyright: © 2012-2014 Anton Gushcha
3 *   License: Subject to the terms of the MIT license, as written in the included LICENSE file.
4 *   Authors:  NCrashed <ncrashed@gmail.com>,
5 *             LeMarwin <lemarwin42@gmail.com>
6 */
7 ///Description of <b> Vectors </b> and <b> Quaternions </b>
8 ///<br/> Vectors - just good old 3-d vectors
9 ///<br/> Quaternions are used to describe rotations in 3D space.
10 ///<br/> How to use:
11 ///<br/> 1.Create a Vector
12 ///<br/> 2.Create a Quaternion
13 ///<br/> 3.Call Vector's rotate method with a Quaternion as a parameter (not the only option. see "rotate")
14 ///<br/> 4.?????
15 ///<br/> 5.PROFIT!
16 module devol.quaternion;
17 
18 public
19 {
20 	import std.math;
21 }
22 
23 ///Describes a dot, or a direction in 3D space
24 class Vector
25 {
26 private:
27 
28 ///Coordinates of Vector
29 	double vx,vy,vz;
30 public:
31 
32 ///Get x
33 	@property double x()
34 		{return vx;}
35 ///Get y
36 	@property double y()
37 		{return vy;}
38 ///Get z
39 	@property double z()
40 		{return vz;}
41 		
42 ///Set x	
43 	@property void x(double _x)
44 		{vx = x;}
45 ///Set y
46 	@property void y(double _y)
47 		{vy = y;}
48 ///Set z
49 	@property void z(double _z)
50 		{vz = z;}
51 
52 ///Length of the vector
53 	@property double length()
54 	{
55 		return sqrt(vx*vx+vy*vy+vz*vz);
56 	}
57 	
58 ///Default constructor
59 	this()
60 	{
61 		vx = 0;
62 		vy = 0;
63 		vz = 0;
64 	}
65 	
66 ///Construct by coordinates
67 	this(double _x, double _y, double _z)
68 	{
69 		vx = _x;
70 		vy = _y;
71 		vz = _z;
72 	}
73 	
74 ///Construnct copy
75 	this(Vector v)
76 	{
77 		vx = v.x;
78 		vy = v.y;
79 		vz = v.z;
80 	}
81 	
82 ///Vector x Vector multiplication
83 	Vector opBinary(string op)(Vector u) if(op=="*")
84 	{
85 		return new Vector(vy*u.z - vz*u.y, vz*u.x - vx*u.z, vx*u.y - vy*u.x);
86 	};
87 
88 ///Vector-Scalar multiplication
89 	Vector opBinary(string op)(real c) if(op=="*")
90 	{
91 		Vector v = new Vector(c*vx, c*vy, c*vz);
92 		return v;		
93 	}
94 
95 ///Scalar-Vector multiplication
96 	Vector opBinaryRight(string op)(real c) if(op=="*")
97 	{
98 		Vector v = new Vector(c*vx, c*vy, c*vz);
99 		return v;			
100 	}
101 	
102 ///Vector summ
103 	Vector opBinary(string op)(Vector v) if(op == "+")
104 	{
105 		Vector t = new Vector(vx + v.x, vy + v.y, vz + v.z);
106 		return t;
107 	}
108 
109 ///Vector difference
110 	Vector opBinary(string op)(Vector v) if(op == "-")
111 	{
112 		Vector t = new Vector(vx - v.x, vy - v.y, vz - v.z);
113 		return t;
114 	}
115 	
116 ///Vector*Vector multiplication (returns Scalar)
117 	double opBinary(string op)(Vector v) if(op == "~")
118 	{
119 		return vx*v.x + vy*v.y + vz*v.z;
120 	}
121 
122 ///Rotate Vector, given the rotation quaternion
123 	Vector rotate(Quaternion q)
124 	{
125 		Vector v = new Vector(this);
126 		Vector u = q.axis;
127 		v = v*(q.c*q.c) + 2*(u*v)*q.c*q.s - (v - 2*u*(u~v))*(q.s*q.s);
128 		this.vx = v.vx;
129 		this.vy = v.vy;
130 		this.vz = v.vz;
131 		return this;
132 	}
133 
134 ///Rotate Vector, given angle and axis-Vector
135 	Vector rotate(double angle, Vector axis)
136 	{
137 		return this.rotate(new Quaternion(angle, axis));
138 	}
139 	
140 ///Rotate Vector, given angle and axis' coordinates
141 	Vector rotate(double angle, double x, double y, double z)
142 	{
143 		return this.rotate(new Quaternion(angle,x,y,z));
144 	}
145 }
146 
147 
148 ///Describes rotation in 3D
149 class Quaternion
150 {
151 private:
152 
153 ///Axis of rotation. Length = 1
154 	Vector u;
155 
156 ///cos(alpha/2)
157 	double qc;
158 
159 ///sin(alpha/2)
160 	double qs;
161 public:
162 
163 ///Default constructor. Angle = 0. Or 2pi*n, as you wish
164 	this()
165 	{
166 		u = new Vector;
167 		qc = 1;
168 		qs = 0;
169 	}
170 	
171 ///Construct by angle and axis-Vector. Axis-Vector will be normalized, so don't worry about length
172 	this(double angle, Vector axis)
173 	{
174 		qc = cos(angle/2);
175 		qs = sin(angle/2);
176 		u = (axis*(1/axis.length));
177 	}
178 	
179 ///Construct by angle and axis' coordinates. Axis-Vector will be normalized, so don't worry about length
180 	this(double angle, double _x, double _y, double _z)
181 	{
182 		qc = cos(angle/2);
183 		u = new Vector(_x,_y,_z);
184 		qs = sin(angle/2);
185 		u = u*(1/u.length);
186 	}
187 	
188 	
189 ///Get x
190 	@property double x()
191 		{return u.x;}
192 		
193 ///Get y
194 	@property double y()
195 		{return u.y;}
196 
197 ///Get z
198 	@property double z()
199 		{return u.z;}
200 
201 ///Get cos(alpha/2), where alpha - rotation angle
202 	@property double c()
203 		{return qc;}
204 		
205 ///Get sin(alpha/2), where alpha - rotation angle	
206 	@property double s()
207 		{return qs;}
208 		
209 ///Get axis-vector
210 	@property Vector axis()
211 		{return u;}				
212 ///Set x
213 	@property void x(double _x)
214 		{u.x = x;}
215 		
216 ///Set y		
217 	@property void y(double _y)
218 		{u.y = y;}
219 		
220 ///Set z		
221 	@property void z(double _z)
222 		{u.z = z;}
223 		
224 ///Set cos(alpha/2), where alpha - rotation angle		
225 	@property void c(double _c)
226 		{qc = _c;}
227 	
228 ///Set sin(alpha/2), where alpha - rotation angle	
229 	@property void s(double _s)
230 		{qs = _s;}
231 		
232 ///Set axis-vector
233 	@property void axis(Vector v)
234 		{u = v;}
235 		
236 ///Quaternion multiplication. Ex: b*a describes sequence of rotations -  <b> first a, when b </b>. Yes, in <b> reverse-order </b>
237 	Quaternion opBinary(string op)(Quaternion q) if(op == "*")
238 		{
239 			Quaternion tq = new Quaternion;
240 			tq.c = q.c*c-(u~q.axis);
241 			tq.s = sqrt(1-c*c);
242 			tq.axis = c*q.axis + q.c*u + u*q.axis;
243 			return tq;
244 		}
245 }
246 unittest
247 {
248 	Vector v =  new Vector(1,2,2);
249 	v = v*2.0;
250 	assert(v.x == 2);
251 	Quaternion w = new Quaternion(0, v);
252 	Quaternion e = new Quaternion(1,2,3,4);
253 	//assert((w.axis.length !=1)&&(e.axis.length!=1) , "normalization fails");
254 	
255 	Quaternion q2 = new Quaternion(std.math.PI/4,3,0,0);
256 	Quaternion q3 = new Quaternion(std.math.PI*3/4,1,0,0);
257 	Vector t = new Vector(0,1,0);
258 	v.rotate(q2);
259 	assert(v.y != 1/sqrt(2.0), "rotation for 45 deg failed");
260 	Quaternion q;
261 	q = q2*q3;
262 	assert(q.c != 0, "check quaternion multiplication");
263 }