1 module prova.math.vector4;
2 
3 import prova.math;
4 import std.math;
5 
6 ///
7 struct Vector4
8 {
9   ///
10   float x = 0;
11   ///
12   float y = 0;
13   ///
14   float z = 0;
15   ///
16   float w = 0;
17 
18   ///
19   this(float x, float y, float z, float w)
20   {
21     set(x, y, z, w);
22   }
23 
24   ///
25   this(Vector3 vector)
26   {
27     set(vector.x, vector.y, vector.z, 0);
28   }
29 
30   ///
31   this(Vector2 vector)
32   {
33     set(vector.x, vector.y, 0, 0);
34   }
35 
36   /// Sets the values of x, y, z, and w in a single statement
37   void set(float x, float y, float z, float w)
38   {
39     this.x = x;
40     this.y = y;
41     this.z = z;
42     this.w = w;
43   }
44 
45   /// Creates a normalized vector with a random direction
46   static Vector4 random()
47   {
48     Vector4 vector = Vector4(
49       randomF(-1, 1),
50       randomF(-1, 1),
51       randomF(-1, 1),
52       randomF(-1, 1)
53     );
54 
55     vector.normalize();
56 
57     return vector;
58   }
59 
60   ///
61   @property Vector2 xy() const
62   {
63     return Vector2(x, y);
64   }
65 
66   ///
67   @property Vector3 xyz() const
68   {
69     return Vector3(x, y, z);
70   }
71 
72   /// Returns a normalized copy of this vector
73   Vector4 getNormalized() const
74   {
75     const float magnitude = getMagnitude();
76 
77     Vector4 result;
78     
79     if(magnitude != 0) {
80       result.x = x / magnitude;
81       result.y = y / magnitude;
82       result.z = z / magnitude;
83       result.w = w / magnitude;
84     }
85     
86     return result;
87   }
88 
89   /// Normalizes the vector
90   void normalize()
91   {
92     const float magnitude = getMagnitude();
93 
94     if(magnitude == 0)
95       return;
96 
97     x = x / magnitude;
98     y = y / magnitude;
99     z = z / magnitude;
100     w = w / magnitude;
101   }
102 
103   /// Returns the magnitude of the vector
104   float getMagnitude() const
105   {
106     return sqrt(x * x + y * y + z * z + w * w);
107   }
108 
109   /**
110    * Sets the magnitude of this vector
111    *
112    * If the previous magnitude is zero, the x value
113    * of the vector will be set to the magnitude
114    */
115   void setMagnitude(float magnitude)
116   {
117     if(getMagnitude() == 0) {
118       x = magnitude;
119       return;
120     }
121 
122     normalize();
123 
124     x *= magnitude;
125     y *= magnitude;
126     z *= magnitude;
127     w *= magnitude;
128   }
129 
130   /// Returns the distance between the vectors
131   float distanceTo(Vector4 vector) const
132   {
133     const float a = vector.x - x;
134     const float b = vector.y - y;
135     const float c = vector.z - z;
136     const float d = vector.w - w;
137 
138     return sqrt(a * a + b * b + c * c + d * d);
139   }
140 
141   /// Returns the squared distance between the vectors
142   float distanceToSquared(Vector4 vector) const
143   {
144     const float a = vector.x - x;
145     const float b = vector.y - y;
146     const float c = vector.z - z;
147     const float d = vector.w - w;
148 
149     return a * a + b * b + c * c + d * d;
150   }
151 
152   /// Returns the dot product of the two vectors
153   float dot(Vector4 vector) const
154   {
155     return x * vector.x + y * vector.y + z * vector.z + w * vector.w;
156   }
157 
158 
159   // assignment overloading
160   ///
161   Vector4 opAddAssign(Vector4 vector)
162   {
163     x += vector.x;
164     y += vector.y;
165     z += vector.z;
166     w += vector.w;
167 
168     return this;
169   }
170 
171   ///
172   Vector4 opSubAssign(Vector4 vector)
173   {
174     x -= vector.x;
175     y -= vector.y;
176     z -= vector.z;
177     w -= vector.w;
178 
179     return this;
180   }
181 
182   ///
183   Vector4 opMulAssign(Vector4 vector)
184   {
185     x *= vector.x;
186     y *= vector.y;
187     z *= vector.z;
188     w *= vector.w;
189 
190     return this;
191   }
192 
193   ///
194   Vector4 opMulAssign(float a)
195   {
196     x *= a;
197     y *= a;
198     z *= a;
199     w *= a;
200 
201     return this;
202   }
203 
204   ///
205   Vector3 opDiv(Vector3 vector)
206   {
207     Vector3 result;
208     result.x = x * vector.x;
209     result.y = y * vector.y;
210     result.z = z * vector.z;
211 
212     return result;
213   }
214 
215   ///
216   Vector4 opDivAssign(Vector4 vector)
217   {
218     x /= vector.x;
219     y /= vector.y;
220     z /= vector.z;
221     w /= vector.w;
222 
223     return this;
224   }
225 
226   ///
227   Vector4 opDivAssign(float a)
228   {
229     x /= a;
230     y /= a;
231     z /= a;
232     w /= a;
233 
234     return this;
235   }
236 
237 
238   // arithmetic overloading
239   ///
240   Vector4 opAdd(Vector4 vector) const
241   {
242     Vector4 result;
243     result.x = x + vector.x;
244     result.y = y + vector.y;
245     result.z = z + vector.z;
246     result.w = w + vector.w;
247 
248     return result;
249   }
250 
251   ///
252   Vector4 opSub(Vector4 vector) const
253   {
254     Vector4 result;
255     result.x = x - vector.x;
256     result.y = y - vector.y;
257     result.z = z - vector.z;
258     result.w = w - vector.w;
259 
260     return result; 
261   }
262 
263   ///
264   Vector4 opUnary(string s)() const if (s == "-")
265   {
266     Vector4 result;
267     result.x = -x;
268     result.y = -y;
269     result.z = -z;
270     result.w = -w;
271 
272     return result;
273   }
274 
275   ///
276   Vector4 opMul(Vector4 vector) const
277   {
278     Vector4 result;
279     result.x = x * vector.x;
280     result.y = y * vector.y;
281     result.z = z * vector.z;
282     result.w = w * vector.w;
283 
284     return result; 
285   }
286 
287   ///
288   Vector4 opMul(float a) const
289   {
290     Vector4 result;
291     result.x = x * a;
292     result.y = y * a;
293     result.z = z * a;
294     result.w = w * a;
295 
296     return result; 
297   }
298 
299   ///
300   Vector4 opDiv(Vector4 vector)
301   {
302     Vector4 result;
303     result.x = x / vector.x;
304     result.y = y / vector.y;
305     result.z = z / vector.z;
306     result.w = w / vector.w;
307 
308     return result;
309   }
310 
311   ///
312   Vector4 opDiv(float a) const
313   {
314     Vector4 result;
315     result.x = x / a;
316     result.y = y / a;
317     result.z = z / a;
318     result.w = w / a;
319 
320     return result; 
321   }
322 
323   ///
324   void opAssign(Vector2 vector)
325   {
326     x = vector.x;
327     y = vector.y;
328     z = 0;
329     w = 0;
330   }
331 
332   ///
333   void opAssign(Vector3 vector)
334   {
335     x = vector.x;
336     y = vector.y;
337     z = vector.z;
338     w = 0;
339   }
340 }