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