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 }