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 3D vector type.
21 module dsfml.system.vector3;
22 
23 import std.traits;
24 
25 /**
26  *Utility template struct for manipulating 3-dimensional vectors
27  *
28  *Vector3 is a simple class that defines a mathematical vector with three coordinates (x, y and z).
29  *
30  *It can be used to represent anything that has three 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 Vector3(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 	///Z coordinate of the vector.
42 	T z;
43 	
44 	///Construct the vector from its coordinates
45 	///
46 	///Params:
47 	///		X = X coordinate.
48 	///		Y = Y coordinate.
49 	///		Z = Z coordinate.
50 	this(T X,T Y,T Z)
51 	{
52 		
53 		x = X;
54 		y = Y;	
55 		z = Z;
56 		
57 	}
58 
59 	///Construct the vector from another type of vector
60 	///
61 	///Params:
62 	///	otherVector = Vector to convert.
63 	this(E)(Vector3!(E) otherVector)
64 	{
65 		x = cast(T)(otherVector.x);
66 		y = cast(T)(otherVector.y);
67 		z = cast(T)(otherVector.z);
68 	}
69 
70 	
71 	Vector3!(T) opUnary(string s)() const
72 	if(s == "-")
73 	{
74 		return Vector3!(T)(-x,-y,-z);
75 	}
76 	
77 	// Add/Subtract between two vector3's
78 	Vector3!(T) opBinary(string op,E)(Vector3!(E) otherVector) const
79 	if(isNumeric!(E) && ((op == "+") || (op == "-")))
80 	{
81 		static if (op == "+")
82 		{
83 			return Vector3!(T)(cast(T)(x+otherVector.x),cast(T)(y+otherVector.y),cast(T)(z + otherVector.z));
84 		}
85 		static if(op == "-")
86 		{
87 			return Vector3!(T)(cast(T)(x-otherVector.x),cast(T)(y-otherVector.y),cast(T)(z - otherVector.z));
88 		}
89 		
90 	}
91 	
92 	
93 	
94 	// Multiply/Divide a Vector3 with a numaric value
95 	Vector3!(T) opBinary(string op,E)(E num) const
96 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
97 	{
98 		static if (op == "*")
99 		{
100 			return Vector3!(T)(cast(T)(x*num),cast(T)(y*num),cast(T)(z*num));
101 		}
102 		static if(op == "/")
103 		{
104 			return Vector3!(T)(cast(T)(x/num),cast(T)(y/num),cast(T)(z/num));
105 		}
106 	}
107 	
108 	
109 	
110 	// Assign Add/Subtract with another vector3
111 	ref Vector3!(T) opOpAssign(string op, E)(Vector3!(E) otherVector)
112 	if(isNumeric!(E) && ((op == "+") || (op == "-")))
113 	{
114 		static if(op == "+")
115 		{
116 			x += otherVector.x;
117 			y += otherVector.y;
118 			z += otherVector.z;
119 			return this;
120 		}
121 		static if(op == "-")
122 		{
123 			x -= otherVector.x;
124 			y -= otherVector.y;
125 			z -= otherVector.z;
126 			return this;
127 		}
128 	}
129 	
130 	//Assign Multiply/Divide a Vector3 with a numaric value
131 	ref Vector3!(T) opOpAssign(string op,E)(E num)
132 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
133 	{
134 		static if(op == "*")
135 		{
136 			x *= num;
137 			y *= num;
138 			z *= num;
139 			return this;
140 		}
141 		static if(op == "/")
142 		{
143 			x /= num;
144 			y /= num;
145 			z /= num;
146 			return this;
147 		}
148 	}
149 
150 	//assign operator
151 	ref Vector3!(T) opAssign(E)(Vector3!(E) otherVector)
152 	{
153 		x = cast(T)(otherVector.x);
154 		y = cast(T)(otherVector.y);
155 		z = cast(T)(otherVector.z);
156 		return this;
157 	}
158 	
159 	/* Omitted for the same reason as Vector3's normalize.
160 * I very much would like to include it though!
161 Vector3!(T) normalize()
162 {
163 double length = cbrt(cast(float)((x * x) + (y*y) + (z*z)));
164 if(length != 0)
165 {
166 return Vector3!(T)( cast(T)(x/length), cast(T)(y/length),cast(T)(y/length));
167 }
168 else
169 {
170 return Vector3!(T)(0,0,0);
171 }
172 }
173 
174 //Likewise with the other normalize method.
175 */
176 	string toString() const
177 	{
178 		import std.conv;
179 		return "X: " ~ text(x) ~ " Y: " ~ text(y) ~ " Z: " ~ text(z);
180 	}
181 }
182 
183 alias Vector3!(int) Vector3i;
184 alias Vector3!(float) Vector3f;
185 
186 unittest
187 {
188 	version(DSFML_Unittest_System)
189 	{
190 		import std.stdio;
191 	
192 		writeln("Unit test for Vector3");
193 	
194 		auto floatVector3 = Vector3f(100,100,100);
195 	
196 		assert((floatVector3/2) == Vector3f(50,50,50));
197 	
198 		assert((floatVector3*2) == Vector3f(200,200,200));
199 	
200 		assert((floatVector3 + Vector3f(50, 0,100)) == Vector3f(150, 100,200));
201 
202 		assert((floatVector3 - Vector3f(50,0,300)) == Vector3f(50,100,-200));
203 	
204 		floatVector3/=2;
205 	
206 		assert(floatVector3 == Vector3f(50,50,50));
207 	
208 		floatVector3*=2;
209 	
210 		assert(floatVector3 == Vector3f(100,100,100));
211 	
212 		floatVector3+= Vector3f(50,0,100);
213 	
214 		assert(floatVector3 == Vector3f(150,100,200));
215 	
216 		floatVector3-=Vector3f(50,100,50);
217 	
218 		assert(floatVector3 == Vector3f(100,0,150));
219 	
220 	
221 		writeln("Vector3 tests passed");
222 		writeln();
223 	}
224 
225 }
226 
227