Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_vector3.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
15#include "structure/math/spk_vector2.hpp"
16
17namespace spk
18{
32 template <typename TType>
33 struct IVector3
34 {
38 using value_type = TType;
39
43 TType x{};
47 TType y{};
51 TType z{};
52
56 constexpr IVector3() = default;
57
64 template <typename TX, typename TY, typename TZ>
65 requires(std::is_constructible_v<TType, TX> && std::is_constructible_v<TType, TY> &&
66 std::is_constructible_v<TType, TZ>)
67 constexpr IVector3(const TX &p_x, const TY &p_y, const TZ &p_z) :
68 x(static_cast<TType>(p_x)),
69 y(static_cast<TType>(p_y)),
70 z(static_cast<TType>(p_z))
71 {
72 }
73
81 template <typename TOtherVector, typename TZ>
82 requires(std::is_constructible_v<TType, TOtherVector> && std::is_constructible_v<TType, TZ>)
83 constexpr IVector3(const IVector2<TOtherVector> &p_other, const TZ &p_z) :
84 x(static_cast<TType>(p_other.x)),
85 y(static_cast<TType>(p_other.y)),
86 z(static_cast<TType>(p_z))
87 {
88 }
89
95 template <typename TOther>
96 requires std::is_constructible_v<TType, TOther>
97 explicit constexpr IVector3(const IVector3<TOther> &p_other) :
98 x(static_cast<TType>(p_other.x)),
99 y(static_cast<TType>(p_other.y)),
100 z(static_cast<TType>(p_other.z))
101 {
102 }
103
108 template <typename TOther>
109 requires std::is_constructible_v<TType, TOther>
110 explicit constexpr IVector3(const TOther &p_value) :
111 x(static_cast<TType>(p_value)),
112 y(static_cast<TType>(p_value)),
113 z(static_cast<TType>(p_value))
114 {
115 }
116
120 static const IVector3 Zero;
124 static const IVector3 One;
125
130 std::string toString() const
131 {
132 std::ostringstream stream;
133 stream << *this;
134 return stream.str();
135 }
136
141 std::wstring toWstring() const
142 {
143 std::wostringstream stream;
144 stream << *this;
145 return stream.str();
146 }
147
154 friend std::ostream &operator<<(std::ostream &p_stream, const IVector3 &p_value)
155 {
156 p_stream << '(' << p_value.x << ", " << p_value.y << ", " << p_value.z << ')';
157 return p_stream;
158 }
159
166 friend std::wostream &operator<<(std::wostream &p_stream, const IVector3 &p_value)
167 {
168 p_stream << L'(' << p_value.x << L", " << p_value.y << L", " << p_value.z << L')';
169 return p_stream;
170 }
171
177 bool operator==(const IVector3 &p_other) const
178 {
179 return spk::SafeComparand(x) == p_other.x &&
180 spk::SafeComparand(y) == p_other.y &&
181 spk::SafeComparand(z) == p_other.z;
182 }
183
190 bool operator!=(const IVector3 &p_other) const
191 {
192 return !(*this == p_other);
193 }
194
200 IVector3 operator+(const IVector3 &p_other) const
201 {
202 return IVector3(x + p_other.x, y + p_other.y, z + p_other.z);
203 }
204
210 IVector3 operator-(const IVector3 &p_other) const
211 {
212 return IVector3(x - p_other.x, y - p_other.y, z - p_other.z);
213 }
214
220 IVector3 operator*(const IVector3 &p_other) const
221 {
222 return IVector3(x * p_other.x, y * p_other.y, z * p_other.z);
223 }
224
231 IVector3 operator/(const IVector3 &p_other) const
232 {
233 if (spk::SafeComparand(p_other.x) == 0 ||
234 spk::SafeComparand(p_other.y) == 0 ||
235 spk::SafeComparand(p_other.z) == 0)
236 {
237 throw std::invalid_argument("Can't divide by 0");
238 }
239 return IVector3(x / p_other.x, y / p_other.y, z / p_other.z);
240 }
241
247 IVector3 operator+(const TType &p_scalar) const
248 {
249 return IVector3(x + p_scalar, y + p_scalar, z + p_scalar);
250 }
251
257 IVector3 operator-(const TType &p_scalar) const
258 {
259 return IVector3(x - p_scalar, y - p_scalar, z - p_scalar);
260 }
261
267 IVector3 operator*(const TType &p_scalar) const
268 {
269 return IVector3(x * p_scalar, y * p_scalar, z * p_scalar);
270 }
271
278 IVector3 operator/(const TType &p_scalar) const
279 {
280 if (spk::SafeComparand(p_scalar) == 0)
281 {
282 throw std::invalid_argument("Can't divide by 0");
283 }
284 return IVector3(x / p_scalar, y / p_scalar, z / p_scalar);
285 }
286
294 friend IVector3 operator+(const TType &p_scalar, const IVector3 &p_vector)
295 {
296 return p_vector + p_scalar;
297 }
298
305 friend IVector3 operator-(const TType &p_scalar, const IVector3 &p_vector)
306 {
307 return IVector3(p_scalar - p_vector.x, p_scalar - p_vector.y, p_scalar - p_vector.z);
308 }
309
317 friend IVector3 operator*(const TType &p_scalar, const IVector3 &p_vector)
318 {
319 return p_vector * p_scalar;
320 }
321
329 friend IVector3 operator/(const TType &p_scalar, const IVector3 &p_vector)
330 {
331 if (spk::SafeComparand(p_vector.x) == 0 ||
332 spk::SafeComparand(p_vector.y) == 0 ||
333 spk::SafeComparand(p_vector.z) == 0)
334 {
335 throw std::invalid_argument("Can't divide by 0");
336 }
337 return IVector3(p_scalar / p_vector.x, p_scalar / p_vector.y, p_scalar / p_vector.z);
338 }
339
345 {
346 return IVector3(-x, -y, -z);
347 }
348
354 {
355 return inverse();
356 }
357
364 IVector3 &operator+=(const IVector3 &p_other)
365 {
366 x += p_other.x;
367 y += p_other.y;
368 z += p_other.z;
369 return *this;
370 }
371
378 IVector3 &operator-=(const IVector3 &p_other)
379 {
380 x -= p_other.x;
381 y -= p_other.y;
382 z -= p_other.z;
383 return *this;
384 }
385
392 IVector3 &operator*=(const IVector3 &p_other)
393 {
394 x *= p_other.x;
395 y *= p_other.y;
396 z *= p_other.z;
397 return *this;
398 }
399
407 IVector3 &operator/=(const IVector3 &p_other)
408 {
409 if (spk::SafeComparand(p_other.x) == 0 ||
410 spk::SafeComparand(p_other.y) == 0 ||
411 spk::SafeComparand(p_other.z) == 0)
412 {
413 throw std::invalid_argument("Can't divide by 0");
414 }
415 x /= p_other.x;
416 y /= p_other.y;
417 z /= p_other.z;
418 return *this;
419 }
420
427 IVector3 &operator+=(const TType &p_scalar)
428 {
429 x += p_scalar;
430 y += p_scalar;
431 z += p_scalar;
432 return *this;
433 }
434
441 IVector3 &operator-=(const TType &p_scalar)
442 {
443 x -= p_scalar;
444 y -= p_scalar;
445 z -= p_scalar;
446 return *this;
447 }
448
455 IVector3 &operator*=(const TType &p_scalar)
456 {
457 x *= p_scalar;
458 y *= p_scalar;
459 z *= p_scalar;
460 return *this;
461 }
462
470 IVector3 &operator/=(const TType &p_scalar)
471 {
472 if (spk::SafeComparand(p_scalar) == 0)
473 {
474 throw std::invalid_argument("Can't divide by 0");
475 }
476 x /= p_scalar;
477 y /= p_scalar;
478 z /= p_scalar;
479 return *this;
480 }
481
486 bool isZero() const
487 {
488 return spk::SafeComparand(x) == 0 &&
489 spk::SafeComparand(y) == 0 &&
490 spk::SafeComparand(z) == 0;
491 }
492
498 float squaredLength() const
499 {
500 const auto px = static_cast<float>(x);
501 const auto py = static_cast<float>(y);
502 const auto pz = static_cast<float>(z);
503 return (px * px) + (py * py) + (pz * pz);
504 }
505
511 float length() const
512 {
513 return static_cast<float>(std::sqrt(static_cast<double>(squaredLength())));
514 }
515
522 {
523 float baseSquareLenght = squaredLength();
524
525 if (spk::SafeComparand(baseSquareLenght) == 0)
526 {
527 throw std::runtime_error("Can't normilize a vector of norm == 0");
528 }
529 return (this->operator/(std::sqrt(baseSquareLenght)));
530 }
531
538 float squaredDistance(const IVector3 &p_other) const
539 {
540 return (*this - p_other).squaredLength();
541 }
542
549 float distance(const IVector3 &p_other) const
550 {
551 return (*this - p_other).length();
552 }
553
560 float dot(const IVector3 &p_other) const
561 {
562 const auto px = static_cast<float>(x);
563 const auto py = static_cast<float>(y);
564 const auto pz = static_cast<float>(z);
565 return (px * static_cast<float>(p_other.x)) +
566 (py * static_cast<float>(p_other.y)) +
567 (pz * static_cast<float>(p_other.z));
568 }
569
576 IVector3 cross(const IVector3 &p_other) const
577 {
578 const auto ax = static_cast<float>(x);
579 const auto ay = static_cast<float>(y);
580 const auto az = static_cast<float>(z);
581 const auto bx = static_cast<float>(p_other.x);
582 const auto by = static_cast<float>(p_other.y);
583 const auto bz = static_cast<float>(p_other.z);
584
585 return IVector3(
586 static_cast<TType>((ay * bz) - (az * by)),
587 static_cast<TType>((az * bx) - (ax * bz)),
588 static_cast<TType>((ax * by) - (ay * bx)));
589 }
590
596 {
597 return IVector2<TType>(x, y);
598 }
599
605 {
606 return IVector2<TType>(y, z);
607 }
608
624 template <typename TAlpha>
625 requires std::is_arithmetic_v<TAlpha>
626 static IVector3 lerp(const IVector3 &p_from, const IVector3 &p_to, const TAlpha &p_alpha)
627 {
628 const auto alpha = static_cast<float>(p_alpha);
629 const auto startX = static_cast<float>(p_from.x);
630 const auto startY = static_cast<float>(p_from.y);
631 const auto startZ = static_cast<float>(p_from.z);
632 const auto deltaX = static_cast<float>(p_to.x) - startX;
633 const auto deltaY = static_cast<float>(p_to.y) - startY;
634 const auto deltaZ = static_cast<float>(p_to.z) - startZ;
635 return IVector3(
636 static_cast<TType>(startX + (deltaX * alpha)),
637 static_cast<TType>(startY + (deltaY * alpha)),
638 static_cast<TType>(startZ + (deltaZ * alpha)));
639 }
640
648 static IVector3 min(const IVector3 &p_a, const IVector3 &p_b)
649 {
650 return IVector3(
651 std::min(p_a.x, p_b.x),
652 std::min(p_a.y, p_b.y),
653 std::min(p_a.z, p_b.z));
654 }
655
665 template <typename... TOthers>
666 requires(sizeof...(TOthers) > 0 && (std::is_same_v<TOthers, IVector3> && ...))
667 static IVector3 min(const IVector3 &p_a, const IVector3 &p_b, const TOthers &...p_rest)
668 {
669 return min(min(p_a, p_b), p_rest...);
670 }
671
678 static IVector3 min(std::initializer_list<IVector3> p_values)
679 {
680 if (p_values.size() == 0)
681 {
682 throw std::invalid_argument("IVector3::min requires at least one operand");
683 }
684
685 auto result = *p_values.begin();
686 for (auto it = std::next(p_values.begin()); it != p_values.end(); ++it)
687 {
688 result = min(result, *it);
689 }
690 return result;
691 }
692
700 static IVector3 max(const IVector3 &p_a, const IVector3 &p_b)
701 {
702 return IVector3(
703 std::max(p_a.x, p_b.x),
704 std::max(p_a.y, p_b.y),
705 std::max(p_a.z, p_b.z));
706 }
707
716 template <typename... TOthers>
717 requires(sizeof...(TOthers) > 0 && (std::is_same_v<TOthers, IVector3> && ...))
718 static IVector3 max(const IVector3 &p_a, const IVector3 &p_b, const TOthers &...p_rest)
719 {
720 return max(max(p_a, p_b), p_rest...);
721 }
722
729 static IVector3 max(std::initializer_list<IVector3> p_values)
730 {
731 if (p_values.size() == 0)
732 {
733 throw std::invalid_argument("IVector3::max requires at least one operand");
734 }
735
736 auto result = *p_values.begin();
737 for (auto it = std::next(p_values.begin()); it != p_values.end(); ++it)
738 {
739 result = max(result, *it);
740 }
741 return result;
742 }
743
752 static IVector3 clamp(const IVector3 &p_value, const IVector3 &p_boundA, const IVector3 &p_boundB)
753 {
754 const IVector3 low(
755 std::min(p_boundA.x, p_boundB.x),
756 std::min(p_boundA.y, p_boundB.y),
757 std::min(p_boundA.z, p_boundB.z));
758 const IVector3 high(
759 std::max(p_boundA.x, p_boundB.x),
760 std::max(p_boundA.y, p_boundB.y),
761 std::max(p_boundA.z, p_boundB.z));
762
763 return IVector3(
764 std::clamp(p_value.x, low.x, high.x),
765 std::clamp(p_value.y, low.y, high.y),
766 std::clamp(p_value.z, low.z, high.z));
767 }
768
776 IVector3 clamped(const IVector3 &p_boundA, const IVector3 &p_boundB) const
777 {
778 return clamp(*this, p_boundA, p_boundB);
779 }
780
789 static bool isBetween(const IVector3 &p_value, const IVector3 &p_boundA, const IVector3 &p_boundB)
790 {
791 const IVector3 low(
792 std::min(p_boundA.x, p_boundB.x),
793 std::min(p_boundA.y, p_boundB.y),
794 std::min(p_boundA.z, p_boundB.z));
795 const IVector3 high(
796 std::max(p_boundA.x, p_boundB.x),
797 std::max(p_boundA.y, p_boundB.y),
798 std::max(p_boundA.z, p_boundB.z));
799
800 return (p_value.x >= low.x && p_value.x <= high.x) &&
801 (p_value.y >= low.y && p_value.y <= high.y) &&
802 (p_value.z >= low.z && p_value.z <= high.z);
803 }
804
810 template <typename TOther>
811 requires std::is_constructible_v<TOther, TType>
812 explicit constexpr operator IVector3<TOther>() const
813 {
814 return IVector3<TOther>(
815 static_cast<TOther>(x),
816 static_cast<TOther>(y),
817 static_cast<TOther>(z));
818 }
819 };
820
821 template <typename TType>
822 inline const IVector3<TType> IVector3<TType>::Zero{};
823
824 template <typename TType>
826 static_cast<TType>(1),
827 static_cast<TType>(1),
828 static_cast<TType>(1)};
829
830 using Vector3 = IVector3<float_t>;
831 using Vector3Int = IVector3<int32_t>;
832 using Vector3UInt = IVector3<uint32_t>;
833}
2D value type holding two components with basic arithmetic helpers.
Definition spk_vector2.hpp:35
TType x
X component.
Definition spk_vector2.hpp:44
TType y
Y component.
Definition spk_vector2.hpp:48
3D value type with common arithmetic helpers.
Definition spk_vector3.hpp:34
IVector3 operator-() const
Unary minus.
Definition spk_vector3.hpp:353
IVector3 operator/(const TType &p_scalar) const
Divides each component by a scalar.
Definition spk_vector3.hpp:278
std::wstring toWstring() const
Converts the vector to a wide string.
Definition spk_vector3.hpp:141
constexpr IVector3(const TX &p_x, const TY &p_y, const TZ &p_z)
Builds a vector from three components.
Definition spk_vector3.hpp:67
IVector2< TType > yz() const
Projects this vector into 2D using y and z components.
Definition spk_vector3.hpp:604
float_t x
Definition spk_vector3.hpp:43
constexpr IVector3(const IVector3< TOther > &p_other)
Converting constructor from another component type.
Definition spk_vector3.hpp:97
constexpr IVector3(const TOther &p_value)
Fills all components with the same value.
Definition spk_vector3.hpp:110
float length() const
Computes Euclidean length.
Definition spk_vector3.hpp:511
friend std::wostream & operator<<(std::wostream &p_stream, const IVector3 &p_value)
Streams the vector to a wide output stream.
Definition spk_vector3.hpp:166
IVector3< float > normalize() const
Return the vector once normalized by its length.
Definition spk_vector3.hpp:521
float dot(const IVector3 &p_other) const
Computes dot product with another vector.
Definition spk_vector3.hpp:560
friend IVector3 operator*(const TType &p_scalar, const IVector3 &p_vector)
Multiplies a scalar by a vector (scalar on the left side).
Definition spk_vector3.hpp:317
static const IVector3 Zero
Definition spk_vector3.hpp:120
IVector3 & operator/=(const TType &p_scalar)
In-place scalar division.
Definition spk_vector3.hpp:470
bool operator==(const IVector3 &p_other) const
Checks component-wise equality using SafeComparand.
Definition spk_vector3.hpp:177
static IVector3 min(std::initializer_list< IVector3 > p_values)
Component-wise minimum across an initializer list.
Definition spk_vector3.hpp:678
std::string toString() const
Converts the vector to a string.
Definition spk_vector3.hpp:130
IVector3 & operator/=(const IVector3 &p_other)
In-place component-wise division.
Definition spk_vector3.hpp:407
IVector3 operator+(const IVector3 &p_other) const
Component-wise addition.
Definition spk_vector3.hpp:200
IVector3 & operator+=(const IVector3 &p_other)
In-place component-wise addition.
Definition spk_vector3.hpp:364
IVector3 operator-(const IVector3 &p_other) const
Component-wise subtraction.
Definition spk_vector3.hpp:210
friend IVector3 operator/(const TType &p_scalar, const IVector3 &p_vector)
Divides a scalar by each vector component (scalar on the left side).
Definition spk_vector3.hpp:329
static bool isBetween(const IVector3 &p_value, const IVector3 &p_boundA, const IVector3 &p_boundB)
Checks whether a vector lies within inclusive bounds.
Definition spk_vector3.hpp:789
IVector3 & operator*=(const TType &p_scalar)
In-place scalar multiplication.
Definition spk_vector3.hpp:455
IVector3 clamped(const IVector3 &p_boundA, const IVector3 &p_boundB) const
Returns a clamped copy of this vector.
Definition spk_vector3.hpp:776
static IVector3 max(const IVector3 &p_a, const IVector3 &p_b)
Component-wise maximum of two vectors.
Definition spk_vector3.hpp:700
float squaredDistance(const IVector3 &p_other) const
Computes squared distance to another vector.
Definition spk_vector3.hpp:538
float_t z
Definition spk_vector3.hpp:51
IVector2< TType > xy() const
Projects this vector into 2D using x and y components.
Definition spk_vector3.hpp:595
friend std::ostream & operator<<(std::ostream &p_stream, const IVector3 &p_value)
Streams the vector to an output stream.
Definition spk_vector3.hpp:154
bool isZero() const
Checks if all components are zero.
Definition spk_vector3.hpp:486
float_t y
Definition spk_vector3.hpp:47
IVector3 & operator*=(const IVector3 &p_other)
In-place component-wise multiplication.
Definition spk_vector3.hpp:392
static IVector3 clamp(const IVector3 &p_value, const IVector3 &p_boundA, const IVector3 &p_boundB)
Clamps each component of a vector between two bounds.
Definition spk_vector3.hpp:752
IVector3 & operator-=(const TType &p_scalar)
In-place scalar subtraction.
Definition spk_vector3.hpp:441
IVector3 & operator+=(const TType &p_scalar)
In-place scalar addition.
Definition spk_vector3.hpp:427
IVector3 operator-(const TType &p_scalar) const
Subtracts a scalar from each component.
Definition spk_vector3.hpp:257
static IVector3 min(const IVector3 &p_a, const IVector3 &p_b)
Component-wise minimum of two vectors.
Definition spk_vector3.hpp:648
IVector3 inverse() const
Return the inverse vector.
Definition spk_vector3.hpp:344
constexpr IVector3(const IVector2< TOtherVector > &p_other, const TZ &p_z)
Builds a vector from a 2D vector and Z component.
Definition spk_vector3.hpp:83
constexpr IVector3()=default
Builds a zero vector.
IVector3 operator*(const TType &p_scalar) const
Multiplies each component by a scalar.
Definition spk_vector3.hpp:267
float distance(const IVector3 &p_other) const
Computes Euclidean distance to another vector.
Definition spk_vector3.hpp:549
IVector3 operator*(const IVector3 &p_other) const
Component-wise multiplication.
Definition spk_vector3.hpp:220
TType value_type
Component type stored by the vector.
Definition spk_vector3.hpp:38
bool operator!=(const IVector3 &p_other) const
Negation of equality.
Definition spk_vector3.hpp:190
IVector3 cross(const IVector3 &p_other) const
Computes 3D cross product.
Definition spk_vector3.hpp:576
float squaredLength() const
Computes squared vector length.
Definition spk_vector3.hpp:498
IVector3 operator/(const IVector3 &p_other) const
Component-wise division.
Definition spk_vector3.hpp:231
static IVector3 lerp(const IVector3 &p_from, const IVector3 &p_to, const TAlpha &p_alpha)
Linearly interpolates between two vectors.
Definition spk_vector3.hpp:626
static const IVector3 One
Definition spk_vector3.hpp:124
IVector3 operator+(const TType &p_scalar) const
Adds a scalar to each component.
Definition spk_vector3.hpp:247
static IVector3 max(std::initializer_list< IVector3 > p_values)
Component-wise maximum across an initializer list.
Definition spk_vector3.hpp:729
friend IVector3 operator-(const TType &p_scalar, const IVector3 &p_vector)
Subtracts vector components from a scalar (scalar on the left side).
Definition spk_vector3.hpp:305
friend IVector3 operator+(const TType &p_scalar, const IVector3 &p_vector)
Adds a scalar to a vector (scalar on the left side).
Definition spk_vector3.hpp:294
IVector3 & operator-=(const IVector3 &p_other)
In-place component-wise subtraction.
Definition spk_vector3.hpp:378
Wraps arithmetic values to compare with tolerance for floating-point inputs.
Definition spk_safe_comparand.hpp:17