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 constexpr auto data() const noexcept -> const value_type* {
112 return _components.data();
113 }
114
115 [[nodiscard]] constexpr auto operator[](size_type index) noexcept -> reference {
116 return _components[index];
117 }
118
119 [[nodiscard]] constexpr auto operator[](size_type index) const noexcept -> const_reference {
120 return _components[index];
121 }
122
123 template<scalar Other>
124 constexpr auto operator+=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
125 for (auto i : std::views::iota(0u, Size)) {
126 _components[i] += static_cast<value_type>(other[i]);
127 }
128
129 return *this;
130 }
131
132 template<scalar Other>
133 constexpr auto operator-=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
134 for (auto i : std::views::iota(0u, Size)) {
135 _components[i] -= static_cast<value_type>(other[i]);
136 }
137
138 return *this;
139 }
140
141 template<scalar Other>
142 constexpr auto operator*=(Other scalar) noexcept -> basic_vector& {
143 for (auto i : std::views::iota(0u, Size)) {
144 _components[i] *= static_cast<value_type>(scalar);
145 }
146
147 return *this;
148 }
149
150 template<scalar Other>
151 constexpr auto operator*=(const basic_vector<Size, Other>& other) noexcept -> basic_vector& {
152 for (auto i : std::views::iota(0u, Size)) {
153 _components[i] *= static_cast<value_type>(other[i]);
154 }
155
156 return *this;
157 }
158
159 template<scalar Other>
160 constexpr auto operator/=(Other scalar) noexcept -> basic_vector& {
161 utility::assert_that(!comparision_traits<Other>::equal(scalar, static_cast<Other>(0)), "Division by zero");
162
163 for (auto i : std::views::iota(0u, Size)) {
164 _components[i] /= static_cast<value_type>(scalar);
165 }
166
167 return *this;
168 }
169
170 [[nodiscard]] constexpr auto length_squared() const noexcept -> length_type {
171 auto result = static_cast<length_type>(0);
172
173 for (auto i : std::views::iota(0u, Size)) {
174 result += static_cast<length_type>(_components[i] * _components[i]);
175 }
176
177 return result;
178 }
179
180 [[nodiscard]] constexpr auto length() const noexcept -> length_type {
181 return std::sqrt(length_squared());
182 }
183
184 constexpr auto normalize() noexcept -> basic_vector& {
185 const auto length_squared = this->length_squared();
186
187 if (!comparision_traits<length_type>::equal(length_squared, static_cast<length_type>(0))) {
188 *this /= std::sqrt(length_squared);
189 }
190
191 return *this;
192 }
193
194protected:
195
196 template<std::convertible_to<value_type>... Args>
197 requires (sizeof...(Args) == Size)
198 constexpr basic_vector(Args&&... args) noexcept
199 : _components{utility::make_array<value_type, Size>(std::forward<Args>(args)...)} { }
200
201 constexpr basic_vector(std::array<value_type, Size>&& components) noexcept
202 : _components{std::move(components)} { }
203
204 template<scalar Other>
205 [[nodiscard]] static constexpr auto fill(Other value) noexcept -> basic_vector {
206 return basic_vector{value};
207 }
208
209 template<std::size_t Index, scalar Other>
210 [[nodiscard]] static constexpr auto axis(Other value) noexcept -> basic_vector {
211 return basic_vector{utility::make_array<value_type, Size, Index>(value)};
212 }
213
214private:
215
216 std::array<Type, Size> _components;
217
218}; // class basic_vector
219
220template<std::size_t Size, scalar Lhs, scalar Rhs>
221[[nodiscard]] constexpr auto operator==(const basic_vector<Size, Lhs>& lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> bool {
222 for (auto i : std::views::iota(0u, Size)) {
223 if (!comparision_traits<Lhs>::equal(lhs[i], rhs[i])) {
224 return false;
225 }
226 }
227
228 return true;
229}
230
231template<std::size_t Size, scalar Lhs, scalar Rhs>
232[[nodiscard]] constexpr auto operator+(basic_vector<Size, Lhs> lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector<Size, Lhs> {
233 return lhs += rhs;
234}
235
236template<std::size_t Size, scalar Lhs, scalar Rhs>
237[[nodiscard]] constexpr auto operator-(basic_vector<Size, Lhs> lhs, const basic_vector<Size, Rhs>& rhs) noexcept -> basic_vector<Size, Lhs> {
238 return lhs -= rhs;
239}
240
241template<std::size_t Size, scalar Lhs, scalar Rhs>
242[[nodiscard]] constexpr auto operator*(basic_vector<Size, Lhs> lhs, Rhs scalar) noexcept -> basic_vector<Size, Lhs> {
243 return lhs *= scalar;
244}
245
246template<std::size_t Size, scalar Lhs, scalar Rhs>
247[[nodiscard]] constexpr auto operator/(basic_vector<Size, Lhs> lhs, Rhs scalar) noexcept -> basic_vector<Size, Lhs> {
248 return lhs /= scalar;
249}
250
251template<std::size_t Size, scalar Type>
253
254template<std::size_t Size, scalar Type>
255using concrete_vector_t = typename concrete_vector<Size, Type>::type;
256
257} // namespace sbx::math
258
259#endif // LIBSBX_MATH_VECTOR_HPP_
Definition: vector.hpp:22
Definition: traits.hpp:10
Definition: vector.hpp:252