1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2017 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
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  */
24 
25 /**
26  * $(U Vector2) is a simple structure that defines a mathematical vector with
27  * two coordinates (x and y).  It can be used to represent anything that has two
28  * dimensions: a size, a point, a velocity, etc.
29  *
30  * The template parameter T is the type of the coordinates. It can be any type
31  * that supports arithmetic operations (+, -, /, *) and comparisons (==, !=),
32  * for example int or float.
33  *
34  * You generally don't have to care about the templated form (Vector2!(T),
35  * the most common specializations have special aliases:
36  * $(UL
37  * $(LI Vector2!(float) is Vector2f)
38  * $(LI Vector2!(int) is Vector2i)
39  * $(LI Vector2!(uint) is Vector2u))
40  *
41  * $(PARA
42  * The $(U Vector2) class has a small and simple interface, its x and y members
43  * can be accessed directly (there are no accessors like `setX()`, `getX()`) and
44  * it contains no mathematical function like dot product, cross product, length,
45  * etc.)
46  *
47  * Example:
48  * ---
49  * auto v1 = Vector2f(16.5f, 24.f);
50  * v1.x = 18.2f;
51  * float y = v1.y;
52  *
53  * auto v2 = v1 * 5.f;
54  * Vector2f v3;
55  * v3 = v1 + v2;
56  *
57  * bool different = (v2 != v3);
58  * ---
59  *
60  * See_Also:
61  * $(VECTOR3_LINK)
62  */
63 module dsfml.system.vector2;
64 
65 import std.traits;
66 
67 /**
68  * Utility template struct for manipulating 2-dimensional vectors.
69  */
70 struct Vector2(T)
71 	if(isNumeric!(T) || is(T == bool))
72 {
73 	/// X coordinate of the vector.
74 	T x;
75 	/// Y coordinate of the vector.
76 	T y;
77 
78 	/**
79 	 * Construct the vector from its coordinates.
80 	 *
81 	 * Params:
82 	 * 		X = X coordinate
83 	 * 		Y = Y coordinate
84 	 */
85 	this(T X,T Y)
86 	{
87 		x = X;
88 		y = Y;
89 	}
90 
91 	/**
92 	 * Construct the vector from another type of vector.
93 	 *
94 	 * Params:
95 	 * 	otherVector = Vector to convert
96 	 */
97 	this(E)(Vector2!(E) otherVector)
98 	{
99 		x = cast(T)(otherVector.x);
100 		y = cast(T)(otherVector.y);
101 	}
102 
103 	/// Invert the members of the vector.
104 	Vector2!(T) opUnary(string s)() const
105 	if (s == "-")
106 	{
107 		return Vector2!(T)(-x, -y);
108 	}
109 
110 	/// Add/Subtract between two vector2's.
111 	Vector2!(T) opBinary(string op, E)(Vector2!(E) otherVector) const
112 	if(isNumeric!(E) && ((op == "+") || (op == "-")))
113 	{
114 		static if (op == "+")
115 		{
116 			return Vector2!(T)(cast(T)(x+otherVector.x),cast(T)(y+otherVector.y));
117 		}
118 		static if(op == "-")
119 		{
120 			return Vector2!(T)(cast(T)(x-otherVector.x),cast(T)(y-otherVector.y));
121 		}
122 	}
123 
124 	/// Multiply/Divide a vector with a numaric value.
125 	Vector2!(T) opBinary (string op, E)(E num) const
126 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
127 	{
128 		static if (op == "*")
129 		{
130 			return Vector2!(T)(cast(T)(x*num),cast(T)(y*num));
131 		}
132 		static if(op == "/")
133 		{
134 			return Vector2!(T)(cast(T)(x/num),cast(T)(y/num));
135 		}
136 	}
137 
138 	/// Assign Add/Subtract with another vector2.
139 	ref Vector2!(T) opOpAssign(string op, E)(Vector2!(E) otherVector)
140 	if(isNumeric!(E) && ((op == "+") || (op == "-")))
141 	{
142 		static if(op == "+")
143 		{
144 			x = cast(T)(x + otherVector.x);
145 			y = cast(T)(y + otherVector.y);
146 			return this;
147 		}
148 		static if(op == "-")
149 		{
150 			x = cast(T)(x - otherVector.x);
151 			y = cast(T)(y - otherVector.y);
152 			return this;
153 		}
154 	}
155 
156 	/// Assign Multiply/Divide with a numaric value.
157 	ref Vector2!(T) opOpAssign(string op,E)(E num)
158 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
159 	{
160 		static if(op == "*")
161 		{
162 			x *= num;
163 			y *= num;
164 			return this;
165 		}
166 		static if(op == "/")
167 		{
168 			x /= num;
169 			y /= num;
170 			return this;
171 		}
172 	}
173 
174 	/// Assign the value of another vector whose type can be converted to T.
175 	ref Vector2!(T) opAssign(E)(Vector2!(E) otherVector)
176 	{
177 		x = cast(T)(otherVector.x);
178 		y = cast(T)(otherVector.y);
179 		return this;
180 	}
181 
182 	/// Compare two vectors for equality.
183 	bool opEquals(E)(const Vector2!(E) otherVector) const
184 	if(isNumeric!(E))
185 	{
186 		return ((x == otherVector.x) && (y == otherVector.y));
187 	}
188 
189 	/// Output the string representation of the Vector2.
190 	string toString() const
191 	{
192 		import std.conv;
193 		return "X: " ~ text(x) ~ " Y: " ~ text(y);
194 	}
195 }
196 
197 /// Definition of a Vector2 of integers.
198 alias Vector2!(int) Vector2i;
199 /// Definition of a Vector2 of floats.
200 alias Vector2!(float) Vector2f;
201 /// Definition of a Vector2 of unsigned integers.
202 alias Vector2!(uint) Vector2u;
203 
204 unittest
205 {
206 	version(DSFML_Unittest_System)
207 	{
208 		import std.stdio;
209 
210 		writeln("Unit test for Vector2");
211 
212 		auto floatVector2 = Vector2f(100,100);
213 
214 		assert((floatVector2/2) == Vector2f(50,50));
215 
216 		assert((floatVector2*2) == Vector2f(200,200));
217 
218 		assert((floatVector2 + Vector2f(50, 0)) == Vector2f(150, 100));
219 
220 		assert((floatVector2 - Vector2f(50,0)) == Vector2f(50,100));
221 
222 		floatVector2/=2;
223 
224 		assert(floatVector2 == Vector2f(50,50));
225 
226 		floatVector2*=2;
227 
228 		assert(floatVector2 == Vector2f(100,100));
229 
230 		floatVector2+= Vector2f(50,0);
231 
232 		assert(floatVector2 == Vector2f(150,100));
233 
234 		floatVector2-=Vector2f(50,100);
235 
236 		assert(floatVector2 == Vector2f(100,0));
237 
238 		writeln("Vector2 tests passed");
239 		writeln();
240 
241 	}
242 }