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  * Vector3 is a simple class that defines a mathematical vector with three
27  * coordinates (x, y and z). It can be used to represent anything that has three
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 Vector3!(float) is Vector2f)
38  * $(LI Vector3!(int) is Vector2i))
39  *
40  * Example:
41  * ---
42  * auto v1 = Vector3f(16.5f, 24.f, -8.2f);
43  * v1.x = 18.2f;
44  * float y = v1.y;
45  * float z = v1.z;
46  *
47  * auto v2 = v1 * 5.f;
48  * Vector3f v3;
49  * v3 = v1 + v2;
50  *
51  * bool different = (v2 != v3);
52  * ---
53  *
54  * See_Also:
55  * $(VECTOR2_LINK)
56  */
57 module dsfml.system.vector3;
58 
59 import std.traits;
60 
61 /**
62  * Utility template struct for manipulating 3-dimensional vectors.
63  */
64 struct Vector3(T)
65 	if(isNumeric!(T) || is(T == bool))
66 {
67 	/// X coordinate of the vector.
68 	T x;
69 	/// Y coordinate of the vector.
70 	T y;
71 	/// Z coordinate of the vector.
72 	T z;
73 
74 	/**
75 	 * Construct the vector from its coordinates
76 	 *
77 	 * Params:
78 	 * 		X = X coordinate
79 	 * 		Y = Y coordinate
80 	 * 		Z = Z coordinate
81 	 */
82 	this(T X,T Y,T Z)
83 	{
84 
85 		x = X;
86 		y = Y;
87 		z = Z;
88 
89 	}
90 
91 	/**
92 	 * Construct the vector from another type of vector
93 	 *
94 	 * Params:
95 	 * 	otherVector = Vector to convert.
96 	 */
97 	this(E)(Vector3!(E) otherVector)
98 	{
99 		x = cast(T)(otherVector.x);
100 		y = cast(T)(otherVector.y);
101 		z = cast(T)(otherVector.z);
102 	}
103 
104 	/// Invert the members of the vector.
105 	Vector3!(T) opUnary(string s)() const
106 	if(s == "-")
107 	{
108 		return Vector3!(T)(-x,-y,-z);
109 	}
110 
111 	/// Add/Subtract between two vector3's.
112 	Vector3!(T) opBinary(string op,E)(Vector3!(E) otherVector) const
113 	if(isNumeric!(E) && ((op == "+") || (op == "-")))
114 	{
115 		static if (op == "+")
116 		{
117 			return Vector3!(T)(cast(T)(x+otherVector.x),cast(T)(y+otherVector.y),cast(T)(z + otherVector.z));
118 		}
119 		static if(op == "-")
120 		{
121 			return Vector3!(T)(cast(T)(x-otherVector.x),cast(T)(y-otherVector.y),cast(T)(z - otherVector.z));
122 		}
123 
124 	}
125 
126 	/// Multiply/Divide a Vector3 with a numaric value.
127 	Vector3!(T) opBinary(string op,E)(E num) const
128 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
129 	{
130 		static if (op == "*")
131 		{
132 			return Vector3!(T)(cast(T)(x*num),cast(T)(y*num),cast(T)(z*num));
133 		}
134 		static if(op == "/")
135 		{
136 			return Vector3!(T)(cast(T)(x/num),cast(T)(y/num),cast(T)(z/num));
137 		}
138 	}
139 
140 	/// Assign Add/Subtract with another vector3.
141 	ref Vector3!(T) opOpAssign(string op, E)(Vector3!(E) otherVector)
142 	if(isNumeric!(E) && ((op == "+") || (op == "-")))
143 	{
144 		static if(op == "+")
145 		{
146 			x += otherVector.x;
147 			y += otherVector.y;
148 			z += otherVector.z;
149 			return this;
150 		}
151 		static if(op == "-")
152 		{
153 			x -= otherVector.x;
154 			y -= otherVector.y;
155 			z -= otherVector.z;
156 			return this;
157 		}
158 	}
159 
160 	// Assign Multiply/Divide a Vector3 with a numaric value.
161 	ref Vector3!(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 			z *= num;
169 			return this;
170 		}
171 		static if(op == "/")
172 		{
173 			x /= num;
174 			y /= num;
175 			z /= num;
176 			return this;
177 		}
178 	}
179 
180 	/// Assign the value of another vector whose type can be converted to T.
181 	ref Vector3!(T) opAssign(E)(Vector3!(E) otherVector)
182 	{
183 		x = cast(T)(otherVector.x);
184 		y = cast(T)(otherVector.y);
185 		z = cast(T)(otherVector.z);
186 		return this;
187 	}
188 
189 	/// Compare two vectors for equality.
190 	bool opEquals(E)(const Vector3!(E) otherVector) const
191 	if(isNumeric!(E))
192 	{
193 		return ((x == otherVector.x) && (y == otherVector.y)
194 				&& (z == otherVector.z));
195 	}
196 
197 	/// Output the string representation of the Vector3.
198 	string toString() const
199 	{
200 		import std.conv;
201 		return "X: " ~ text(x) ~ " Y: " ~ text(y) ~ " Z: " ~ text(z);
202 	}
203 }
204 
205 /// Definition of a Vector3 of integers.
206 alias Vector3!(int) Vector3i;
207 /// Definition of a Vector3 of floats.
208 alias Vector3!(float) Vector3f;
209 
210 unittest
211 {
212 	version(DSFML_Unittest_System)
213 	{
214 		import std.stdio;
215 
216 		writeln("Unit test for Vector3");
217 
218 		auto floatVector3 = Vector3f(100,100,100);
219 
220 		assert((floatVector3/2) == Vector3f(50,50,50));
221 
222 		assert((floatVector3*2) == Vector3f(200,200,200));
223 
224 		assert((floatVector3 + Vector3f(50, 0,100)) == Vector3f(150, 100,200));
225 
226 		assert((floatVector3 - Vector3f(50,0,300)) == Vector3f(50,100,-200));
227 
228 		floatVector3/=2;
229 
230 		assert(floatVector3 == Vector3f(50,50,50));
231 
232 		floatVector3*=2;
233 
234 		assert(floatVector3 == Vector3f(100,100,100));
235 
236 		floatVector3+= Vector3f(50,0,100);
237 
238 		assert(floatVector3 == Vector3f(150,100,200));
239 
240 		floatVector3-=Vector3f(50,100,50);
241 
242 		assert(floatVector3 == Vector3f(100,0,150));
243 
244 		writeln("Vector3 tests passed");
245 		writeln();
246 	}
247 
248 }