Not Enough Math
Lightweight zero-dependency C++ math library
Loading...
Searching...
No Matches
vec_utils.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "config.hpp"
4#include "utils.hpp"
5#include "vec.hpp"
6#include "power.hpp"
7#include <concepts>
8
9namespace nem
10{
11 template<typename T, size_t N>
13 {
14 for (size_t c = 0; c < N; ++c)
15 {
16 if (!nem::is_zero(v[c]))
17 {
18 return false;
19 }
20 }
21 return true;
22 }
23
24 template<typename T, size_t N>
26 {
27 for (size_t c = 0; c < N; ++c)
28 {
29 if (!nem::is_zero(v[c]))
30 {
31 return false;
32 }
33 }
34 return true;
35 }
36
40
41 template<typename T, size_t N>
43 {
44 nem::vec<T, N> result;
45 for (size_t i = 0; i < N; ++i)
46 {
47 result[i] = nem::is_infinite(v[i]);
48 }
49 return result;
50 }
51
52 template<typename T, size_t N>
54 {
55 nem::vec<T, N> result;
56 for (size_t i = 0; i < N; ++i)
57 {
58 result[i] = nem::is_nan(v[i]);
59 }
60 return result;
61 }
62
66
67 template<std::floating_point T, size_t N>
68 constexpr nem::vec<T, N> copysign(const nem::vec<T, N>& to, const nem::vec<T, N>& from)
69 {
70 nem::vec<T, N> result;
71 for (size_t i = 0; i < N; ++i)
72 {
73 result[i] = nem::copysign(to[i], from[i]);
74 }
75 return result;
76 }
77
78 template<nem::scalar_type T, size_t N>
80 {
81 nem::vec<T, N> result;
82 for (size_t i = 0; i < N; ++i)
83 {
84 result[i] = nem::sign(v[i]);
85 }
86 return result;
87 }
88
89 template<typename T, size_t N>
90 constexpr nem::vec<T, N> abs(const nem::vec<T, N>& v)
91 {
92 nem::vec<T, N> result;
93 for (size_t i = 0; i < N; ++i)
94 {
95 result[i] = nem::abs(v[i]);
96 }
97 return result;
98 }
99
103
104 template<nem::scalar_type T, size_t N>
105 constexpr bool is_zero_or_neg(const nem::vec<T, N>& v)
106 {
107 for (size_t i = 0; i < N; ++i)
108 {
109 if (!nem::is_zero_or_neg(v[i]))
110 {
111 return false;
112 }
113 }
114 return true;
115 }
116
117 template<nem::scalar_type T, size_t N>
118 constexpr bool equal(const nem::vec<T, N>& a, const nem::vec<T, N>& b)
119 {
120 for (size_t i = 0; i < N; ++i)
121 {
122 if (!nem::equal(a[i], b[i]))
123 {
124 return false;
125 }
126 }
127 return true;
128 }
129
130 template<nem::scalar_type T, size_t N>
132 {
133 nem::vec<T, N> result;
134 for (size_t i = 0; i < N; ++i)
135 {
136 result[i] = nem::get_max(a[i], b[i]);
137 }
138 return result;
139 }
140
141 template<nem::scalar_type T, size_t N>
143 {
144 nem::vec<T, N> result;
145 for (size_t i = 0; i < N; ++i)
146 {
147 result[i] = nem::get_min(a[i], b[i]);
148 }
149 return result;
150 }
151
152 template<nem::scalar_type T, size_t N>
154 {
155 nem::vec<T, N> result;
156 for (size_t i = 0; i < N; ++i)
157 {
158 result[i] = nem::average(a[i], b[i]);
159 }
160 return result;
161 }
162
166
167 template<typename T, size_t N>
169 {
170 nem::vec<T, N> result;
171 for (size_t i = 0; i < N; ++i)
172 {
173 result[i] = nem::pow2(v[i]);
174 }
175 return result;
176 }
177
178 template<typename T, size_t N>
180 {
181 nem::vec<T, N> result;
182 for (size_t i = 0; i < N; ++i)
183 {
184 result[i] = nem::pow3(v[i]);
185 }
186 return result;
187 }
188
189 template<typename T, size_t N>
191 {
192 nem::vec<T, N> result;
193 for (size_t i = 0; i < N; ++i)
194 {
195 result[i] = nem::pow4(v[i]);
196 }
197 return result;
198 }
199
200 template<typename T, size_t N>
202 {
203 nem::vec<T, N> result;
204 for (size_t i = 0; i < N; ++i)
205 {
206 result[i] = nem::sqr(v[i]);
207 }
208 return result;
209 }
210
211 template<typename T, size_t N>
213 {
214 nem::vec<T, N> result;
215 for (size_t i = 0; i < N; ++i)
216 {
217 result[i] = nem::cube(v[i]);
218 }
219 return result;
220 }
221
225
226 template<nem::scalar_type T, size_t N>
228 {
229 nem::vec<T, N> result;
230 for (size_t i = 0; i < N; ++i)
231 {
232 result[i] = nem::truncate(v[i]);
233 }
234 return result;
235 }
236
237 template<nem::scalar_type T, size_t N>
239 {
240 nem::vec<T, N> result;
241 for (size_t i = 0; i < N; ++i)
242 {
243 result[i] = nem::floor(v[i]);
244 }
245 return result;
246 }
247
248 template<nem::scalar_type T, size_t N>
250 {
251 nem::vec<T, N> result;
252 for (size_t i = 0; i < N; ++i)
253 {
254 result[i] = nem::ceil(v[i]);
255 }
256 return result;
257 }
258
259 template<nem::scalar_type T, size_t N>
260 constexpr nem::vec<T, N> mod(const nem::vec<T, N>& a, const nem::vec<T, N>& b)
261 {
262 nem::vec<T, N> result;
263 for (size_t i = 0; i < N; ++i)
264 {
265 result[i] = nem::mod(a[i], b[i]);
266 }
267 return result;
268 }
269
270 template<std::floating_point T, size_t N>
272 {
273 nem::vec<T, N> result;
274 for (size_t i = 0; i < N; ++i)
275 {
276 result[i] = nem::frac(v[i]);
277 }
278 return result;
279 }
280
281 template<std::floating_point T, size_t N>
283 {
284 nem::vec<T, N> result;
285 for (size_t i = 0; i < N; ++i)
286 {
287 result[i] = nem::round(v[i]);
288 }
289 return result;
290 }
291
295
296 template<nem::scalar_type T, size_t N>
297 constexpr nem::vec<T, N> floor(const nem::vec<T, N>& v, const nem::vec<T, N>& step)
298 {
299 nem::vec<T, N> result;
300 for (size_t i = 0; i < N; ++i)
301 {
302 result[i] = nem::floor(v[i], step[i]);
303 }
304 return result;
305 }
306
307 template<nem::scalar_type T, size_t N>
308 constexpr nem::vec<T, N> ceil(const nem::vec<T, N>& v, const nem::vec<T, N>& step)
309 {
310 nem::vec<T, N> result;
311 for (size_t i = 0; i < N; ++i)
312 {
313 result[i] = nem::ceil(v[i], step[i]);
314 }
315 return result;
316 }
317
318 template<nem::scalar_type T, size_t N>
319 constexpr nem::vec<T, N> round(const nem::vec<T, N>& v, const nem::vec<T, N>& step)
320 {
321 nem::vec<T, N> result;
322 for (size_t i = 0; i < N; ++i)
323 {
324 result[i] = nem::round(v[i], step[i]);
325 }
326 return result;
327 }
328
332
333 template<nem::scalar_type T, size_t N>
334 constexpr nem::vec<T, N> repeat(const nem::vec<T, N>& value, const nem::vec<T, N>& lengthExcl)
335 {
336 nem::vec<T, N> result;
337 for (size_t i = 0; i < N; ++i)
338 {
339 result[i] = nem::repeat(value[i], lengthExcl[i]);
340 }
341 return result;
342 }
343
344 template<nem::scalar_type T, size_t N>
345 constexpr nem::vec<T, N> repeat(const nem::vec<T, N>& value, const nem::vec<T, N>& minIncl, const nem::vec<T, N>& maxExcl)
346 {
347 nem::vec<T, N> result;
348 for (size_t i = 0; i < N; ++i)
349 {
350 result[i] = nem::repeat(value[i], minIncl[i], maxExcl[i]);
351 }
352 return result;
353 }
354
355 template<nem::scalar_type T, size_t N>
357 {
358 nem::vec<T, N> result;
359 for (size_t i = 0; i < N; ++i)
360 {
361 result[i] = nem::pingpong(value[i], length[i]);
362 }
363 return result;
364 }
365
366 template<nem::scalar_type T, size_t N>
367 constexpr nem::vec<T, N> pingpong(const nem::vec<T, N>& value, const nem::vec<T, N>& minIncl, const nem::vec<T, N>& maxExcl)
368 {
369 nem::vec<T, N> result;
370 for (size_t i = 0; i < N; ++i)
371 {
372 result[i] = nem::pingpong(value[i], minIncl[i], maxExcl[i]);
373 }
374 return result;
375 }
376
377 template<std::totally_ordered T, size_t N>
378 constexpr nem::vec<T, N> clamp(const nem::vec<T, N>& value, const nem::vec<T, N>& minIncl, const nem::vec<T, N>& maxIncl)
379 {
380 nem::vec<T, N> result;
381 for (size_t i = 0; i < N; ++i)
382 {
383 result[i] = nem::clamp(value[i], minIncl[i], maxIncl[i]);
384 }
385 return result;
386 }
387
388 template<std::totally_ordered T, size_t N>
389 constexpr nem::vec<T, N> clamp01(const nem::vec<T, N>& value)
390 {
391 nem::vec<T, N> result;
392 for (size_t i = 0; i < N; ++i)
393 {
394 result[i] = nem::clamp01(value[i]);
395 }
396 return result;
397 }
398
402
403 template<typename T, size_t N>
404 constexpr nem::vec<T, N> smoothstep(const nem::vec<T, N>& edge0, const nem::vec<T, N>& edge1, const nem::vec<T, N>& x)
405 {
406 nem::vec<T, N> result;
407 for (size_t i = 0; i < N; ++i)
408 {
409 result[i] = nem::smoothstep(edge0[i], edge1[i], x[i]);
410 }
411 return result;
412 }
413
417
418 template<nem::scalar_type T, size_t N>
419 constexpr nem::vec<T, N> remap(const nem::vec<T, N>& value, const nem::vec<T, N>& fromMin, const nem::vec<T, N>& fromMax,
420 const nem::vec<T, N>& toMin, const nem::vec<T, N>& toMax)
421 {
422 nem::vec<T, N> result;
423 for (size_t i = 0; i < N; ++i)
424 {
425 result[i] = nem::remap(value[i], fromMin[i], fromMax[i], toMin[i], toMax[i]);
426 }
427 return result;
428 }
429
433
434 template<nem::scalar_type T, size_t N>
436 {
437 nem::vec<T, N> result;
438 for (size_t i = 0; i < N; ++i)
439 {
440 result[i] = nem::is_whole(v[i]);
441 }
442 return result;
443 }
444
445 template<typename T, size_t N>
447 {
448 T result = (T)0.0;
449 for (size_t c = 0; c < N; ++c)
450 {
451 result += a[c] * b[c];
452 }
453 return result;
454 }
455
456 template <typename T>
458 {
459 return nem::vec<T, 3>(
460 a.y * b.z - a.z * b.y,
461 a.z * b.x - a.x * b.z,
462 a.x * b.y - a.y * b.x
463 );
464 }
465
466 template<typename T, size_t N>
468 {
469 T result = (T)0.0;
470 for (size_t c = 0; c < N; ++c)
471 {
472 result += v[c];
473 }
474 return result;
475 }
476
477 template<typename T, size_t N>
479 {
480 T result = (T)1.0;
481 for (size_t c = 0; c < N; ++c)
482 {
483 result *= v[c];
484 }
485 return result;
486 }
487
488 template<typename T, size_t N>
490 {
491 return vector - (T)2.0 * nem::dot(vector, normal) * normal;
492 }
493
494 template<typename T, size_t N>
495 static constexpr nem::vec<T, N> lerp(const nem::vec<T, N>& a, const nem::vec<T, N>& b, float t)
496 {
497 nem::vec<T, N> result;
498 for (size_t i = 0; i < N; ++i)
499 {
500 result[i] = (T)nem::lerp(a[i], b[i], t);
501 }
502 return result;
503 }
504
505 template<typename T, size_t N>
506 constexpr T sqr_length(const nem::vec<T, N>& vec)
507 {
508 T sum{};
509 for (size_t i = 0; i < N; ++i)
510 {
511 sum += vec[i] * vec[i];
512 }
513 return sum;
514 }
515
516 template<typename T, size_t N>
518 {
520 }
521
522 template<typename T, size_t N>
524 {
525 nem::vec<T, N> result;
526 const T len = nem::length(vec);
527
528 if (nem::is_zero(len))
529 {
531 }
532
533 if constexpr (std::is_floating_point_v<T>)
534 {
535 const T fac = (T)1.0 / len;
536 for (size_t i = 0; i < N; ++i)
537 {
538 result[i] = vec[i] * fac;
539 }
540 }
541 else
542 {
543 for (size_t i = 0; i < N; ++i)
544 {
545 result[i] = vec[i] / len;
546 }
547 }
548
549 return result;
550 }
551
552 template<typename T>
554 {
555 if (nem::is_zero(vector))
556 {
558 return false;
559 }
560
561 if (nem::abs(vector.z) < 0.999f) // TODO : fix magic precision number
562 {
563 b1 = nem::normalize(nem::cross(vector, nem::vec<T, 3>(0, 0, 1)));
564 }
565 else
566 {
567 b1 = nem::normalize(nem::cross(vector, nem::vec<T, 3>(1, 0, 0)));
568 }
569
570 b2 = nem::cross(vector, b1);
571
572 return true;
573 }
574}
#define NEM_INLINE
Definition config.hpp:12
T invalid_result(nem::error::Kind kind=Kind::RuntimeError, const char *const msg=nullptr)
Definition err.hpp:120
void report_invalid(nem::error::Kind kind=Kind::RuntimeError, const char *const msg=nullptr)
Definition err.hpp:109
Definition config.hpp:16
nem::quat_t< T > normalize(nem::quat_t< T > q)
constexpr T smoothstep(T edge0, T edge1, T x)
Definition utils.hpp:276
constexpr T floor(T value) noexcept
Floors always towards -infinity.
Definition utils.hpp:87
constexpr T get_max(T a, T b) noexcept
Definition utils.hpp:58
constexpr T get_min(T a, T b) noexcept
Definition utils.hpp:60
T horizontal_sum(const nem::vec< T, N > &v)
constexpr T mod(T a, T b)
Calculates euclidean modulo of a % b = r, where r belongs to [0, b). Unline standard C++ modulo opera...
Definition utils.hpp:115
nem::vec< T, 3 > cross(const nem::vec< T, 3 > &a, const nem::vec< T, 3 > &b)
constexpr T ceil(T value) noexcept
Ceils always towards +infinity.
Definition utils.hpp:101
T sqrt(T value)
Definition power.hpp:180
T dot(const nem::vec< T, N > &a, const nem::vec< T, N > &b)
bool orthogonal_3d_basis(const nem::vec< T, 3 > &vector, nem::vec< T, 3 > &b1, nem::vec< T, 3 > &b2)
constexpr T repeat(T value, T lengthExcl)
Unwinds number to 0 when goes past length. Lengh is excluded: when value == lengthExcl,...
Definition utils.hpp:237
constexpr T remap(T value, T fromMin, T fromMax, T toMin, T toMax)
Definition utils.hpp:292
constexpr T is_nan(T value) noexcept
Definition utils.hpp:20
constexpr T sign(T value) noexcept
Definition utils.hpp:36
constexpr T abs(T value) noexcept
Definition utils.hpp:38
constexpr bool is_zero(T a) noexcept
Is a nearly 0? Given an Epsilon > 0, within each all numbers are considered indistinguisable from 0,...
Definition utils.hpp:48
constexpr T pow3(T value) noexcept
Definition utils.hpp:70
constexpr T pow4(T value) noexcept
Definition utils.hpp:71
constexpr bool is_zero_or_neg(T a) noexcept
Definition utils.hpp:51
constexpr T frac(T value) noexcept
Returns the fractional part of the floating-point number, with respect to sign 3.5 -> 0....
Definition utils.hpp:133
constexpr T pow2(T value) noexcept
Definition utils.hpp:69
T horizontal_mul(const nem::vec< T, N > &v)
constexpr T round(T value) noexcept
Definition utils.hpp:144
constexpr T sqr_length(const nem::quat_t< T > &q)
constexpr T pingpong(T value, T length)
Definition utils.hpp:250
constexpr T is_infinite(T value) noexcept
Definition utils.hpp:19
constexpr T copysign(T to, T from) noexcept
Copies the sign of {from} over to {to}. If the signs were the same, it doesn't change.
Definition utils.hpp:31
constexpr T clamp01(T value) noexcept
Definition utils.hpp:267
constexpr T truncate(T value) noexcept
Definition utils.hpp:79
constexpr T sqr(T value) noexcept
Definition utils.hpp:72
constexpr bool equal(T a, T b) noexcept
Are a and b nearly equal? Given an Epsilon > 0, within each all numbers are considered indistinguisab...
Definition utils.hpp:56
T length(const nem::quat_t< T > &q)
constexpr T lerp(T a, T b, T t)
Definition utils.hpp:286
constexpr T clamp(T value, T minIncl, T maxIncl) noexcept
Definition utils.hpp:261
nem::vec< T, N > reflect(const nem::vec< T, N > &vector, const nem::vec< T, N > &normal)
constexpr T cube(T value) noexcept
Definition utils.hpp:73
constexpr T is_whole(T value)
Is a floating point number whole (same as integer)
Definition utils.hpp:307
constexpr T average(T a, T b) noexcept
Definition utils.hpp:62