sandbox
Loading...
Searching...
No Matches
vector.hpp
1#ifndef LIBSBX_MATH_VECTOR_HPP_
2#define LIBSBX_MATH_VECTOR_HPP_
3
4#include <array>
5#include <cmath>
6#include <ranges>
7
8#include <libsbx/utility/make_array.hpp>
9#include <libsbx/utility/assert.hpp>
10#include <libsbx/utility/zip.hpp>
12
13#include <libsbx/math/concepts.hpp>
14#include <libsbx/math/traits.hpp>
15#include <libsbx/math/constants.hpp>
16#include <libsbx/math/algorithm.hpp>
17
18namespace sbx::math {
19
20template<std::size_t Size, scalar Type>
21requires (Size > 1u)
23
24 template<std::size_t S, scalar T>
25 requires (S > 1u)
26 friend class basic_vector;
27
28public:
29
30 using value_type = Type;
31 using reference = value_type&;
32 using const_reference = const value_type&;
33 using size_type = std::size_t;
34 using length_type = std::float_t;
35
36 template<scalar Other = value_type>
37 constexpr basic_vector(Other value = Other{0}) noexcept
38 : _components{utility::make_array<value_type, Size>(value)} { }
39
40 template<scalar Other = value_type>
41 constexpr basic_vector(const basic_vector<Size, Other>& other) noexcept
42 : _components{utility::make_array<value_type, Size>(other._components)} { }
43
44 constexpr basic_vector(const basic_vector& other) noexcept = default;
45
46 constexpr basic_vector(basic_vector&& other) noexcept = default;
47
48 auto operator=(const basic_vector& other) noexcept -> basic_vector& = default;
49
50 auto operator=(basic_vector&& other) noexcept -> basic_vector& = default;
51
52 template<scalar Lhs = value_type, scalar Rhs = value_type>
53 static constexpr auto min(const basic_vector<Size, Lhs>& lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector {
54 auto result = lhs;
55
56 for (auto i : std::views::iota(0u, Size)) {
57 result[i] = std::min(lhs[i], rhs[i]);
58 }
59
60 return result;
61 }
62
63 template<scalar Lhs = value_type, scalar Rhs = value_type>
64 static constexpr auto max(const basic_vector<Size, Lhs>& lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector {
65 auto result = lhs;
66
67 for (auto i : std::views::iota(0u, Size)) {
68 result[i] = std::max(lhs[i], rhs[i]);
69 }
70
71 return result;
72 }
73
74 template<scalar Lhs = value_type, scalar Rhs = value_type>
75 static constexpr auto abs(const basic_vector<Size, Lhs>& vector) noexcept -> basic_vector {
76 auto result = vector;
77
78 for (auto i : std::views::iota(0u, Size)) {
79 result[i] = std::abs(vector[i]);
80 }
81
82 return result;
83 }
84
85 template<size_type Axis, scalar Other = value_type>
86 requires (Axis < Size)
87 [[nodiscard]] static constexpr auto splat(const basic_vector<Size, Other>& vector) noexcept -> basic_vector<Size, Other> {
88 auto result = basic_vector<Size, Other>{};
89
90 for (auto i : std::views::iota(0u, Size)) {
91 result[i] = vector[Axis];
92 }
93
94 return result;
95 }
96
97 [[nodiscard]] static constexpr auto lerp(const basic_vector& x, const basic_vector& y, const value_type a) noexcept -> basic_vector {
98 auto result = basic_vector{};
99
100 for (auto i : std::views::iota(0u, Size)) {
101 result[i] = math::mix(x[i], y[i], a);
102 }
103
104 return result;
105 }
106
107 constexpr auto data() noexcept -> value_type* {
108 return _components.data();
109 }
110
111 [[nodiscard]] constexpr auto operator[](size_type index) noexcept -> reference {
112 return _components[index];
113 }
114
115 [[nodiscard]] constexpr auto operator[](size_type index) const noexcept -> const_reference {
116 return _components[index];
117 }
118
119 template<scalar Other>
120 constexpr auto operator+=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
121 for (auto i : std::views::iota(0u, Size)) {
122 _components[i] += static_cast<value_type>(other[i]);
123 }
124
125 return *this;
126 }
127
128 template<scalar Other>
129 constexpr auto operator-=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
130 for (auto i : std::views::iota(0u, Size)) {
131 _components[i] -= static_cast<value_type>(other[i]);
132 }
133
134 return *this;
135 }
136
137 template<scalar Other>
138 constexpr auto operator*=(Other scalar) noexcept -> basic_vector& {
139 for (auto i : std::views::iota(0u, Size)) {
140 _components[i] *= static_cast<value_type>(scalar);
141 }
142
143 return *this;
144 }
145
146 template<scalar Other>
147 constexpr auto operator*=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
148 for (auto i : std::views::iota(0u, Size)) {
149 _components[i] *= static_cast<value_type>(other[i]);
150 }
151
152 return *this;
153 }
154
155 template<scalar Other>
156 constexpr auto operator/=(Other scalar) noexcept -> basic_vector& {
157 utility::assert_that(!comparision_traits<Other>::equal(scalar, static_cast<Other>(0)), "Division by zero");
158
159 for (auto i : std::views::iota(0u, Size)) {
160 _components[i] /= static_cast<value_type>(scalar);
161 }
162
163 return *this;
164 }
165
166 [[nodiscard]] constexpr auto length_squared() const noexcept -> length_type {
167 auto result = static_cast<length_type>(0);
168
169 for (auto i : std::views::iota(0u, Size)) {
170 result += static_cast<length_type>(_components[i] * _components[i]);
171 }
172
173 return result;
174 }
175
176 [[nodiscard]] constexpr auto length() const noexcept -> length_type {
177 return std::sqrt(length_squared());
178 }
179
180 constexpr auto normalize() noexcept -> basic_vector& {
181 const auto length_squared = this->length_squared();
182
183 if (!comparision_traits<length_type>::equal(length_squared, static_cast<length_type>(0))) {
184 *this /= std::sqrt(length_squared);
185 }
186
187 return *this;
188 }
189
190protected:
191
192 template<std::convertible_to<value_type>... Args>
193 requires (sizeof...(Args) == Size)
194 constexpr basic_vector(Args&&... args) noexcept
195 : _components{utility::make_array<value_type, Size>(std::forward<Args>(args)...)} { }
196
197 constexpr basic_vector(std::array<value_type, Size>&& components) noexcept
198 : _components{std::move(components)} { }
199
200 template<scalar Other>
201 [[nodiscard]] static constexpr auto fill(Other value) noexcept -> basic_vector {
202 return basic_vector{value};
203 }
204
205 template<std::size_t Index, scalar Other>
206 [[nodiscard]] static constexpr auto axis(Other value) noexcept -> basic_vector {
207 return basic_vector{utility::make_array<value_type, Size, Index>(value)};
208 }
209
210private:
211
212 std::array<Type, Size> _components;
213
214}; // class basic_vector
215
216template<std::size_t Size, scalar Lhs, scalar Rhs>
217[[nodiscard]] constexpr auto operator==(const basic_vector<Size, Lhs>& lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> bool {
218 for (auto i : std::views::iota(0u, Size)) {
219 if (!comparision_traits<Lhs>::equal(lhs[i], rhs[i])) {
220 return false;
221 }
222 }
223
224 return true;
225}
226
227template<std::size_t Size, scalar Lhs, scalar Rhs>
228[[nodiscard]] constexpr auto operator+(basic_vector<Size, Lhs> lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector<Size, Lhs> {
229 return lhs += rhs;
230}
231
232template<std::size_t Size, scalar Lhs, scalar Rhs>
233[[nodiscard]] constexpr auto operator-(basic_vector<Size, Lhs> lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector<Size, Lhs> {
234 return lhs -= rhs;
235}
236
237template<std::size_t Size, scalar Lhs, scalar Rhs>
238[[nodiscard]] constexpr auto operator*(basic_vector<Size, Lhs> lhs, Rhs scalar) noexcept -> basic_vector<Size, Lhs> {
239 return lhs *= scalar;
240}
241
242template<std::size_t Size, scalar Lhs, scalar Rhs>
243[[nodiscard]] constexpr auto operator/(basic_vector<Size, Lhs> lhs, Rhs scalar) noexcept -> basic_vector<Size, Lhs> {
244 return lhs /= scalar;
245}
246
247} // namespace sbx::math
248
249#endif // LIBSBX_MATH_VECTOR_HPP_
Definition: vector.hpp:22
Definition: traits.hpp:10