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(float a)
161   {
162     x *= a;
163     y *= a;
164 
165     return this;
166   }
167 
168   Vector2 opDivAssign(float a)
169   {
170     x /= a;
171     y /= a;
172 
173     return this;
174   }
175 
176 
177   // arithmetic overloading
178   Vector2 opAdd(Vector2 vector) const
179   {
180     Vector2 result;
181     result.x = x + vector.x;
182     result.y = y + vector.y;
183 
184     return result;
185   }
186 
187   Vector3 opAdd(Vector3 vector) const
188   {
189     Vector3 result;
190     result.x = x + vector.x;
191     result.y = y + vector.y;
192     result.z = vector.z;
193 
194     return vector;
195   }
196 
197   Vector2 opSub(Vector2 vector) const
198   {
199     Vector2 result;
200     result.x = x - vector.x;
201     result.y = y - vector.y;
202 
203     return result; 
204   }
205 
206   Vector3 opSub(Vector3 vector) const
207   {
208     Vector3 result;
209     result.x = x - vector.x;
210     result.y = y - vector.y;
211     result.z = vector.z;
212 
213     return result; 
214   }
215 
216   Vector2 opUnary(string s)() const if (s == "-")
217   {
218     Vector2 result;
219     result.x = -x;
220     result.y = -y;
221 
222     return result;
223   }
224 
225   Vector2 opMul(float a) const
226   {
227     Vector2 result;
228     result.x = x * a;
229     result.y = y * a;
230 
231     return result; 
232   }
233 
234   Vector2 opDiv(float a) const
235   {
236     Vector2 result;
237     result.x = x / a;
238     result.y = y / a;
239 
240     return result; 
241   }
242 }