1 /* 2 DSFML - The Simple and Fast Multimedia Library for D 3 4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 6 This software is provided 'as-is', without any express or implied warranty. 7 In no event will the authors be held liable for any damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial applications, 10 and to alter it and redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 14 15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 16 17 3. This notice may not be removed or altered from any source distribution 18 */ 19 20 ///A module containing a numeric 3D vector type. 21 module dsfml.system.vector3; 22 23 import std.traits; 24 25 /** 26 *Utility template struct for manipulating 3-dimensional vectors 27 * 28 *Vector3 is a simple class that defines a mathematical vector with three coordinates (x, y and z). 29 * 30 *It can be used to represent anything that has three dimensions: a size, a point, a velocity, etc. 31 * 32 *The template parameter T is the type of the coordinates. It can be any type that supports arithmetic operations (+, -, /, *) and comparisons (==, !=), for example int or float. 33 */ 34 struct Vector3(T) 35 if(isNumeric!(T)) 36 { 37 ///X coordinate of the vector. 38 T x; 39 ///Y coordinate of the vector. 40 T y; 41 ///Z coordinate of the vector. 42 T z; 43 44 ///Construct the vector from its coordinates 45 /// 46 ///Params: 47 /// X = X coordinate. 48 /// Y = Y coordinate. 49 /// Z = Z coordinate. 50 this(T X,T Y,T Z) 51 { 52 53 x = X; 54 y = Y; 55 z = Z; 56 57 } 58 59 ///Construct the vector from another type of vector 60 /// 61 ///Params: 62 /// otherVector = Vector to convert. 63 this(E)(Vector3!(E) otherVector) 64 { 65 x = cast(T)(otherVector.x); 66 y = cast(T)(otherVector.y); 67 z = cast(T)(otherVector.z); 68 } 69 70 71 Vector3!(T) opUnary(string s)() const 72 if(s == "-") 73 { 74 return Vector3!(T)(-x,-y,-z); 75 } 76 77 // Add/Subtract between two vector3's 78 Vector3!(T) opBinary(string op,E)(Vector3!(E) otherVector) const 79 if(isNumeric!(E) && ((op == "+") || (op == "-"))) 80 { 81 static if (op == "+") 82 { 83 return Vector3!(T)(cast(T)(x+otherVector.x),cast(T)(y+otherVector.y),cast(T)(z + otherVector.z)); 84 } 85 static if(op == "-") 86 { 87 return Vector3!(T)(cast(T)(x-otherVector.x),cast(T)(y-otherVector.y),cast(T)(z - otherVector.z)); 88 } 89 90 } 91 92 93 94 // Multiply/Divide a Vector3 with a numaric value 95 Vector3!(T) opBinary(string op,E)(E num) const 96 if(isNumeric!(E) && ((op == "*") || (op == "/"))) 97 { 98 static if (op == "*") 99 { 100 return Vector3!(T)(cast(T)(x*num),cast(T)(y*num),cast(T)(z*num)); 101 } 102 static if(op == "/") 103 { 104 return Vector3!(T)(cast(T)(x/num),cast(T)(y/num),cast(T)(z/num)); 105 } 106 } 107 108 109 110 // Assign Add/Subtract with another vector3 111 ref Vector3!(T) opOpAssign(string op, E)(Vector3!(E) otherVector) 112 if(isNumeric!(E) && ((op == "+") || (op == "-"))) 113 { 114 static if(op == "+") 115 { 116 x += otherVector.x; 117 y += otherVector.y; 118 z += otherVector.z; 119 return this; 120 } 121 static if(op == "-") 122 { 123 x -= otherVector.x; 124 y -= otherVector.y; 125 z -= otherVector.z; 126 return this; 127 } 128 } 129 130 //Assign Multiply/Divide a Vector3 with a numaric value 131 ref Vector3!(T) opOpAssign(string op,E)(E num) 132 if(isNumeric!(E) && ((op == "*") || (op == "/"))) 133 { 134 static if(op == "*") 135 { 136 x *= num; 137 y *= num; 138 z *= num; 139 return this; 140 } 141 static if(op == "/") 142 { 143 x /= num; 144 y /= num; 145 z /= num; 146 return this; 147 } 148 } 149 150 //assign operator 151 ref Vector3!(T) opAssign(E)(Vector3!(E) otherVector) 152 { 153 x = cast(T)(otherVector.x); 154 y = cast(T)(otherVector.y); 155 z = cast(T)(otherVector.z); 156 return this; 157 } 158 159 /* Omitted for the same reason as Vector3's normalize. 160 * I very much would like to include it though! 161 Vector3!(T) normalize() 162 { 163 double length = cbrt(cast(float)((x * x) + (y*y) + (z*z))); 164 if(length != 0) 165 { 166 return Vector3!(T)( cast(T)(x/length), cast(T)(y/length),cast(T)(y/length)); 167 } 168 else 169 { 170 return Vector3!(T)(0,0,0); 171 } 172 } 173 174 //Likewise with the other normalize method. 175 */ 176 string toString() const 177 { 178 import std.conv; 179 return "X: " ~ text(x) ~ " Y: " ~ text(y) ~ " Z: " ~ text(z); 180 } 181 } 182 183 alias Vector3!(int) Vector3i; 184 alias Vector3!(float) Vector3f; 185 186 unittest 187 { 188 version(DSFML_Unittest_System) 189 { 190 import std.stdio; 191 192 writeln("Unit test for Vector3"); 193 194 auto floatVector3 = Vector3f(100,100,100); 195 196 assert((floatVector3/2) == Vector3f(50,50,50)); 197 198 assert((floatVector3*2) == Vector3f(200,200,200)); 199 200 assert((floatVector3 + Vector3f(50, 0,100)) == Vector3f(150, 100,200)); 201 202 assert((floatVector3 - Vector3f(50,0,300)) == Vector3f(50,100,-200)); 203 204 floatVector3/=2; 205 206 assert(floatVector3 == Vector3f(50,50,50)); 207 208 floatVector3*=2; 209 210 assert(floatVector3 == Vector3f(100,100,100)); 211 212 floatVector3+= Vector3f(50,0,100); 213 214 assert(floatVector3 == Vector3f(150,100,200)); 215 216 floatVector3-=Vector3f(50,100,50); 217 218 assert(floatVector3 == Vector3f(100,0,150)); 219 220 221 writeln("Vector3 tests passed"); 222 writeln(); 223 } 224 225 } 226 227