Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_vector2.hpp
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <cstdint>
6#include <initializer_list>
7#include <iostream>
8#include <sstream>
9#include <stdexcept>
10#include <string>
11#include <type_traits>
12
13#include "structure/math/spk_safe_comparand.hpp"
14
15namespace spk
16{
33 template <typename TType>
34 struct IVector2
35 {
39 using value_type = TType;
40
44 TType x{};
48 TType y{};
49
53 constexpr IVector2() = default;
54
60 template <typename TX, typename TY>
61 requires(std::is_constructible_v<TType, TX> && std::is_constructible_v<TType, TY>)
62 constexpr IVector2(const TX &p_x, const TY &p_y) :
63 x(static_cast<TType>(p_x)),
64 y(static_cast<TType>(p_y))
65 {
66 }
67
73 template <typename TOther>
74 requires std::is_constructible_v<TType, TOther>
75 explicit constexpr IVector2(const IVector2<TOther> &p_other) :
76 x(static_cast<TType>(p_other.x)),
77 y(static_cast<TType>(p_other.y))
78 {
79 }
80
85 template <typename TOther>
86 requires std::is_constructible_v<TType, TOther>
87 explicit constexpr IVector2(const TOther &p_value) :
88 x(static_cast<TType>(p_value)),
89 y(static_cast<TType>(p_value))
90 {
91 }
92
96 static const IVector2 Zero;
100 static const IVector2 One;
101
106 std::string toString() const
107 {
108 std::ostringstream stream;
109 stream << *this;
110 return stream.str();
111 }
112
117 std::wstring toWstring() const
118 {
119 std::wostringstream stream;
120 stream << *this;
121 return stream.str();
122 }
123
130 friend std::ostream &operator<<(std::ostream &p_stream, const IVector2 &p_value)
131 {
132 p_stream << '(' << p_value.x << ", " << p_value.y << ')';
133 return p_stream;
134 }
135
142 friend std::wostream &operator<<(std::wostream &p_stream, const IVector2 &p_value)
143 {
144 p_stream << L'(' << p_value.x << L", " << p_value.y << L')';
145 return p_stream;
146 }
147
154 bool operator==(const IVector2 &p_other) const
155 {
156 return spk::SafeComparand(x) == p_other.x &&
157 spk::SafeComparand(y) == p_other.y;
158 }
159
166 bool operator!=(const IVector2 &p_other) const
167 {
168 return !(*this == p_other);
169 }
170
176 IVector2 operator+(const IVector2 &p_other) const
177 {
178 return IVector2(x + p_other.x, y + p_other.y);
179 }
180
186 IVector2 operator-(const IVector2 &p_other) const
187 {
188 return IVector2(x - p_other.x, y - p_other.y);
189 }
190
196 IVector2 operator*(const IVector2 &p_other) const
197 {
198 return IVector2(x * p_other.x, y * p_other.y);
199 }
200
207 IVector2 operator/(const IVector2 &p_other) const
208 {
209 if (spk::SafeComparand(p_other.x) == 0 ||
210 spk::SafeComparand(p_other.y) == 0)
211 {
212 throw std::invalid_argument("Can't divide by 0");
213 }
214 return IVector2(x / p_other.x, y / p_other.y);
215 }
216
222 IVector2 operator+(const TType &p_scalar) const
223 {
224 return IVector2(x + p_scalar, y + p_scalar);
225 }
226
232 IVector2 operator-(const TType &p_scalar) const
233 {
234 return IVector2(x - p_scalar, y - p_scalar);
235 }
236
242 IVector2 operator*(const TType &p_scalar) const
243 {
244 return IVector2(x * p_scalar, y * p_scalar);
245 }
246
253 IVector2 operator/(const TType &p_scalar) const
254 {
255 if (spk::SafeComparand(p_scalar) == 0)
256 {
257 throw std::invalid_argument("Can't divide by 0");
258 }
259 return IVector2(x / p_scalar, y / p_scalar);
260 }
261
269 friend IVector2 operator+(const TType &p_scalar, const IVector2 &p_vector)
270 {
271 return p_vector + p_scalar;
272 }
273
280 friend IVector2 operator-(const TType &p_scalar, const IVector2 &p_vector)
281 {
282 return IVector2(p_scalar - p_vector.x, p_scalar - p_vector.y);
283 }
284
292 friend IVector2 operator*(const TType &p_scalar, const IVector2 &p_vector)
293 {
294 return p_vector * p_scalar;
295 }
296
304 friend IVector2 operator/(const TType &p_scalar, const IVector2 &p_vector)
305 {
306 if (spk::SafeComparand(p_vector.x) == 0 ||
307 spk::SafeComparand(p_vector.y) == 0)
308 {
309 throw std::invalid_argument("Can't divide by 0");
310 }
311 return IVector2(p_scalar / p_vector.x, p_scalar / p_vector.y);
312 }
313
319 {
320 return IVector2(-x, -y);
321 }
322
328 {
329 return inverse();
330 }
331
338 IVector2 &operator+=(const IVector2 &p_other)
339 {
340 x += p_other.x;
341 y += p_other.y;
342 return *this;
343 }
344
351 IVector2 &operator-=(const IVector2 &p_other)
352 {
353 x -= p_other.x;
354 y -= p_other.y;
355 return *this;
356 }
357
364 IVector2 &operator*=(const IVector2 &p_other)
365 {
366 x *= p_other.x;
367 y *= p_other.y;
368 return *this;
369 }
370
378 IVector2 &operator/=(const IVector2 &p_other)
379 {
380 if (spk::SafeComparand(p_other.x) == 0 ||
381 spk::SafeComparand(p_other.y) == 0)
382 {
383 throw std::invalid_argument("Can't divide by 0");
384 }
385 x /= p_other.x;
386 y /= p_other.y;
387 return *this;
388 }
389
396 IVector2 &operator+=(const TType &p_scalar)
397 {
398 x += p_scalar;
399 y += p_scalar;
400 return *this;
401 }
402
409 IVector2 &operator-=(const TType &p_scalar)
410 {
411 x -= p_scalar;
412 y -= p_scalar;
413 return *this;
414 }
415
422 IVector2 &operator*=(const TType &p_scalar)
423 {
424 x *= p_scalar;
425 y *= p_scalar;
426 return *this;
427 }
428
436 IVector2 &operator/=(const TType &p_scalar)
437 {
438 if (spk::SafeComparand(p_scalar) == 0)
439 {
440 throw std::invalid_argument("Can't divide by 0");
441 }
442 x /= p_scalar;
443 y /= p_scalar;
444 return *this;
445 }
446
451 bool isZero() const
452 {
453 return spk::SafeComparand(x) == 0 &&
454 spk::SafeComparand(y) == 0;
455 }
456
462 float squaredLength() const
463 {
464 const auto px = static_cast<float>(x);
465 const auto py = static_cast<float>(y);
466 return (px * px) + (py * py);
467 }
468
475 {
476 float baseSquareLenght = squaredLength();
477
478 if (spk::SafeComparand(baseSquareLenght) == 0)
479 {
480 throw std::runtime_error("Can't normilize a vector of norm == 0");
481 }
482 return (this->operator/(std::sqrt(baseSquareLenght)));
483 }
484
490 float length() const
491 {
492 return static_cast<float>(std::sqrt(static_cast<double>(squaredLength())));
493 }
494
501 float squaredDistance(const IVector2 &p_other) const
502 {
503 return (*this - p_other).squaredLength();
504 }
505
512 float distance(const IVector2 &p_other) const
513 {
514 return (*this - p_other).length();
515 }
516
523 float dot(const IVector2 &p_other) const
524 {
525 const auto px = static_cast<float>(x);
526 const auto py = static_cast<float>(y);
527 return (px * static_cast<float>(p_other.x)) +
528 (py * static_cast<float>(p_other.y));
529 }
530
537 float cross(const IVector2 &p_other) const
538 {
539 return (static_cast<float>(x) * static_cast<float>(p_other.y)) -
540 (static_cast<float>(y) * static_cast<float>(p_other.x));
541 }
542
548 {
549 return IVector2(-y, x);
550 }
551
566 static IVector2 lerp(const IVector2 &p_from, const IVector2 &p_to, const float &p_alpha)
567 {
568 const auto startX = static_cast<float>(p_from.x);
569 const auto startY = static_cast<float>(p_from.y);
570 const auto deltaX = static_cast<float>(p_to.x) - startX;
571 const auto deltaY = static_cast<float>(p_to.y) - startY;
572 return IVector2(
573 static_cast<TType>(startX + (deltaX * p_alpha)),
574 static_cast<TType>(startY + (deltaY * p_alpha)));
575 }
576
584 static IVector2 min(const IVector2 &p_a, const IVector2 &p_b)
585 {
586 return IVector2(
587 std::min(p_a.x, p_b.x),
588 std::min(p_a.y, p_b.y));
589 }
590
600 template <typename... TOthers>
601 requires(sizeof...(TOthers) > 0 && (std::is_same_v<TOthers, IVector2> && ...))
602 static IVector2 min(const IVector2 &p_a, const IVector2 &p_b, const TOthers &...p_rest)
603 {
604 return min(min(p_a, p_b), p_rest...);
605 }
606
613 static IVector2 min(std::initializer_list<IVector2> p_values)
614 {
615 if (p_values.size() == 0)
616 {
617 throw std::invalid_argument("IVector2::min requires at least one operand");
618 }
619
620 auto result = *p_values.begin();
621 for (auto it = std::next(p_values.begin()); it != p_values.end(); ++it)
622 {
623 result = min(result, *it);
624 }
625 return result;
626 }
627
635 static IVector2 max(const IVector2 &p_a, const IVector2 &p_b)
636 {
637 return IVector2(
638 std::max(p_a.x, p_b.x),
639 std::max(p_a.y, p_b.y));
640 }
641
650 template <typename... TOthers>
651 requires(sizeof...(TOthers) > 0 && (std::is_same_v<TOthers, IVector2> && ...))
652 static IVector2 max(const IVector2 &p_a, const IVector2 &p_b, const TOthers &...p_rest)
653 {
654 return max(max(p_a, p_b), p_rest...);
655 }
656
663 static IVector2 max(std::initializer_list<IVector2> p_values)
664 {
665 if (p_values.size() == 0)
666 {
667 throw std::invalid_argument("IVector2::max requires at least one operand");
668 }
669
670 auto result = *p_values.begin();
671 for (auto it = std::next(p_values.begin()); it != p_values.end(); ++it)
672 {
673 result = max(result, *it);
674 }
675 return result;
676 }
677
691 static IVector2 clamp(const IVector2 &p_value, const IVector2 &p_boundMinimum, const IVector2 &p_boundMaximum)
692 {
693 const IVector2 low(
694 std::min(p_boundMinimum.x, p_boundMaximum.x),
695 std::min(p_boundMinimum.y, p_boundMaximum.y));
696 const IVector2 high(
697 std::max(p_boundMinimum.x, p_boundMaximum.x),
698 std::max(p_boundMinimum.y, p_boundMaximum.y));
699
700 return IVector2(
701 std::clamp(p_value.x, low.x, high.x),
702 std::clamp(p_value.y, low.y, high.y));
703 }
704
712 IVector2 clamped(const IVector2 &p_boundMinimum, const IVector2 &p_boundMaximum) const
713 {
714 return clamp(*this, p_boundMinimum, p_boundMaximum);
715 }
716
726 static bool isBetween(const IVector2 &p_value, const IVector2 &p_valueA, const IVector2 &p_valueB)
727 {
728 return (p_value.x >= p_valueA.x && p_value.x <= p_valueB.x) &&
729 (p_value.y >= p_valueA.y && p_value.y <= p_valueB.y);
730 }
731
737 template <typename TOther>
738 requires std::is_constructible_v<TOther, TType>
739 explicit constexpr operator IVector2<TOther>() const
740 {
741 return IVector2<TOther>(
742 static_cast<TOther>(x),
743 static_cast<TOther>(y));
744 }
745 };
746
747 template <typename TType>
748 inline const IVector2<TType> IVector2<TType>::Zero{};
749
750 template <typename TType>
751 inline const IVector2<TType> IVector2<TType>::One{static_cast<TType>(1), static_cast<TType>(1)};
752
753 using Vector2 = IVector2<float_t>;
754 using Vector2Int = IVector2<int32_t>;
755 using Vector2UInt = IVector2<uint32_t>;
756}
2D value type holding two components with basic arithmetic helpers.
Definition spk_vector2.hpp:35
IVector2 operator/(const IVector2 &p_other) const
Component-wise division.
Definition spk_vector2.hpp:207
IVector2 & operator-=(const TType &p_scalar)
In-place scalar subtraction.
Definition spk_vector2.hpp:409
static IVector2 max(std::initializer_list< IVector2 > p_values)
Component-wise maximum across an initializer list.
Definition spk_vector2.hpp:663
bool operator!=(const IVector2 &p_other) const
Negation of equality.
Definition spk_vector2.hpp:166
IVector2 inverse() const
Return the inverse vector.
Definition spk_vector2.hpp:318
constexpr IVector2(const IVector2< TOther > &p_other)
Converting constructor from another component type.
Definition spk_vector2.hpp:75
friend IVector2 operator+(const TType &p_scalar, const IVector2 &p_vector)
Adds a scalar to a vector (scalar on the left side).
Definition spk_vector2.hpp:269
friend std::wostream & operator<<(std::wostream &p_stream, const IVector2 &p_value)
Streams the vector to a wide output stream.
Definition spk_vector2.hpp:142
IVector2 operator+(const IVector2 &p_other) const
Component-wise addition.
Definition spk_vector2.hpp:176
friend IVector2 operator*(const TType &p_scalar, const IVector2 &p_vector)
Multiplies a scalar by a vector (scalar on the left side).
Definition spk_vector2.hpp:292
std::wstring toWstring() const
Converts the vector to a wide string.
Definition spk_vector2.hpp:117
IVector2 operator/(const TType &p_scalar) const
Divides each component by a scalar.
Definition spk_vector2.hpp:253
IVector2 operator*(const TType &p_scalar) const
Multiplies each component by a scalar.
Definition spk_vector2.hpp:242
IVector2 & operator*=(const IVector2 &p_other)
In-place component-wise multiplication.
Definition spk_vector2.hpp:364
static IVector2 max(const IVector2 &p_a, const IVector2 &p_b)
Component-wise maximum of two vectors.
Definition spk_vector2.hpp:635
float squaredDistance(const IVector2 &p_other) const
Computes squared distance to another vector.
Definition spk_vector2.hpp:501
IVector2 operator-(const TType &p_scalar) const
Subtracts a scalar from each component.
Definition spk_vector2.hpp:232
IVector2 operator+(const TType &p_scalar) const
Adds a scalar to each component.
Definition spk_vector2.hpp:222
IVector2 operator-(const IVector2 &p_other) const
Component-wise subtraction.
Definition spk_vector2.hpp:186
IVector2 clamped(const IVector2 &p_boundMinimum, const IVector2 &p_boundMaximum) const
Returns a clamped copy of this vector.
Definition spk_vector2.hpp:712
constexpr IVector2()=default
Builds a zero vector.
float cross(const IVector2 &p_other) const
Computes 2D cross product (x1*y2 - y1*x2).
Definition spk_vector2.hpp:537
IVector2 & operator+=(const IVector2 &p_other)
In-place component-wise addition.
Definition spk_vector2.hpp:338
IVector2 perpendicular() const
Returns a perpendicular vector (rotated 90 degrees).
Definition spk_vector2.hpp:547
IVector2 & operator/=(const TType &p_scalar)
In-place scalar division.
Definition spk_vector2.hpp:436
IVector2 & operator/=(const IVector2 &p_other)
In-place component-wise division.
Definition spk_vector2.hpp:378
static IVector2 clamp(const IVector2 &p_value, const IVector2 &p_boundMinimum, const IVector2 &p_boundMaximum)
Clamps each component of a vector between two bounds.
Definition spk_vector2.hpp:691
float_t x
Definition spk_vector2.hpp:44
static IVector2 min(const IVector2 &p_a, const IVector2 &p_b)
Component-wise minimum of two vectors.
Definition spk_vector2.hpp:584
constexpr IVector2(const TX &p_x, const TY &p_y)
Builds a vector from two components.
Definition spk_vector2.hpp:62
float distance(const IVector2 &p_other) const
Computes Euclidean distance to another vector.
Definition spk_vector2.hpp:512
bool isZero() const
Checks if both components are zero.
Definition spk_vector2.hpp:451
static IVector2 lerp(const IVector2 &p_from, const IVector2 &p_to, const float &p_alpha)
Linearly interpolates between two vectors.
Definition spk_vector2.hpp:566
IVector2 & operator*=(const TType &p_scalar)
In-place scalar multiplication.
Definition spk_vector2.hpp:422
friend IVector2 operator/(const TType &p_scalar, const IVector2 &p_vector)
Divides a scalar by each vector component (scalar on the left side).
Definition spk_vector2.hpp:304
TType value_type
Component type stored by the vector.
Definition spk_vector2.hpp:39
IVector2 & operator-=(const IVector2 &p_other)
In-place component-wise subtraction.
Definition spk_vector2.hpp:351
std::string toString() const
Converts the vector to a string.
Definition spk_vector2.hpp:106
float length() const
Computes Euclidean length.
Definition spk_vector2.hpp:490
static const IVector2 Zero
Definition spk_vector2.hpp:96
IVector2 & operator+=(const TType &p_scalar)
In-place scalar addition.
Definition spk_vector2.hpp:396
bool operator==(const IVector2 &p_other) const
Checks component-wise equality using SafeComparand.
Definition spk_vector2.hpp:154
static const IVector2 One
Definition spk_vector2.hpp:100
IVector2 operator-() const
Unary minus.
Definition spk_vector2.hpp:327
float squaredLength() const
Computes squared vector length.
Definition spk_vector2.hpp:462
friend IVector2 operator-(const TType &p_scalar, const IVector2 &p_vector)
Subtracts vector components from a scalar (scalar on the left side).
Definition spk_vector2.hpp:280
static bool isBetween(const IVector2 &p_value, const IVector2 &p_valueA, const IVector2 &p_valueB)
Checks whether a vector lies within inclusive bounds.
Definition spk_vector2.hpp:726
float dot(const IVector2 &p_other) const
Computes dot product with another vector.
Definition spk_vector2.hpp:523
IVector2 operator*(const IVector2 &p_other) const
Component-wise multiplication.
Definition spk_vector2.hpp:196
float_t y
Definition spk_vector2.hpp:48
friend std::ostream & operator<<(std::ostream &p_stream, const IVector2 &p_value)
Streams the vector to an output stream.
Definition spk_vector2.hpp:130
static IVector2 min(std::initializer_list< IVector2 > p_values)
Component-wise minimum across an initializer list.
Definition spk_vector2.hpp:613
constexpr IVector2(const TOther &p_value)
Fills both components with the same value.
Definition spk_vector2.hpp:87
IVector2< float > normalize() const
Return the vector once normalized by its length.
Definition spk_vector2.hpp:474
Wraps arithmetic values to compare with tolerance for floating-point inputs.
Definition spk_safe_comparand.hpp:17