Blender V4.3
BLI_math_base.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
11#include <algorithm>
12#include <cmath>
13#include <type_traits>
14
15#include "BLI_math_numbers.hh"
16#include "BLI_utildefines.h"
17
18namespace blender::math {
19
20template<typename T> inline constexpr bool is_math_float_type = std::is_floating_point_v<T>;
21template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>;
22
23template<typename T> inline bool is_zero(const T &a)
24{
25 return a == T(0);
26}
27
28template<typename T> inline bool is_any_zero(const T &a)
29{
30 return is_zero(a);
31}
32
33template<typename T> inline T abs(const T &a)
34{
35 return std::abs(a);
36}
37
38template<typename T> inline T sign(const T &a)
39{
40 return (T(0) < a) - (a < T(0));
41}
42
43template<typename T> inline T min(const T &a, const T &b)
44{
45 return std::min(a, b);
46}
47
48template<typename T> inline T max(const T &a, const T &b)
49{
50 return std::max(a, b);
51}
52
53template<typename T> inline void max_inplace(T &a, const T &b)
54{
55 a = math::max(a, b);
56}
57
58template<typename T> inline void min_inplace(T &a, const T &b)
59{
60 a = math::min(a, b);
61}
62
63template<typename T> inline T clamp(const T &a, const T &min, const T &max)
64{
65 return std::clamp(a, min, max);
66}
67
68template<typename T> inline T step(const T &edge, const T &value)
69{
70 return value < edge ? 0 : 1;
71}
72
73template<typename T> inline T mod(const T &a, const T &b)
74{
75 return std::fmod(a, b);
76}
77
78template<typename T> inline T safe_mod(const T &a, const T &b)
79{
80 return (b != 0) ? std::fmod(a, b) : 0;
81}
82
83template<typename T> inline void min_max(const T &value, T &min, T &max)
84{
85 min = math::min(value, min);
86 max = math::max(value, max);
87}
88
89template<typename T> inline T safe_divide(const T &a, const T &b)
90{
91 return (b != 0) ? a / b : T(0.0f);
92}
93
94template<typename T> inline T floor(const T &a)
95{
96 return std::floor(a);
97}
98
99template<typename T> inline T round(const T &a)
100{
101 return std::round(a);
102}
103
109template<typename T> inline T mod_periodic(const T &a, const T &b)
110{
111 BLI_assert(b != 0);
112 if constexpr (std::is_integral_v<T>) {
113 BLI_assert(std::numeric_limits<T>::max() - math::abs(a) >= b);
114 return ((a % b) + b) % b;
115 }
116
117 return a - (b * math::floor(a / b));
118}
119
120template<typename T> inline T ceil(const T &a)
121{
122 return std::ceil(a);
123}
124
125template<typename T> inline T distance(const T &a, const T &b)
126{
127 return std::abs(a - b);
128}
129
130template<typename T> inline T fract(const T &a)
131{
132 return a - std::floor(a);
133}
134
135template<typename T> inline T sqrt(const T &a)
136{
137 return std::sqrt(a);
138}
139
140/* Inverse value.
141 * If the input is zero the output is NaN. */
142template<typename T> inline T rcp(const T &a)
143{
144 return T(1) / a;
145}
146
147/* Inverse value.
148 * If the input is zero the output is zero. */
149template<typename T> inline T safe_rcp(const T &a)
150{
151 return a ? T(1) / a : T(0);
152}
153
154template<typename T> inline T cos(const T &a)
155{
156 return std::cos(a);
157}
158
159template<typename T> inline T sin(const T &a)
160{
161 return std::sin(a);
162}
163
164template<typename T> inline T tan(const T &a)
165{
166 return std::tan(a);
167}
168
169template<typename T> inline T acos(const T &a)
170{
171 return std::acos(a);
172}
173
174template<typename T> inline T pow(const T &x, const T &power)
175{
176 return std::pow(x, power);
177}
178
179template<typename T> inline T square(const T &a)
180{
181 return a * a;
182}
183
184template<typename T> inline T exp(const T &x)
185{
186 return std::exp(x);
187}
188
189template<typename T> inline T safe_acos(const T &a)
190{
191 if (UNLIKELY(a <= T(-1))) {
192 return T(numbers::pi);
193 }
194 else if (UNLIKELY(a >= T(1))) {
195 return T(0);
196 }
197 return math::acos((a));
198}
199
201inline float safe_acos_approx(float x)
202{
203 const float f = std::abs(x);
204 /* Clamp and crush denormals. */
205 const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
206 /* Based on http://www.pouet.net/topic.php?which=9132&page=2
207 * 85% accurate (ULP 0)
208 * Examined 2130706434 values of `acos`:
209 * 15.2000597 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // without "denormal crush".
210 * Examined 2130706434 values of `acos`:
211 * 15.2007108 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // with "denormal crush".
212 */
213 const float a = std::sqrt(1.0f - m) *
214 (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
215 return x < 0.0f ? float(numbers::pi) - a : a;
216}
217
218template<typename T> inline T asin(const T &a)
219{
220 return std::asin(a);
221}
222
223template<typename T> inline T atan(const T &a)
224{
225 return std::atan(a);
226}
227
228template<typename T> inline T atan2(const T &y, const T &x)
229{
230 return std::atan2(y, x);
231}
232
233template<typename T> inline T hypot(const T &y, const T &x)
234{
235 return std::hypot(y, x);
236}
237
238template<typename T, typename FactorT>
239inline T interpolate(const T &a, const T &b, const FactorT &t)
240{
241 auto result = a * (1 - t) + b * t;
242 if constexpr (std::is_integral_v<T> && std::is_floating_point_v<FactorT>) {
243 result = std::round(result);
244 }
245 return result;
246}
247
248template<typename T> inline T midpoint(const T &a, const T &b)
249{
250 if constexpr (std::is_integral_v<T>) {
252 using Unsigned = std::make_unsigned_t<T>;
253 int sign = 1;
254 Unsigned smaller = a;
255 Unsigned larger = b;
256 if (a > b) {
257 sign = -1;
258 smaller = b;
259 larger = a;
260 }
261 return a + sign * T(Unsigned(larger - smaller) / 2);
262 }
263 else {
264 return (a + b) * T(0.5);
265 }
266}
267
268} // namespace blender::math
#define BLI_assert(a)
Definition BLI_assert.h:50
#define UNLIKELY(x)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
ccl_device_inline float2 power(float2 v, float e)
#define T
T cos(const AngleRadianBase< T > &a)
float safe_acos_approx(float x)
T pow(const T &x, const T &power)
constexpr bool is_math_float_type
T clamp(const T &a, const T &min, const T &max)
T safe_rcp(const T &a)
T acos(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)
constexpr bool is_math_integral_type
T distance(const T &a, const T &b)
T exp(const T &x)
void min_inplace(T &a, const T &b)
T min(const T &a, const T &b)
T atan(const T &a)
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 atan2(const T &y, const T &x)
T rcp(const T &a)
T safe_acos(const T &a)
void min_max(const T &value, T &min, T &max)
T asin(const T &a)
T square(const T &a)
T ceil(const T &a)
T mod_periodic(const T &a, const T &b)
T sin(const AngleRadianBase< T > &a)
T max(const T &a, const T &b)
T mod(const T &a, const T &b)
T abs(const T &a)
T tan(const AngleRadianBase< T > &a)
T round(const T &a)
T hypot(const T &y, const T &x)
void max_inplace(T &a, const T &b)
#define min(a, b)
Definition sort.c:32
float max