Blender V4.5
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
204template<typename T, int Size>
205[[nodiscard]] inline VecBase<T, Size> pow(const VecBase<T, Size> &x, const T &y)
206{
208 for (int i = 0; i < Size; i++) {
209 result[i] = math::pow(x[i], y);
210 }
211 return result;
212}
213
218template<typename T, int Size>
219[[nodiscard]] inline VecBase<T, Size> safe_pow(const VecBase<T, Size> &x, const T &y)
220{
222 for (int i = 0; i < Size; i++) {
223 result[i] = math::safe_pow(x[i], y);
224 }
225 return result;
226}
227
232template<typename T, int Size>
234 const T &y,
235 const VecBase<T, Size> &fallback)
236{
238 for (int i = 0; i < Size; i++) {
239 result[i] = math::fallback_pow(x[i], y, fallback[i]);
240 }
241 return result;
242}
243
248template<typename T, int Size>
253
255template<typename T, int Size>
256[[nodiscard]] inline VecBase<T, Size> square(const VecBase<T, Size> &a)
257{
259}
260
261/* Per-element exponent. */
262template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> exp(const VecBase<T, Size> &x)
263{
265}
266
272template<typename T, int Size>
274 const VecBase<T, Size> &b)
275{
277 for (int i = 0; i < Size; i++) {
278 BLI_assert(a[i] >= 0);
279 BLI_assert(b[i] > 0);
280 result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i];
281 }
282 return result;
283}
284
289template<typename T, int Size>
290[[nodiscard]] inline VecBase<T, Size> divide_ceil(const VecBase<T, Size> &a,
291 const VecBase<T, Size> &b)
292{
294 for (int i = 0; i < Size; i++) {
295 BLI_assert(a[i] >= 0);
296 BLI_assert(b[i] > 0);
297 result[i] = (a[i] + b[i] - 1) / b[i];
298 }
299 return result;
300}
301
302template<typename T, int Size>
308
312template<typename T, int Size>
318
322template<typename T, int Size>
323[[nodiscard]] inline VecBase<T, Size> safe_divide(const VecBase<T, Size> &a, const T &b)
324{
325 return (b != 0) ? a / b : VecBase<T, Size>(0.0f);
326}
327
328template<typename T, int Size>
329[[nodiscard]] inline VecBase<T, Size> floor(const VecBase<T, Size> &a)
330{
332}
333
334template<typename T, int Size>
335[[nodiscard]] inline VecBase<T, Size> round(const VecBase<T, Size> &a)
336{
338}
339
340template<typename T, int Size>
341[[nodiscard]] inline VecBase<T, Size> ceil(const VecBase<T, Size> &a)
342{
344}
345
350template<typename T, int Size>
351[[nodiscard]] inline VecBase<T, Size> sqrt(const VecBase<T, Size> &a)
352{
354}
355
360template<typename T, int Size>
361[[nodiscard]] inline VecBase<T, Size> safe_sqrt(const VecBase<T, Size> &a)
362{
364 for (int i = 0; i < Size; i++) {
365 result[i] = a[i] >= T(0) ? math ::sqrt(a[i]) : T(0);
366 }
367 return result;
368}
369
374template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> rcp(const VecBase<T, Size> &a)
375{
377}
378
383template<typename T, int Size>
388
389template<typename T, int Size>
390[[nodiscard]] inline VecBase<T, Size> fract(const VecBase<T, Size> &a)
391{
393}
394
401template<typename T, int Size>
402[[nodiscard]] inline T dot(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
403{
404 T result = a[0] * b[0];
405 for (int i = 1; i < Size; i++) {
406 result += a[i] * b[i];
407 }
408 return result;
409}
410
414template<typename T, int Size> [[nodiscard]] inline T length_manhattan(const VecBase<T, Size> &a)
415{
416 T result = math::abs(a[0]);
417 for (int i = 1; i < Size; i++) {
418 result += math::abs(a[i]);
419 }
420 return result;
421}
422
423template<typename T, int Size> [[nodiscard]] inline T length_squared(const VecBase<T, Size> &a)
424{
425 return dot(a, a);
426}
427
428template<typename T, int Size> [[nodiscard]] inline T length(const VecBase<T, Size> &a)
429{
430 return math::sqrt(length_squared(a));
431}
432
434template<typename T, int Size> [[nodiscard]] inline bool is_unit_scale(const VecBase<T, Size> &v)
435{
436 /* Checks are flipped so NAN doesn't assert because we're making sure the value was
437 * normalized and in the case we don't want NAN to be raising asserts since there
438 * is nothing to be done in that case. */
439 const T test_unit = math::length_squared(v);
440 return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon<T>::value) ||
441 !(math::abs(test_unit) >= AssertUnitEpsilon<T>::value));
442}
443
444template<typename T, int Size>
445[[nodiscard]] inline T distance_manhattan(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
446{
447 return length_manhattan(a - b);
448}
449
450template<typename T, int Size>
451[[nodiscard]] inline T distance_squared(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
452{
453 return length_squared(a - b);
454}
455
456template<typename T, int Size>
457[[nodiscard]] inline T distance(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
458{
459 return length(a - b);
460}
461
462template<typename T, int Size>
463[[nodiscard]] inline VecBase<T, Size> reflect(const VecBase<T, Size> &incident,
464 const VecBase<T, Size> &normal)
465{
466 BLI_assert(is_unit_scale(normal));
467 return incident - 2.0 * dot(normal, incident) * normal;
468}
469
470template<typename T, int Size>
471[[nodiscard]] inline VecBase<T, Size> refract(const VecBase<T, Size> &incident,
472 const VecBase<T, Size> &normal,
473 const T &eta)
474{
475 float dot_ni = dot(normal, incident);
476 float k = 1.0f - eta * eta * (1.0f - dot_ni * dot_ni);
477 if (k < 0.0f) {
478 return VecBase<T, Size>(0.0f);
479 }
480 return eta * incident - (eta * dot_ni + sqrt(k)) * normal;
481}
482
487template<typename T, int Size>
488[[nodiscard]] inline VecBase<T, Size> project(const VecBase<T, Size> &p,
489 const VecBase<T, Size> &v_proj)
490{
491 if (UNLIKELY(is_zero(v_proj))) {
492 return VecBase<T, Size>(0.0f);
493 }
494 return v_proj * (dot(p, v_proj) / dot(v_proj, v_proj));
495}
496
497template<typename T, int Size>
499 T &out_length)
500{
501 out_length = length_squared(v);
502 /* A larger value causes normalize errors in a scaled down models with camera extreme close. */
503 constexpr T threshold = std::is_same_v<T, double> ? 1.0e-70 : 1.0e-35f;
504 if (out_length > threshold) {
505 out_length = sqrt(out_length);
506 return v / out_length;
507 }
508 /* Either the vector is small or one of it's values contained `nan`. */
509 out_length = 0.0;
510 return VecBase<T, Size>(0.0);
511}
512
513template<typename T, int Size>
514[[nodiscard]] inline VecBase<T, Size> normalize(const VecBase<T, Size> &v)
515{
516 T len;
518}
519
528template<typename T>
529[[nodiscard]] inline VecBase<T, 3> cross(const VecBase<T, 3> &a, const VecBase<T, 3> &b)
530{
531 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};
532}
533
538 const VecBase<float, 3> &b)
539{
540 return {float(double(a.y) * double(b.z) - double(a.z) * double(b.y)),
541 float(double(a.z) * double(b.x) - double(a.x) * double(b.z)),
542 float(double(a.x) * double(b.y) - double(a.y) * double(b.x))};
543}
544
550template<typename T> [[nodiscard]] inline VecBase<T, 3> cross_poly(Span<VecBase<T, 3>> poly)
551{
552 /* Newell's Method. */
553 int nv = int(poly.size());
554 if (nv < 3) {
555 return VecBase<T, 3>(0, 0, 0);
556 }
557 const VecBase<T, 3> *v_prev = &poly[nv - 1];
558 const VecBase<T, 3> *v_curr = &poly[0];
559 VecBase<T, 3> n(0, 0, 0);
560 for (int i = 0; i < nv;) {
561 n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
562 n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
563 n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
564 v_prev = v_curr;
565 ++i;
566 if (i < nv) {
567 v_curr = &poly[i];
568 }
569 }
570 return n;
571}
572
577template<typename T>
578[[nodiscard]] inline VecBase<T, 3> cross_tri(const VecBase<T, 3> &v1,
579 const VecBase<T, 3> &v2,
580 const VecBase<T, 3> &v3)
581{
582 return cross(v1 - v2, v2 - v3);
583}
584
589template<typename T>
590[[nodiscard]] inline VecBase<T, 3> normal_tri(const VecBase<T, 3> &v1,
591 const VecBase<T, 3> &v2,
592 const VecBase<T, 3> &v3)
593{
594 return normalize(cross_tri(v1, v2, v3));
595}
596
602template<typename T, typename FactorT, int Size>
603[[nodiscard]] inline VecBase<T, Size> interpolate(const VecBase<T, Size> &a,
604 const VecBase<T, Size> &b,
605 const FactorT &t)
606{
607 return a * (1 - t) + b * t;
608}
609
613template<typename T, int Size>
614[[nodiscard]] inline VecBase<T, Size> midpoint(const VecBase<T, Size> &a,
615 const VecBase<T, Size> &b)
616{
617 return (a + b) * 0.5;
618}
619
623template<typename T, int Size>
625 const VecBase<T, Size> &incident,
626 const VecBase<T, Size> &reference)
627{
628 return (dot(reference, incident) < 0) ? vector : -vector;
629}
630
634template<typename T> [[nodiscard]] inline int dominant_axis(const VecBase<T, 3> &a)
635{
636 VecBase<T, 3> b = abs(a);
637 return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
638}
639
643template<typename T, int Size> [[nodiscard]] inline T reduce_max(const VecBase<T, Size> &a)
644{
645 T result = a[0];
646 for (int i = 1; i < Size; i++) {
647 if (a[i] > result) {
648 result = a[i];
649 }
650 }
651 return result;
652}
653
657template<typename T, int Size> [[nodiscard]] inline T reduce_min(const VecBase<T, Size> &a)
658{
659 T result = a[0];
660 for (int i = 1; i < Size; i++) {
661 if (a[i] < result) {
662 result = a[i];
663 }
664 }
665 return result;
666}
667
671template<typename T, int Size> [[nodiscard]] inline T reduce_add(const VecBase<T, Size> &a)
672{
673 T result = a[0];
674 for (int i = 1; i < Size; i++) {
675 result += a[i];
676 }
677 return result;
678}
679
683template<typename T, int Size> [[nodiscard]] inline T reduce_mul(const VecBase<T, Size> &a)
684{
685 T result = a[0];
686 for (int i = 1; i < Size; i++) {
687 result *= a[i];
688 }
689 return result;
690}
691
695template<typename T, int Size> [[nodiscard]] inline T average(const VecBase<T, Size> &a)
696{
697 return reduce_add(a) * (T(1) / T(Size));
698}
699
705template<typename T> [[nodiscard]] inline VecBase<T, 3> orthogonal(const VecBase<T, 3> &v)
706{
707 const int axis = dominant_axis(v);
708 switch (axis) {
709 case 0:
710 return {-v.y - v.z, v.x, v.x};
711 case 1:
712 return {v.y, -v.x - v.z, v.y};
713 case 2:
714 return {v.z, v.z, -v.x - v.y};
715 }
716 return v;
717}
718
723template<typename T> [[nodiscard]] inline VecBase<T, 2> orthogonal(const VecBase<T, 2> &v)
724{
725 return {-v.y, v.x};
726}
727
731template<typename T, int Size>
732[[nodiscard]] inline bool is_equal(const VecBase<T, Size> &a,
733 const VecBase<T, Size> &b,
734 const T epsilon = T(0))
735{
736 for (int i = 0; i < Size; i++) {
737 if (math::abs(a[i] - b[i]) > epsilon) {
738 return false;
739 }
740 }
741 return true;
742}
743
750template<typename T, int Size>
751[[nodiscard]] inline bool is_zero(const VecBase<T, Size> &a, const T epsilon = T(0))
752{
753 for (int i = 0; i < Size; i++) {
754 if (math::abs(a[i]) > epsilon) {
755 return false;
756 }
757 }
758 return true;
759}
760
764template<typename T, int Size> [[nodiscard]] inline bool is_any_zero(const VecBase<T, Size> &a)
765{
766 for (int i = 0; i < Size; i++) {
767 if (a[i] == T(0)) {
768 return true;
769 }
770 }
771 return false;
772}
773
778template<typename T, int Size>
779[[nodiscard]] inline bool is_unit(const VecBase<T, Size> &a,
780 const T epsilon = T(10) * std::numeric_limits<T>::epsilon())
781{
782 const T length = length_squared(a);
783 return math::abs(length - T(1)) <= epsilon;
784}
785
787
788template<typename T> struct isect_result {
789 enum {
795 typename T::base_type lambda;
796};
797
798template<typename T, int Size>
800 const VecBase<T, Size> &v2,
801 const VecBase<T, Size> &v3,
802 const VecBase<T, Size> &v4);
803
804} // 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
#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 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::@261376216017141314173064203006052213163255271007 kind
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len