1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "Prerequisites/BsPrerequisitesUtil.h"
6#include "Math/BsMath.h"
7
8namespace bs
9{
10 /** @addtogroup Math
11 * @{
12 */
13
14 /** A two dimensional vector. */
15 class BS_UTILITY_EXPORT Vector2
16 {
17 public:
18 float x, y;
19
20 public:
21 Vector2() = default;
22
23 constexpr Vector2(BS_ZERO)
24 :x(0.0f), y(0.0f)
25 { }
26
27 constexpr Vector2(float x, float y)
28 :x(x), y(y)
29 { }
30
31 /** Exchange the contents of this vector with another. */
32 void swap(Vector2& other)
33 {
34 std::swap(x, other.x);
35 std::swap(y, other.y);
36 }
37
38 float operator[] (UINT32 i) const
39 {
40 assert(i < 2);
41
42 return *(&x+i);
43 }
44
45 float& operator[] (UINT32 i)
46 {
47 assert(i < 2);
48
49 return *(&x+i);
50 }
51
52 /** Pointer accessor for direct copying. */
53 float* ptr()
54 {
55 return &x;
56 }
57
58 /** Pointer accessor for direct copying. */
59 const float* ptr() const
60 {
61 return &x;
62 }
63
64 Vector2& operator= (float rhs)
65 {
66 x = rhs;
67 y = rhs;
68
69 return *this;
70 }
71
72 bool operator== (const Vector2& rhs) const
73 {
74 return (x == rhs.x && y == rhs.y);
75 }
76
77 bool operator!= (const Vector2& rhs) const
78 {
79 return (x != rhs.x || y != rhs.y);
80 }
81
82 Vector2 operator+ (const Vector2& rhs) const
83 {
84 return Vector2(x + rhs.x, y + rhs.y);
85 }
86
87 Vector2 operator- (const Vector2& rhs) const
88 {
89 return Vector2(x - rhs.x, y - rhs.y);
90 }
91
92 Vector2 operator* (const float rhs) const
93 {
94 return Vector2(x * rhs, y * rhs);
95 }
96
97 Vector2 operator* (const Vector2& rhs) const
98 {
99 return Vector2(x * rhs.x, y * rhs.y);
100 }
101
102 Vector2 operator/ (const float rhs) const
103 {
104 assert(rhs != 0.0);
105
106 float fInv = 1.0f / rhs;
107
108 return Vector2(x * fInv, y * fInv);
109 }
110
111 Vector2 operator/ (const Vector2& rhs) const
112 {
113 return Vector2(x / rhs.x, y / rhs.y);
114 }
115
116 const Vector2& operator+ () const
117 {
118 return *this;
119 }
120
121 Vector2 operator- () const
122 {
123 return Vector2(-x, -y);
124 }
125
126 friend Vector2 operator* (float lhs, const Vector2& rhs)
127 {
128 return Vector2(lhs * rhs.x, lhs * rhs.y);
129 }
130
131 friend Vector2 operator/ (float lhs, const Vector2& rhs)
132 {
133 return Vector2(lhs / rhs.x, lhs / rhs.y);
134 }
135
136 friend Vector2 operator+ (Vector2& lhs, float rhs)
137 {
138 return Vector2(lhs.x + rhs, lhs.y + rhs);
139 }
140
141 friend Vector2 operator+ (float lhs, const Vector2& rhs)
142 {
143 return Vector2(lhs + rhs.x, lhs + rhs.y);
144 }
145
146 friend Vector2 operator- (const Vector2& lhs, float rhs)
147 {
148 return Vector2(lhs.x - rhs, lhs.y - rhs);
149 }
150
151 friend Vector2 operator- (const float lhs, const Vector2& rhs)
152 {
153 return Vector2(lhs - rhs.x, lhs - rhs.y);
154 }
155
156 Vector2& operator+= (const Vector2& rhs)
157 {
158 x += rhs.x;
159 y += rhs.y;
160
161 return *this;
162 }
163
164 Vector2& operator+= (float rhs)
165 {
166 x += rhs;
167 y += rhs;
168
169 return *this;
170 }
171
172 Vector2& operator-= (const Vector2& rhs)
173 {
174 x -= rhs.x;
175 y -= rhs.y;
176
177 return *this;
178 }
179
180 Vector2& operator-= (float rhs)
181 {
182 x -= rhs;
183 y -= rhs;
184
185 return *this;
186 }
187
188 Vector2& operator*= (float rhs)
189 {
190 x *= rhs;
191 y *= rhs;
192
193 return *this;
194 }
195
196 Vector2& operator*= (const Vector2& rhs)
197 {
198 x *= rhs.x;
199 y *= rhs.y;
200
201 return *this;
202 }
203
204 Vector2& operator/= (float rhs)
205 {
206 assert(rhs != 0.0f);
207
208 float inv = 1.0f / rhs;
209
210 x *= inv;
211 y *= inv;
212
213 return *this;
214 }
215
216 Vector2& operator/= (const Vector2& rhs)
217 {
218 x /= rhs.x;
219 y /= rhs.y;
220
221 return *this;
222 }
223
224 /** Returns the length (magnitude) of the vector. */
225 float length() const
226 {
227 return Math::sqrt(x * x + y * y);
228 }
229
230 /** Returns the square of the length(magnitude) of the vector. */
231 float squaredLength() const
232 {
233 return x * x + y * y;
234 }
235
236 /** Returns the distance to another vector. */
237 float distance(const Vector2& rhs) const
238 {
239 return (*this - rhs).length();
240 }
241
242 /** Returns the square of the distance to another vector. */
243 float sqrdDistance(const Vector2& rhs) const
244 {
245 return (*this - rhs).squaredLength();
246 }
247
248 /** Calculates the dot (scalar) product of this vector with another. */
249 float dot(const Vector2& vec) const
250 {
251 return x * vec.x + y * vec.y;
252 }
253
254 /** Normalizes the vector. */
255 float normalize()
256 {
257 float len = Math::sqrt(x * x + y * y);
258
259 // Will also work for zero-sized vectors, but will change nothing
260 if (len > 1e-08f)
261 {
262 float invLen = 1.0f / len;
263 x *= invLen;
264 y *= invLen;
265 }
266
267 return len;
268 }
269
270 /** Generates a vector perpendicular to this vector. */
271 Vector2 perpendicular() const
272 {
273 return Vector2 (-y, x);
274 }
275
276 /**
277 * Calculates the 2 dimensional cross-product of 2 vectors, which results in a single floating point value which
278 * is 2 times the area of the triangle.
279 */
280 float cross(const Vector2& other) const
281 {
282 return x * other.y - y * other.x;
283 }
284
285 /** Sets this vector's components to the minimum of its own and the ones of the passed in vector. */
286 void floor(const Vector2& cmp)
287 {
288 if(cmp.x < x) x = cmp.x;
289 if(cmp.y < y) y = cmp.y;
290 }
291
292 /** Sets this vector's components to the maximum of its own and the ones of the passed in vector. */
293 void ceil(const Vector2& cmp)
294 {
295 if(cmp.x > x) x = cmp.x;
296 if(cmp.y > y) y = cmp.y;
297 }
298
299 /** Returns true if this vector is zero length. */
300 bool isZeroLength() const
301 {
302 float sqlen = (x * x) + (y * y);
303 return (sqlen < (1e-06f * 1e-06f));
304 }
305
306 /** Calculates a reflection vector to the plane with the given normal. */
307 Vector2 reflect(const Vector2& normal) const
308 {
309 return Vector2(*this - (2 * this->dot(normal) * normal));
310 }
311
312 /** Performs Gram-Schmidt orthonormalization. */
313 static void orthonormalize(Vector2& u, Vector2& v)
314 {
315 u.normalize();
316
317 float dot = u.dot(v);
318 v -= u*dot;
319 v.normalize();
320 }
321
322 /** Normalizes the provided vector and returns a new normalized instance. */
323 static Vector2 normalize(const Vector2& val)
324 {
325 float len = Math::sqrt(val.x * val.x + val.y * val.y);
326
327 // Will also work for zero-sized vectors, but will change nothing
328 Vector2 normalizedVec = val;
329 if (len > 1e-08f)
330 {
331 float invLen = 1.0f / len;
332 normalizedVec.x *= invLen;
333 normalizedVec.y *= invLen;
334 }
335
336 return normalizedVec;
337 }
338
339 /** Checks are any of the vector components NaN. */
340 bool isNaN() const
341 {
342 return Math::isNaN(x) || Math::isNaN(y);
343 }
344
345 /** Returns the minimum of all the vector components as a new vector. */
346 static Vector2 min(const Vector2& a, const Vector2& b)
347 {
348 return Vector2(std::min(a.x, b.x), std::min(a.y, b.y));
349 }
350
351 /** Returns the maximum of all the vector components as a new vector. */
352 static Vector2 max(const Vector2& a, const Vector2& b)
353 {
354 return Vector2(std::max(a.x, b.x), std::max(a.y, b.y));
355 }
356
357 static const Vector2 ZERO;
358 static const Vector2 ONE;
359 static const Vector2 UNIT_X;
360 static const Vector2 UNIT_Y;
361 };
362
363 /** @} */
364
365 /** @cond SPECIALIZATIONS */
366 BS_ALLOW_MEMCPY_SERIALIZATION(Vector2);
367 /** @endcond */
368}
369