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