Blender V5.0
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 <type_traits>
12
13#include "BLI_math_base.hh"
15#include "BLI_span.hh"
16#include "BLI_utildefines.h"
17
18namespace blender::math {
19
24template<typename T, int Size>
25[[nodiscard]] inline bool almost_equal_relative(const VecBase<T, Size> &a,
26 const VecBase<T, Size> &b,
27 const T &epsilon_factor)
28{
29 for (int i = 0; i < Size; i++) {
30 const float epsilon = epsilon_factor * math::abs(a[i]);
31 if (math::distance(a[i], b[i]) > epsilon) {
32 return false;
33 }
34 }
35 return true;
36}
37
38template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> abs(const VecBase<T, Size> &a)
39{
41 for (int i = 0; i < Size; i++) {
42 result[i] = a[i] >= 0 ? a[i] : -a[i];
43 }
44 return result;
45}
46
50template<typename T, int Size>
51[[nodiscard]] inline VecBase<T, Size> sign(const VecBase<T, Size> &a)
52{
54}
55
56template<typename T, int Size>
61
65template<typename T, int Size>
66[[nodiscard]] inline VecBase<T, Size> min(Span<VecBase<T, Size>> values)
67{
68 BLI_assert(!values.is_empty());
69
70 VecBase<T, Size> result = values[0];
71 for (const VecBase<T, Size> &v : values.drop_front(1)) {
72 result = min(result, v);
73 }
74
75 return result;
76}
77
81template<typename T, int Size>
82[[nodiscard]] inline VecBase<T, Size> min(std::initializer_list<VecBase<T, Size>> values)
83{
84 return min(Span(values));
85}
86
87template<typename T, int Size>
92
96template<typename T, int Size>
97[[nodiscard]] inline VecBase<T, Size> max(Span<VecBase<T, Size>> values)
98{
99 BLI_assert(!values.is_empty());
100
101 VecBase<T, Size> result = values[0];
102 for (const VecBase<T, Size> &v : values.drop_front(1)) {
103 result = max(result, v);
104 }
105
106 return result;
107}
108
112template<typename T, int Size>
113[[nodiscard]] inline VecBase<T, Size> max(std::initializer_list<VecBase<T, Size>> values)
114{
115 return max(Span(values));
116}
117
118template<typename T, int Size>
119[[nodiscard]] inline VecBase<T, Size> clamp(const VecBase<T, Size> &a,
120 const VecBase<T, Size> &min,
121 const VecBase<T, Size> &max)
122{
124 for (int i = 0; i < Size; i++) {
125 result[i] = math::clamp(result[i], min[i], max[i]);
126 }
127 return result;
128}
129
130template<typename T, int Size>
131[[nodiscard]] inline VecBase<T, Size> clamp(const VecBase<T, Size> &a, const T &min, const T &max)
132{
134 for (int i = 0; i < Size; i++) {
136 }
137 return result;
138}
139
140template<typename T, int Size>
141[[nodiscard]] inline VecBase<T, Size> step(const VecBase<T, Size> &edge,
142 const VecBase<T, Size> &value)
143{
145}
146
147template<typename T, int Size>
148[[nodiscard]] inline VecBase<T, Size> step(const T &edge, const VecBase<T, Size> &value)
149{
150 VecBase<T, Size> result = value;
151 for (int i = 0; i < Size; i++) {
152 result[i] = math::step(edge, result[i]);
153 }
154 return result;
155}
156
157template<typename T, int Size>
158[[nodiscard]] inline VecBase<T, Size> mod(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
159{
161}
162
163template<typename T, int Size>
164[[nodiscard]] inline VecBase<T, Size> mod(const VecBase<T, Size> &a, const T &b)
165{
166 BLI_assert(b != 0);
168 for (int i = 0; i < Size; i++) {
169 result[i] = math::mod(a[i], b);
170 }
171 return result;
172}
173
177template<typename T, int Size>
183
187template<typename T, int Size>
188[[nodiscard]] inline VecBase<T, Size> safe_mod(const VecBase<T, Size> &a, const T &b)
189{
190 if (b == 0) {
191 return VecBase<T, Size>(0);
192 }
194 for (int i = 0; i < Size; i++) {
195 result[i] = math::mod(a[i], b);
196 }
197 return result;
198}
199
200template<typename T, int Size>
201[[nodiscard]] inline VecBase<T, Size> floored_mod(const VecBase<T, Size> &a,
202 const VecBase<T, Size> &b)
203{
205 for (int i = 0; i < Size; i++) {
206 BLI_assert(b[i] != 0);
207 result[i] = math::floored_mod(a[i], b[i]);
208 }
209 return result;
210}
211
212template<typename T, int Size>
213[[nodiscard]] inline VecBase<T, Size> floored_mod(const VecBase<T, Size> &a, const T &b)
214{
215 BLI_assert(b != 0);
217 for (int i = 0; i < Size; i++) {
218 result[i] = math::floored_mod(a[i], b);
219 }
220 return result;
221}
222
227template<typename T, int Size>
228[[nodiscard]] inline VecBase<T, Size> pow(const VecBase<T, Size> &x, const T &y)
229{
231 for (int i = 0; i < Size; i++) {
232 result[i] = math::pow(x[i], y);
233 }
234 return result;
235}
236
241template<typename T, int Size>
242[[nodiscard]] inline VecBase<T, Size> safe_pow(const VecBase<T, Size> &x, const T &y)
243{
245 for (int i = 0; i < Size; i++) {
246 result[i] = math::safe_pow(x[i], y);
247 }
248 return result;
249}
250
255template<typename T, int Size>
257 const T &y,
258 const VecBase<T, Size> &fallback)
259{
261 for (int i = 0; i < Size; i++) {
262 result[i] = math::fallback_pow(x[i], y, fallback[i]);
263 }
264 return result;
265}
266
271template<typename T, int Size>
276
278template<typename T, int Size>
279[[nodiscard]] inline VecBase<T, Size> square(const VecBase<T, Size> &a)
280{
282}
283
284/* Per-element exponent. */
285template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> exp(const VecBase<T, Size> &x)
286{
288}
289
295template<typename T, int Size>
297 const VecBase<T, Size> &b)
298{
300 for (int i = 0; i < Size; i++) {
301 BLI_assert(a[i] >= 0);
302 BLI_assert(b[i] > 0);
303 result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i];
304 }
305 return result;
306}
307
312template<typename T, int Size>
313[[nodiscard]] inline VecBase<T, Size> divide_ceil(const VecBase<T, Size> &a,
314 const VecBase<T, Size> &b)
315{
317 for (int i = 0; i < Size; i++) {
318 BLI_assert(a[i] >= 0);
319 BLI_assert(b[i] > 0);
320 result[i] = (a[i] + b[i] - 1) / b[i];
321 }
322 return result;
323}
324
325template<typename T, int Size>
331
335template<typename T, int Size>
341
345template<typename T, int Size>
346[[nodiscard]] inline VecBase<T, Size> safe_divide(const VecBase<T, Size> &a, const T &b)
347{
348 return (b != 0) ? a / b : VecBase<T, Size>(0.0f);
349}
350
351template<typename T, int Size>
352[[nodiscard]] inline VecBase<T, Size> floor(const VecBase<T, Size> &a)
353{
355}
356
357template<typename T, int Size>
358[[nodiscard]] inline VecBase<T, Size> round(const VecBase<T, Size> &a)
359{
361}
362
363template<typename T, int Size>
364[[nodiscard]] inline VecBase<T, Size> ceil(const VecBase<T, Size> &a)
365{
367}
368
373template<typename T, int Size>
374[[nodiscard]] inline VecBase<T, Size> sqrt(const VecBase<T, Size> &a)
375{
377}
378
383template<typename T, int Size>
384[[nodiscard]] inline VecBase<T, Size> safe_sqrt(const VecBase<T, Size> &a)
385{
387 for (int i = 0; i < Size; i++) {
388 result[i] = a[i] >= T(0) ? math ::sqrt(a[i]) : T(0);
389 }
390 return result;
391}
392
397template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> rcp(const VecBase<T, Size> &a)
398{
400}
401
406template<typename T, int Size>
411
412template<typename T, int Size>
413[[nodiscard]] inline VecBase<T, Size> fract(const VecBase<T, Size> &a)
414{
416}
417
424template<typename T, int Size>
425[[nodiscard]] inline T dot(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
426{
427 T result = a[0] * b[0];
428 for (int i = 1; i < Size; i++) {
429 result += a[i] * b[i];
430 }
431 return result;
432}
433
437template<typename T, int Size> [[nodiscard]] inline T length_manhattan(const VecBase<T, Size> &a)
438{
439 T result = math::abs(a[0]);
440 for (int i = 1; i < Size; i++) {
441 result += math::abs(a[i]);
442 }
443 return result;
444}
445
446template<typename T, int Size> [[nodiscard]] inline T length_squared(const VecBase<T, Size> &a)
447{
448 return dot(a, a);
449}
450
451template<typename T, int Size> [[nodiscard]] inline T length(const VecBase<T, Size> &a)
452{
453 return math::sqrt(length_squared(a));
454}
455
457template<typename T, int Size> [[nodiscard]] inline bool is_unit_scale(const VecBase<T, Size> &v)
458{
459 /* Checks are flipped so NAN doesn't assert because we're making sure the value was
460 * normalized and in the case we don't want NAN to be raising asserts since there
461 * is nothing to be done in that case. */
462 const T test_unit = math::length_squared(v);
463 return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon<T>::value) ||
464 !(math::abs(test_unit) >= AssertUnitEpsilon<T>::value));
465}
466
467template<typename T, int Size>
468[[nodiscard]] inline T distance_manhattan(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
469{
470 return length_manhattan(a - b);
471}
472
473template<typename T, int Size>
474[[nodiscard]] inline T distance_squared(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
475{
476 return length_squared(a - b);
477}
478
479template<typename T, int Size>
480[[nodiscard]] inline T distance(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
481{
482 return length(a - b);
483}
484
485template<typename T, int Size>
486[[nodiscard]] inline VecBase<T, Size> reflect(const VecBase<T, Size> &incident,
487 const VecBase<T, Size> &normal)
488{
489 BLI_assert(is_unit_scale(normal));
490 return incident - 2.0 * dot(normal, incident) * normal;
491}
492
493template<typename T, int Size>
494[[nodiscard]] inline VecBase<T, Size> refract(const VecBase<T, Size> &incident,
495 const VecBase<T, Size> &normal,
496 const T &eta)
497{
498 float dot_ni = dot(normal, incident);
499 float k = 1.0f - eta * eta * (1.0f - dot_ni * dot_ni);
500 if (k < 0.0f) {
501 return VecBase<T, Size>(0.0f);
502 }
503 return eta * incident - (eta * dot_ni + sqrt(k)) * normal;
504}
505
510template<typename T, int Size>
511[[nodiscard]] inline VecBase<T, Size> project(const VecBase<T, Size> &p,
512 const VecBase<T, Size> &v_proj)
513{
514 if (UNLIKELY(is_zero(v_proj))) {
515 return VecBase<T, Size>(0.0f);
516 }
517 return v_proj * (dot(p, v_proj) / dot(v_proj, v_proj));
518}
519
520template<typename T, int Size>
522 T &out_length)
523{
524 out_length = length_squared(v);
525 /* A larger value causes normalize errors in a scaled down models with camera extreme close. */
526 constexpr T threshold = std::is_same_v<T, double> ? 1.0e-70 : 1.0e-35f;
527 if (out_length > threshold) {
528 out_length = sqrt(out_length);
529 return v / out_length;
530 }
531 /* Either the vector is small or one of it's values contained `nan`. */
532 out_length = 0.0;
533 return VecBase<T, Size>(0.0);
534}
535
536template<typename T, int Size>
537[[nodiscard]] inline VecBase<T, Size> normalize(const VecBase<T, Size> &v)
538{
539 T len;
541}
542
543template<typename T> [[nodiscard]] inline T cross(const VecBase<T, 2> &a, const VecBase<T, 2> &b)
544{
545 return a.x * b.y - a.y * b.x;
546}
547
556template<typename T>
557[[nodiscard]] inline VecBase<T, 3> cross(const VecBase<T, 3> &a, const VecBase<T, 3> &b)
558{
559 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};
560}
561
566 const VecBase<float, 3> &b)
567{
568 return {float(double(a.y) * double(b.z) - double(a.z) * double(b.y)),
569 float(double(a.z) * double(b.x) - double(a.x) * double(b.z)),
570 float(double(a.x) * double(b.y) - double(a.y) * double(b.x))};
571}
572
578template<typename T> [[nodiscard]] inline VecBase<T, 3> cross_poly(Span<VecBase<T, 3>> poly)
579{
580 /* Newell's Method. */
581 int nv = int(poly.size());
582 if (nv < 3) {
583 return VecBase<T, 3>(0, 0, 0);
584 }
585 const VecBase<T, 3> *v_prev = &poly[nv - 1];
586 const VecBase<T, 3> *v_curr = &poly[0];
587 VecBase<T, 3> n(0, 0, 0);
588 for (int i = 0; i < nv;) {
589 n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
590 n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
591 n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
592 v_prev = v_curr;
593 ++i;
594 if (i < nv) {
595 v_curr = &poly[i];
596 }
597 }
598 return n;
599}
600
605template<typename T>
606[[nodiscard]] inline VecBase<T, 3> cross_tri(const VecBase<T, 3> &v1,
607 const VecBase<T, 3> &v2,
608 const VecBase<T, 3> &v3)
609{
610 return cross(v1 - v2, v2 - v3);
611}
612
617template<typename T>
618[[nodiscard]] inline VecBase<T, 3> normal_tri(const VecBase<T, 3> &v1,
619 const VecBase<T, 3> &v2,
620 const VecBase<T, 3> &v3)
621{
622 return normalize(cross_tri(v1, v2, v3));
623}
624
630template<typename T, typename FactorT, int Size>
631[[nodiscard]] inline VecBase<T, Size> interpolate(const VecBase<T, Size> &a,
632 const VecBase<T, Size> &b,
633 const FactorT &t)
634{
635 return a * (1 - t) + b * t;
636}
637
641template<typename T, int Size>
642[[nodiscard]] inline VecBase<T, Size> midpoint(const VecBase<T, Size> &a,
643 const VecBase<T, Size> &b)
644{
645 return (a + b) * 0.5;
646}
647
651template<typename T, int Size>
653 const VecBase<T, Size> &incident,
654 const VecBase<T, Size> &reference)
655{
656 return (dot(reference, incident) < 0) ? vector : -vector;
657}
658
662template<typename T> [[nodiscard]] inline int dominant_axis(const VecBase<T, 3> &a)
663{
664 VecBase<T, 3> b = abs(a);
665 return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
666}
667
671template<typename T, int Size> [[nodiscard]] inline T reduce_max(const VecBase<T, Size> &a)
672{
673 T result = a[0];
674 for (int i = 1; i < Size; i++) {
675 if (a[i] > result) {
676 result = a[i];
677 }
678 }
679 return result;
680}
681
685template<typename T, int Size> [[nodiscard]] inline T reduce_min(const VecBase<T, Size> &a)
686{
687 T result = a[0];
688 for (int i = 1; i < Size; i++) {
689 if (a[i] < result) {
690 result = a[i];
691 }
692 }
693 return result;
694}
695
699template<typename T, int Size> [[nodiscard]] inline T reduce_add(const VecBase<T, Size> &a)
700{
701 T result = a[0];
702 for (int i = 1; i < Size; i++) {
703 result += a[i];
704 }
705 return result;
706}
707
711template<typename T, int Size> [[nodiscard]] inline T reduce_mul(const VecBase<T, Size> &a)
712{
713 T result = a[0];
714 for (int i = 1; i < Size; i++) {
715 result *= a[i];
716 }
717 return result;
718}
719
723template<typename T, int Size> [[nodiscard]] inline T average(const VecBase<T, Size> &a)
724{
725 return reduce_add(a) * (T(1) / T(Size));
726}
727
733template<typename T> [[nodiscard]] inline VecBase<T, 3> orthogonal(const VecBase<T, 3> &v)
734{
735 const int axis = dominant_axis(v);
736 switch (axis) {
737 case 0:
738 return {-v.y - v.z, v.x, v.x};
739 case 1:
740 return {v.y, -v.x - v.z, v.y};
741 case 2:
742 return {v.z, v.z, -v.x - v.y};
743 }
744 return v;
745}
746
751template<typename T> [[nodiscard]] inline VecBase<T, 2> orthogonal(const VecBase<T, 2> &v)
752{
753 return {-v.y, v.x};
754}
755
759template<typename T, int Size>
760[[nodiscard]] inline bool is_equal(const VecBase<T, Size> &a,
761 const VecBase<T, Size> &b,
762 const T epsilon = T(0))
763{
764 for (int i = 0; i < Size; i++) {
765 if (math::abs(a[i] - b[i]) > epsilon) {
766 return false;
767 }
768 }
769 return true;
770}
771
778template<typename T, int Size>
779[[nodiscard]] inline bool is_zero(const VecBase<T, Size> &a, const T epsilon = T(0))
780{
781 for (int i = 0; i < Size; i++) {
782 if (math::abs(a[i]) > epsilon) {
783 return false;
784 }
785 }
786 return true;
787}
788
792template<typename T, int Size> [[nodiscard]] inline bool is_any_zero(const VecBase<T, Size> &a)
793{
794 for (int i = 0; i < Size; i++) {
795 if (a[i] == T(0)) {
796 return true;
797 }
798 }
799 return false;
800}
801
806template<typename T, int Size>
807[[nodiscard]] inline bool is_unit(const VecBase<T, Size> &a,
808 const T epsilon = T(10) * std::numeric_limits<T>::epsilon())
809{
810 const T length = length_squared(a);
811 return math::abs(length - T(1)) <= epsilon;
812}
813
815
816template<typename T> struct isect_result {
817 enum {
823 typename T::base_type lambda;
824};
825
826template<typename T, int Size>
828 const VecBase<T, Size> &v2,
829 const VecBase<T, Size> &v3,
830 const VecBase<T, Size> &v4);
831
832} // namespace blender::math
#define BLI_assert(a)
Definition BLI_assert.h:46
#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 btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
nullptr float
#define round
#define pow
#define exp
VecBase< T, D > reflect(VecOp< T, D >, VecOp< T, D >) RET
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< T, D > faceforward(VecOp< T, D >, VecOp< T, D >, VecOp< T, D >) RET
#define abs
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
#define floor
#define ceil
#define sqrt
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
#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 floored_mod(const T &a, const T &b)
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 dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
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)
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)
T safe_pow(const T &x, const T &power)
T fallback_pow(const T &x, const T &power, const T &fallback)
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)
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 > 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.cc:36
enum blender::math::isect_result::@263246371363174113064124076102177335155253321343 kind
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len