1 module prova.math.vector2;
2 
3 import prova.math,
4        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),
32       randomF(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)
138   {
139     return x * vector.x + y * vector.y;
140   }
141 
142 
143   // assignment overloading
144   Vector2 opAddAssign(Vector2 vector)
145   {
146     x += vector.x;
147     y += vector.y;
148 
149     return this;
150   }
151 
152   Vector2 opSubAssign(Vector2 vector)
153   {
154     x -= vector.x;
155     y -= vector.y;
156 
157     return this;
158   }
159 
160   Vector2 opMulAssign(Vector2 vector)
161   {
162     x *= vector.x;
163     y *= vector.y;
164 
165     return this;
166   }
167 
168   Vector2 opMulAssign(float a)
169   {
170     x *= a;
171     y *= a;
172 
173     return this;
174   }
175 
176   Vector2 opDivAssign(float a)
177   {
178     x /= a;
179     y /= a;
180 
181     return this;
182   }
183 
184 
185   // arithmetic overloading
186   Vector2 opAdd(Vector2 vector) const
187   {
188     Vector2 result;
189     result.x = x + vector.x;
190     result.y = y + vector.y;
191 
192     return result;
193   }
194 
195   Vector3 opAdd(Vector3 vector) const
196   {
197     Vector3 result;
198     result.x = x + vector.x;
199     result.y = y + vector.y;
200     result.z = vector.z;
201 
202     return vector;
203   }
204 
205   Vector2 opSub(Vector2 vector) const
206   {
207     Vector2 result;
208     result.x = x - vector.x;
209     result.y = y - vector.y;
210 
211     return result; 
212   }
213 
214   Vector3 opSub(Vector3 vector) const
215   {
216     Vector3 result;
217     result.x = x - vector.x;
218     result.y = y - vector.y;
219     result.z = vector.z;
220 
221     return result; 
222   }
223 
224   Vector2 opUnary(string s)() const if (s == "-")
225   {
226     Vector2 result;
227     result.x = -x;
228     result.y = -y;
229 
230     return result;
231   }
232 
233   Vector2 opMul(Vector2 vector) const
234   {
235     Vector2 result;
236     result.x = x * vector.x;
237     result.y = y * vector.y;
238 
239     return result; 
240   }
241 
242   Vector2 opMul(float a) const
243   {
244     Vector2 result;
245     result.x = x * a;
246     result.y = y * a;
247 
248     return result; 
249   }
250 
251   Vector2 opDiv(float a) const
252   {
253     Vector2 result;
254     result.x = x / a;
255     result.y = y / a;
256 
257     return result; 
258   }
259 }