Blender V4.3
BLI_math_vector.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
10
11#include <cmath>
12#include <type_traits>
13
14#include "BLI_math_base.hh"
16#include "BLI_span.hh"
17#include "BLI_utildefines.h"
18
19namespace blender::math {
20
25template<typename T, int Size>
26[[nodiscard]] inline bool almost_equal_relative(const VecBase<T, Size> &a,
27 const VecBase<T, Size> &b,
28 const T &epsilon_factor)
29{
30 for (int i = 0; i < Size; i++) {
31 const float epsilon = epsilon_factor * math::abs(a[i]);
32 if (math::distance(a[i], b[i]) > epsilon) {
33 return false;
34 }
35 }
36 return true;
37}
38
39template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> abs(const VecBase<T, Size> &a)
40{
42 for (int i = 0; i < Size; i++) {
43 result[i] = a[i] >= 0 ? a[i] : -a[i];
44 }
45 return result;
46}
47
51template<typename T, int Size>
52[[nodiscard]] inline VecBase<T, Size> sign(const VecBase<T, Size> &a)
53{
55}
56
57template<typename T, int Size>
62
63template<typename T, int Size>
68
69template<typename T, int Size>
70[[nodiscard]] inline VecBase<T, Size> clamp(const VecBase<T, Size> &a,
71 const VecBase<T, Size> &min,
72 const VecBase<T, Size> &max)
73{
75 for (int i = 0; i < Size; i++) {
76 result[i] = math::clamp(result[i], min[i], max[i]);
77 }
78 return result;
79}
80
81template<typename T, int Size>
82[[nodiscard]] inline VecBase<T, Size> clamp(const VecBase<T, Size> &a, const T &min, const T &max)
83{
85 for (int i = 0; i < Size; i++) {
86 result[i] = math::clamp(result[i], min, max);
87 }
88 return result;
89}
90
91template<typename T, int Size>
92[[nodiscard]] inline VecBase<T, Size> step(const VecBase<T, Size> &edge,
93 const VecBase<T, Size> &value)
94{
96}
97
98template<typename T, int Size>
99[[nodiscard]] inline VecBase<T, Size> step(const T &edge, const VecBase<T, Size> &value)
100{
101 VecBase<T, Size> result = value;
102 for (int i = 0; i < Size; i++) {
103 result[i] = math::step(edge, result[i]);
104 }
105 return result;
106}
107
108template<typename T, int Size>
109[[nodiscard]] inline VecBase<T, Size> mod(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
110{
112}
113
114template<typename T, int Size>
115[[nodiscard]] inline VecBase<T, Size> mod(const VecBase<T, Size> &a, const T &b)
116{
117 BLI_assert(b != 0);
119 for (int i = 0; i < Size; i++) {
120 result[i] = math::mod(a[i], b);
121 }
122 return result;
123}
124
128template<typename T, int Size>
134
138template<typename T, int Size>
139[[nodiscard]] inline VecBase<T, Size> safe_mod(const VecBase<T, Size> &a, const T &b)
140{
141 if (b == 0) {
142 return VecBase<T, Size>(0);
143 }
145 for (int i = 0; i < Size; i++) {
146 result[i] = math::mod(a[i], b);
147 }
148 return result;
149}
150
155template<typename T, int Size>
156[[nodiscard]] inline VecBase<T, Size> pow(const VecBase<T, Size> &x, const T &y)
157{
159 for (int i = 0; i < Size; i++) {
160 result[i] = math::pow(x[i], y);
161 }
162 return result;
163}
164
169template<typename T, int Size>
174
176template<typename T, int Size>
177[[nodiscard]] inline VecBase<T, Size> square(const VecBase<T, Size> &a)
178{
180}
181
182/* Per-element exponent. */
183template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> exp(const VecBase<T, Size> &x)
184{
186}
187
193template<typename T, int Size>
195 const VecBase<T, Size> &b)
196{
198 for (int i = 0; i < Size; i++) {
199 BLI_assert(a[i] >= 0);
200 BLI_assert(b[i] > 0);
201 result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i];
202 }
203 return result;
204}
205
210template<typename T, int Size>
211[[nodiscard]] inline VecBase<T, Size> divide_ceil(const VecBase<T, Size> &a,
212 const VecBase<T, Size> &b)
213{
215 for (int i = 0; i < Size; i++) {
216 BLI_assert(a[i] >= 0);
217 BLI_assert(b[i] > 0);
218 result[i] = (a[i] + b[i] - 1) / b[i];
219 }
220 return result;
221}
222
223template<typename T, int Size>
229
233template<typename T, int Size>
239
243template<typename T, int Size>
244[[nodiscard]] inline VecBase<T, Size> safe_divide(const VecBase<T, Size> &a, const T &b)
245{
246 return (b != 0) ? a / b : VecBase<T, Size>(0.0f);
247}
248
249template<typename T, int Size>
250[[nodiscard]] inline VecBase<T, Size> floor(const VecBase<T, Size> &a)
251{
253}
254
255template<typename T, int Size>
256[[nodiscard]] inline VecBase<T, Size> round(const VecBase<T, Size> &a)
257{
259}
260
261template<typename T, int Size>
262[[nodiscard]] inline VecBase<T, Size> ceil(const VecBase<T, Size> &a)
263{
265}
266
271template<typename T, int Size>
272[[nodiscard]] inline VecBase<T, Size> sqrt(const VecBase<T, Size> &a)
273{
275}
276
281template<typename T, int Size>
282[[nodiscard]] inline VecBase<T, Size> safe_sqrt(const VecBase<T, Size> &a)
283{
285 for (int i = 0; i < Size; i++) {
286 result[i] = a[i] >= T(0) ? math ::sqrt(a[i]) : T(0);
287 }
288 return result;
289}
290
295template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> rcp(const VecBase<T, Size> &a)
296{
298}
299
304template<typename T, int Size>
309
310template<typename T, int Size>
311[[nodiscard]] inline VecBase<T, Size> fract(const VecBase<T, Size> &a)
312{
314}
315
322template<typename T, int Size>
323[[nodiscard]] inline T dot(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
324{
325 T result = a[0] * b[0];
326 for (int i = 1; i < Size; i++) {
327 result += a[i] * b[i];
328 }
329 return result;
330}
331
335template<typename T, int Size> [[nodiscard]] inline T length_manhattan(const VecBase<T, Size> &a)
336{
337 T result = math::abs(a[0]);
338 for (int i = 1; i < Size; i++) {
339 result += math::abs(a[i]);
340 }
341 return result;
342}
343
344template<typename T, int Size> [[nodiscard]] inline T length_squared(const VecBase<T, Size> &a)
345{
346 return dot(a, a);
347}
348
349template<typename T, int Size> [[nodiscard]] inline T length(const VecBase<T, Size> &a)
350{
351 return math::sqrt(length_squared(a));
352}
353
355template<typename T, int Size> [[nodiscard]] inline bool is_unit_scale(const VecBase<T, Size> &v)
356{
357 /* Checks are flipped so NAN doesn't assert because we're making sure the value was
358 * normalized and in the case we don't want NAN to be raising asserts since there
359 * is nothing to be done in that case. */
360 const T test_unit = math::length_squared(v);
361 return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon<T>::value) ||
362 !(math::abs(test_unit) >= AssertUnitEpsilon<T>::value));
363}
364
365template<typename T, int Size>
366[[nodiscard]] inline T distance_manhattan(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
367{
368 return length_manhattan(a - b);
369}
370
371template<typename T, int Size>
372[[nodiscard]] inline T distance_squared(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
373{
374 return length_squared(a - b);
375}
376
377template<typename T, int Size>
378[[nodiscard]] inline T distance(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
379{
380 return length(a - b);
381}
382
383template<typename T, int Size>
384[[nodiscard]] inline VecBase<T, Size> reflect(const VecBase<T, Size> &incident,
385 const VecBase<T, Size> &normal)
386{
387 BLI_assert(is_unit_scale(normal));
388 return incident - 2.0 * dot(normal, incident) * normal;
389}
390
391template<typename T, int Size>
392[[nodiscard]] inline VecBase<T, Size> refract(const VecBase<T, Size> &incident,
393 const VecBase<T, Size> &normal,
394 const T &eta)
395{
396 float dot_ni = dot(normal, incident);
397 float k = 1.0f - eta * eta * (1.0f - dot_ni * dot_ni);
398 if (k < 0.0f) {
399 return VecBase<T, Size>(0.0f);
400 }
401 return eta * incident - (eta * dot_ni + sqrt(k)) * normal;
402}
403
408template<typename T, int Size>
409[[nodiscard]] inline VecBase<T, Size> project(const VecBase<T, Size> &p,
410 const VecBase<T, Size> &v_proj)
411{
412 if (UNLIKELY(is_zero(v_proj))) {
413 return VecBase<T, Size>(0.0f);
414 }
415 return v_proj * (dot(p, v_proj) / dot(v_proj, v_proj));
416}
417
418template<typename T, int Size>
420 T &out_length)
421{
422 out_length = length_squared(v);
423 /* A larger value causes normalize errors in a scaled down models with camera extreme close. */
424 constexpr T threshold = std::is_same_v<T, double> ? 1.0e-70 : 1.0e-35f;
425 if (out_length > threshold) {
426 out_length = sqrt(out_length);
427 return v / out_length;
428 }
429 /* Either the vector is small or one of it's values contained `nan`. */
430 out_length = 0.0;
431 return VecBase<T, Size>(0.0);
432}
433
434template<typename T, int Size>
435[[nodiscard]] inline VecBase<T, Size> normalize(const VecBase<T, Size> &v)
436{
437 T len;
439}
440
449template<typename T>
450[[nodiscard]] inline VecBase<T, 3> cross(const VecBase<T, 3> &a, const VecBase<T, 3> &b)
451{
452 return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
453}
454
459 const VecBase<float, 3> &b)
460{
461 return {float(double(a.y) * double(b.z) - double(a.z) * double(b.y)),
462 float(double(a.z) * double(b.x) - double(a.x) * double(b.z)),
463 float(double(a.x) * double(b.y) - double(a.y) * double(b.x))};
464}
465
471template<typename T> [[nodiscard]] inline VecBase<T, 3> cross_poly(Span<VecBase<T, 3>> poly)
472{
473 /* Newell's Method. */
474 int nv = int(poly.size());
475 if (nv < 3) {
476 return VecBase<T, 3>(0, 0, 0);
477 }
478 const VecBase<T, 3> *v_prev = &poly[nv - 1];
479 const VecBase<T, 3> *v_curr = &poly[0];
480 VecBase<T, 3> n(0, 0, 0);
481 for (int i = 0; i < nv;) {
482 n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
483 n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
484 n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
485 v_prev = v_curr;
486 ++i;
487 if (i < nv) {
488 v_curr = &poly[i];
489 }
490 }
491 return n;
492}
493
498template<typename T>
499[[nodiscard]] inline VecBase<T, 3> cross_tri(const VecBase<T, 3> &v1,
500 const VecBase<T, 3> &v2,
501 const VecBase<T, 3> &v3)
502{
503 return cross(v1 - v2, v2 - v3);
504}
505
510template<typename T>
511[[nodiscard]] inline VecBase<T, 3> normal_tri(const VecBase<T, 3> &v1,
512 const VecBase<T, 3> &v2,
513 const VecBase<T, 3> &v3)
514{
515 return normalize(cross_tri(v1, v2, v3));
516}
517
523template<typename T, typename FactorT, int Size>
524[[nodiscard]] inline VecBase<T, Size> interpolate(const VecBase<T, Size> &a,
525 const VecBase<T, Size> &b,
526 const FactorT &t)
527{
528 return a * (1 - t) + b * t;
529}
530
534template<typename T, int Size>
535[[nodiscard]] inline VecBase<T, Size> midpoint(const VecBase<T, Size> &a,
536 const VecBase<T, Size> &b)
537{
538 return (a + b) * 0.5;
539}
540
544template<typename T, int Size>
546 const VecBase<T, Size> &incident,
547 const VecBase<T, Size> &reference)
548{
549 return (dot(reference, incident) < 0) ? vector : -vector;
550}
551
555template<typename T> [[nodiscard]] inline int dominant_axis(const VecBase<T, 3> &a)
556{
557 VecBase<T, 3> b = abs(a);
558 return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
559}
560
564template<typename T, int Size> [[nodiscard]] inline T reduce_max(const VecBase<T, Size> &a)
565{
566 T result = a[0];
567 for (int i = 1; i < Size; i++) {
568 if (a[i] > result) {
569 result = a[i];
570 }
571 }
572 return result;
573}
574
578template<typename T, int Size> [[nodiscard]] inline T reduce_min(const VecBase<T, Size> &a)
579{
580 T result = a[0];
581 for (int i = 1; i < Size; i++) {
582 if (a[i] < result) {
583 result = a[i];
584 }
585 }
586 return result;
587}
588
592template<typename T, int Size> [[nodiscard]] inline T reduce_add(const VecBase<T, Size> &a)
593{
594 T result = a[0];
595 for (int i = 1; i < Size; i++) {
596 result += a[i];
597 }
598 return result;
599}
600
604template<typename T, int Size> [[nodiscard]] inline T reduce_mul(const VecBase<T, Size> &a)
605{
606 T result = a[0];
607 for (int i = 1; i < Size; i++) {
608 result *= a[i];
609 }
610 return result;
611}
612
616template<typename T, int Size> [[nodiscard]] inline T average(const VecBase<T, Size> &a)
617{
618 return reduce_add(a) * (T(1) / T(Size));
619}
620
626template<typename T> [[nodiscard]] inline VecBase<T, 3> orthogonal(const VecBase<T, 3> &v)
627{
628 const int axis = dominant_axis(v);
629 switch (axis) {
630 case 0:
631 return {-v.y - v.z, v.x, v.x};
632 case 1:
633 return {v.y, -v.x - v.z, v.y};
634 case 2:
635 return {v.z, v.z, -v.x - v.y};
636 }
637 return v;
638}
639
644template<typename T> [[nodiscard]] inline VecBase<T, 2> orthogonal(const VecBase<T, 2> &v)
645{
646 return {-v.y, v.x};
647}
648
652template<typename T, int Size>
653[[nodiscard]] inline bool is_equal(const VecBase<T, Size> &a,
654 const VecBase<T, Size> &b,
655 const T epsilon = T(0))
656{
657 for (int i = 0; i < Size; i++) {
658 if (math::abs(a[i] - b[i]) > epsilon) {
659 return false;
660 }
661 }
662 return true;
663}
664
671template<typename T, int Size>
672[[nodiscard]] inline bool is_zero(const VecBase<T, Size> &a, const T epsilon = T(0))
673{
674 for (int i = 0; i < Size; i++) {
675 if (math::abs(a[i]) > epsilon) {
676 return false;
677 }
678 }
679 return true;
680}
681
685template<typename T, int Size> [[nodiscard]] inline bool is_any_zero(const VecBase<T, Size> &a)
686{
687 for (int i = 0; i < Size; i++) {
688 if (a[i] == T(0)) {
689 return true;
690 }
691 }
692 return false;
693}
694
699template<typename T, int Size>
700[[nodiscard]] inline bool is_unit(const VecBase<T, Size> &a,
701 const T epsilon = T(10) * std::numeric_limits<T>::epsilon())
702{
703 const T length = length_squared(a);
704 return math::abs(length - T(1)) <= epsilon;
705}
706
708
709template<typename T> struct isect_result {
710 enum {
716 typename T::base_type lambda;
717};
718
719template<typename T, int Size>
721 const VecBase<T, Size> &v2,
722 const VecBase<T, Size> &v3,
723 const VecBase<T, Size> &v4);
724
725} // namespace blender::math
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_UNROLL_MATH_VEC_FUNC_VEC_VEC(op, a, b)
#define BLI_UNROLL_MATH_VEC_OP_VEC(op, a)
#define UNLIKELY(x)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
local_group_size(16, 16) .push_constant(Type b
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define T
T length_squared(const VecBase< T, Size > &a)
VecBase< T, 3 > normal_tri(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3)
T pow(const T &x, const T &power)
T clamp(const T &a, const T &min, const T &max)
T safe_rcp(const T &a)
bool is_any_zero(const T &a)
T sqrt(const T &a)
T safe_divide(const T &a, const T &b)
T sign(const T &a)
T floor(const T &a)
VecBase< T, Size > project(const VecBase< T, Size > &p, const VecBase< T, Size > &v_proj)
T reduce_max(const VecBase< T, Size > &a)
isect_result< VecBase< T, Size > > isect_seg_seg(const VecBase< T, Size > &v1, const VecBase< T, Size > &v2, const VecBase< T, Size > &v3, const VecBase< T, Size > &v4)
T distance(const T &a, const T &b)
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T length(const VecBase< T, Size > &a)
T exp(const T &x)
VecBase< float, 3 > cross_high_precision(const VecBase< float, 3 > &a, const VecBase< float, 3 > &b)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
bool is_unit_scale(const MatBase< T, NumCol, NumRow > &m)
T length_manhattan(const VecBase< T, Size > &a)
T reduce_min(const VecBase< T, Size > &a)
T average(const VecBase< T, Size > &a)
T min(const T &a, const T &b)
T step(const T &edge, const T &value)
bool is_zero(const T &a)
T midpoint(const T &a, const T &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
T safe_mod(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T fract(const T &a)
VecBase< T, 3 > cross_tri(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3)
T rcp(const T &a)
void min_max(const T &value, T &min, T &max)
T reduce_mul(const VecBase< T, Size > &a)
VecBase< T, Size > refract(const VecBase< T, Size > &incident, const VecBase< T, Size > &normal, const T &eta)
T square(const T &a)
VecBase< T, Size > faceforward(const VecBase< T, Size > &vector, const VecBase< T, Size > &incident, const VecBase< T, Size > &reference)
T ceil(const T &a)
bool almost_equal_relative(const VecBase< T, Size > &a, const VecBase< T, Size > &b, const T &epsilon_factor)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T distance_manhattan(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
VecBase< T, 3 > orthogonal(const VecBase< T, 3 > &v)
int dominant_axis(const VecBase< T, 3 > &a)
VecBase< T, Size > reflect(const VecBase< T, Size > &incident, const VecBase< T, Size > &normal)
VecBase< T, Size > ceil_to_multiple(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T max(const T &a, const T &b)
T mod(const T &a, const T &b)
bool is_unit(const VecBase< T, Size > &a, const T epsilon=T(10) *std::numeric_limits< T >::epsilon())
T abs(const T &a)
T round(const T &a)
VecBase< T, 3 > cross_poly(Span< VecBase< T, 3 > > poly)
T reduce_add(const VecBase< T, Size > &a)
VecBase< T, Size > safe_sqrt(const VecBase< T, Size > &a)
#define min(a, b)
Definition sort.c:32
enum blender::math::isect_result::@044052056044324103344077076162031251105165205056 kind
float max