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 2D vector type. 21 module dsfml.system.vector2; 22 23 import std.traits; 24 25 /** 26 *Utility template struct for manipulating 2-dimensional vectors 27 * 28 *Vector2 is a simple class that defines a mathematical vector with two coordinates (x and y). 29 * 30 *It can be used to represent anything that has two 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 Vector2(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 42 ///Construct the vector from its coordinates 43 /// 44 ///Params: 45 /// X = X coordinate. 46 /// Y = Y coordinate. 47 this(T X,T Y) 48 { 49 x = X; 50 y = Y; 51 } 52 53 ///Construct the vector from another type of vector 54 /// 55 ///Params: 56 /// otherVector = Vector to convert. 57 this(E)(Vector2!(E) otherVector) 58 { 59 x = cast(T)(otherVector.x); 60 y = cast(T)(otherVector.y); 61 } 62 63 64 //I think it could be a useful function, but 65 //since it isn't part of the API I will leave it out for now. 66 67 /* 68 //Returns a copy of the normalized vector instead of changing current one. 69 Vector2!(T) normalized() 70 { 71 double length = sqrt(cast(double)((x * x) +(y*y))); 72 if(length != 0) 73 { 74 return Vector2!(T)( cast(T)(x/length), cast(T)(y/length)); 75 } 76 else 77 { 78 return Vector2!(T)(0,0); 79 } 80 } 81 82 //Had plans for a method that normalizes the vector instead of returning 83 //a normalized copy, but also not part of the API 84 85 86 */ 87 88 Vector2!(T) opUnary(string s)() const 89 if (s == "-") 90 { 91 return Vector2!(T)(-x, -y); 92 } 93 94 // Add/Subtract between two vector2's 95 Vector2!(T) opBinary(string op, E)(Vector2!(E) otherVector) const 96 if(isNumeric!(E) && ((op == "+") || (op == "-"))) 97 { 98 static if (op == "+") 99 { 100 return Vector2!(T)(cast(T)(x+otherVector.x),cast(T)(y+otherVector.y)); 101 } 102 static if(op == "-") 103 { 104 return Vector2!(T)(cast(T)(x-otherVector.x),cast(T)(y-otherVector.y)); 105 } 106 } 107 108 109 110 // Multiply/Divide a vector with a numaric value 111 Vector2!(T) opBinary (string op, E)(E num) const 112 if(isNumeric!(E) && ((op == "*") || (op == "/"))) 113 { 114 static if (op == "*") 115 { 116 return Vector2!(T)(cast(T)(x*num),cast(T)(y*num)); 117 } 118 static if(op == "/") 119 { 120 return Vector2!(T)(cast(T)(x/num),cast(T)(y/num)); 121 } 122 } 123 124 125 // Assign Add/Subtract with another vector2 126 ref Vector2!(T) opOpAssign(string op, E)(Vector2!(E) otherVector) 127 if(isNumeric!(E) && ((op == "+") || (op == "-"))) 128 { 129 static if(op == "+") 130 { 131 x = cast(T)(x + otherVector.x); 132 y = cast(T)(y + otherVector.y); 133 return this; 134 } 135 static if(op == "-") 136 { 137 x = cast(T)(x - otherVector.x); 138 y = cast(T)(y - otherVector.y); 139 return this; 140 } 141 } 142 143 //Assign Multiply/Divide with a numaric value 144 ref Vector2!(T) opOpAssign(string op,E)(E num) 145 if(isNumeric!(E) && ((op == "*") || (op == "/"))) 146 { 147 static if(op == "*") 148 { 149 x *= num; 150 y *= num; 151 return this; 152 } 153 static if(op == "/") 154 { 155 x /= num; 156 y /= num; 157 return this; 158 } 159 } 160 161 //assign operator 162 ref Vector2!(T) opAssign(E)(Vector2!(E) otherVector) 163 { 164 x = cast(T)(otherVector.x); 165 y = cast(T)(otherVector.y); 166 return this; 167 } 168 169 //Compare operator 170 bool opEquals(E)(const Vector2!(E) otherVector) const 171 if(isNumeric!(E)) 172 { 173 return ((x == otherVector.x) && (y == otherVector.y)); 174 } 175 176 //figured it would be useful for testing, debugging, etc 177 string toString() const 178 { 179 import std.conv; 180 return "X: " ~ text(x) ~ " Y: " ~ text(y); 181 } 182 } 183 184 alias Vector2!(int) Vector2i; 185 alias Vector2!(float) Vector2f; 186 alias Vector2!(uint) Vector2u; 187 188 unittest 189 { 190 version(DSFML_Unittest_System) 191 { 192 import std.stdio; 193 194 writeln("Unit test for Vector2"); 195 196 auto floatVector2 = Vector2f(100,100); 197 198 assert((floatVector2/2) == Vector2f(50,50)); 199 200 assert((floatVector2*2) == Vector2f(200,200)); 201 202 assert((floatVector2 + Vector2f(50, 0)) == Vector2f(150, 100)); 203 204 assert((floatVector2 - Vector2f(50,0)) == Vector2f(50,100)); 205 206 floatVector2/=2; 207 208 assert(floatVector2 == Vector2f(50,50)); 209 210 floatVector2*=2; 211 212 assert(floatVector2 == Vector2f(100,100)); 213 214 floatVector2+= Vector2f(50,0); 215 216 assert(floatVector2 == Vector2f(150,100)); 217 218 floatVector2-=Vector2f(50,100); 219 220 assert(floatVector2 == Vector2f(100,0)); 221 222 223 writeln("Vector2 tests passed"); 224 writeln(); 225 226 } 227 } 228