Blender V5.0
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
10
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 static_assert(std::is_arithmetic_v<T>, "math::min on non-arithmetic type is likely unintended");
46 return std::min(a, b);
47}
48
49template<typename T> inline T max(const T &a, const T &b)
50{
51 static_assert(std::is_arithmetic_v<T>, "math::max on non-arithmetic type is likely unintended");
52 return std::max(a, b);
53}
54
55template<typename T> inline void max_inplace(T &a, const T &b)
56{
57 static_assert(std::is_arithmetic_v<T>,
58 "math::max_inplace on non-arithmetic type is likely unintended");
59 a = std::max(a, b);
60}
61
62template<typename T> inline void min_inplace(T &a, const T &b)
63{
64 static_assert(std::is_arithmetic_v<T>,
65 "math::min_inplace on non-arithmetic type is likely unintended");
66 a = std::min(a, b);
67}
68
69template<typename T> inline T clamp(const T &a, const T &min, const T &max)
70{
71 return std::clamp(a, min, max);
72}
73
74template<typename T> inline T step(const T &edge, const T &value)
75{
76 return value < edge ? 0 : 1;
77}
78
79template<typename T> inline T mod(const T &a, const T &b)
80{
81 return std::fmod(a, b);
82}
83
84template<typename T> inline T safe_mod(const T &a, const T &b)
85{
86 return (b != 0) ? std::fmod(a, b) : 0;
87}
88
89template<typename T> inline T floored_mod(const T &a, const T &b)
90{
91 return a - std::floor(a / b) * b;
92}
93
94template<typename T> inline T safe_floored_mod(const T &a, const T &b)
95{
96 return (b != 0) ? a - std::floor(a / b) * b : 0;
97}
98
99template<typename T> inline void min_max(const T &value, T &min, T &max)
100{
101 static_assert(std::is_arithmetic_v<T>,
102 "math::min_max on non-arithmetic type is likely unintended");
103 min = std::min(value, min);
104 max = std::max(value, max);
105}
106
107template<typename T> inline T safe_divide(const T &a, const T &b)
108{
109 return (b != 0) ? a / b : T(0.0f);
110}
111
112template<typename T> inline T floor(const T &a)
113{
114 return std::floor(a);
115}
116
117template<typename T> inline T round(const T &a)
118{
119 return std::round(a);
120}
121
127template<typename T> inline T mod_periodic(const T &a, const T &b)
128{
129 BLI_assert(b != 0);
130 if constexpr (std::is_integral_v<T>) {
131 BLI_assert(std::numeric_limits<T>::max() - math::abs(a) >= b);
132 return ((a % b) + b) % b;
133 }
134
135 return a - (b * math::floor(a / b));
136}
137
138template<typename T> inline T ceil(const T &a)
139{
140 return std::ceil(a);
141}
142
143template<typename T> inline T distance(const T &a, const T &b)
144{
145 return std::abs(a - b);
146}
147
148template<typename T> inline T fract(const T &a)
149{
150 return a - std::floor(a);
151}
152
153template<typename T> inline T sqrt(const T &a)
154{
155 return std::sqrt(a);
156}
157
158/* Inverse value.
159 * If the input is zero the output is NaN. */
160template<typename T> inline T rcp(const T &a)
161{
162 static_assert(!std::is_integral_v<T>, "T must not be an integral type.");
163 return T(1) / a;
164}
165
166/* Inverse value.
167 * If the input is zero the output is zero. */
168template<typename T> inline T safe_rcp(const T &a)
169{
170 static_assert(!std::is_integral_v<T>, "T must be not be an integral type.");
171 return a ? T(1) / a : T(0);
172}
173
174template<typename T> inline T cos(const T &a)
175{
176 return std::cos(a);
177}
178
179template<typename T> inline T sin(const T &a)
180{
181 return std::sin(a);
182}
183
184template<typename T> inline T tan(const T &a)
185{
186 return std::tan(a);
187}
188
189template<typename T> inline T acos(const T &a)
190{
191 return std::acos(a);
192}
193
194template<typename T> inline T pow(const T &x, const T &power)
195{
196 return std::pow(x, power);
197}
198
199template<typename T> inline T safe_pow(const T &x, const T &power)
200{
201 return (x < 0 || (x == 0 && power <= 0)) ? x : std::pow(x, power);
202}
203
204template<typename T> inline T fallback_pow(const T &x, const T &power, const T &fallback)
205{
206 return (x < 0 || (x == 0 && power <= 0)) ? fallback : std::pow(x, power);
207}
208
209template<typename T> inline T square(const T &a)
210{
211 return a * a;
212}
213
214template<typename T> inline T cube(const T &a)
215{
216 return a * a * a;
217}
218
219template<typename T> inline T exp(const T &x)
220{
221 return std::exp(x);
222}
223
224template<typename T> inline T safe_acos(const T &a)
225{
226 if (UNLIKELY(a <= T(-1))) {
227 return T(numbers::pi);
228 }
229 if (UNLIKELY(a >= T(1))) {
230 return T(0);
231 }
232 return math::acos((a));
233}
234
236inline float safe_acos_approx(float x)
237{
238 const float f = std::abs(x);
239 /* Clamp and crush denormals. */
240 const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
241 /* Based on http://www.pouet.net/topic.php?which=9132&page=2
242 * 85% accurate (ULP 0)
243 * Examined 2130706434 values of `acos`:
244 * 15.2000597 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // without "denormal crush".
245 * Examined 2130706434 values of `acos`:
246 * 15.2007108 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // with "denormal crush".
247 */
248 const float a = std::sqrt(1.0f - m) *
249 (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
250 return x < 0.0f ? float(numbers::pi) - a : a;
251}
252
253template<typename T> inline T asin(const T &a)
254{
255 return std::asin(a);
256}
257
258template<typename T> inline T atan(const T &a)
259{
260 return std::atan(a);
261}
262
263template<typename T> inline T atan2(const T &y, const T &x)
264{
265 return std::atan2(y, x);
266}
267
268template<typename T> inline T hypot(const T &y, const T &x)
269{
270 return std::hypot(y, x);
271}
272
273template<typename T, typename FactorT>
274inline T interpolate(const T &a, const T &b, const FactorT &t)
275{
276 auto result = a * (1 - t) + b * t;
277 if constexpr (std::is_integral_v<T> && std::is_floating_point_v<FactorT>) {
278 result = std::round(result);
279 }
280 return result;
281}
282
283template<typename T> inline T midpoint(const T &a, const T &b)
284{
285 if constexpr (std::is_integral_v<T>) {
287 using Unsigned = std::make_unsigned_t<T>;
288 int sign = 1;
289 Unsigned smaller = a;
290 Unsigned larger = b;
291 if (a > b) {
292 sign = -1;
293 smaller = b;
294 larger = a;
295 }
296 return a + sign * T(Unsigned(larger - smaller) / 2);
297 }
298 else {
299 return (a + b) * T(0.5);
300 }
301}
302
303} // namespace blender::math
#define BLI_assert(a)
Definition BLI_assert.h:46
#define UNLIKELY(x)
nullptr float
#define atan
#define tan
#define sin
#define round
#define pow
#define exp
#define cos
#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
#define asin
#define acos
ccl_device_inline float2 power(const float2 v, const float e)
#define T
T safe_floored_mod(const T &a, const T &b)
float safe_acos_approx(float x)
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 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 floored_mod(const T &a, const T &b)
void min_inplace(T &a, const T &b)
T min(const T &a, const T &b)
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)
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 square(const T &a)
T mod_periodic(const T &a, const T &b)
T cube(const T &a)
T max(const T &a, const T &b)
T abs(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.cc:36
max
Definition text_draw.cc:251