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