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