opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
common_functions.h
Go to the documentation of this file.
1#pragma once
2
7
8#include <algorithm>
9#include <cmath>
10#include <concepts>
11#include <cstddef>
12#include <initializer_list>
13#include <iterator>
14#include <numeric>
15#include <ranges>
16#include <span>
17#include <tuple>
18#include <type_traits>
19
20namespace osc
21{
22 // returns the absolute value of `num`
23 template<std::signed_integral T>
25 {
26 return std::abs(num);
27 }
28
29 // returns the absolute value of `num`
30 template<std::floating_point T>
31 T abs(T num)
32 {
33 return std::fabs(num);
34 }
35
36 // satisfied if `abs(x)` is a valid expression for type `T`
37 template<typename T>
38 concept HasAbsFunction = requires (T x) {
39 { abs(x) } -> std::same_as<T>;
40 };
41
42 // returns a vector containing `abs(xv)` for each `xv` in `x`
43 template<HasAbsFunction T, size_t N>
45 {
46 return map(x, [](const T& xv) { return abs(xv); });
47 }
48
49 // returns the largest integer value not greater than `num`
50 template<std::floating_point T>
52 {
53 return std::floor(num);
54 }
55
56 // satisfied if `floor(x)` is a valid expression for type `T`
57 template<typename T>
58 concept HasFloorFunction = requires (T x) {
59 { floor(x) } -> std::same_as<T>;
60 };
61
62 // returns a vector containing `floor(xv)` for each `xv` in `x`
63 template<HasFloorFunction T, size_t N>
65 {
66 return map(x, [](const T& xv) { return floor(xv); });
67 }
68
69 // returns a floating point value with magnitude `mag` and the sign of `sgn`
70 template<std::floating_point T>
72 {
73 return std::copysign(mag, sgn);
74 }
75
76 // returns the integer remainder of the division operation `x / y`
77 template<std::integral T>
78 constexpr T mod(T x, T y)
79 {
80 return x % y;
81 }
82
83 // returns the floating-point remainder of the division operation `x / y`
84 template<std::floating_point T>
85 T mod(T x, T y)
86 {
87 return std::fmod(x, y);
88 }
89
90 // satisfied if `mod(x, y)` is a valid expression for type `T`
91 template<typename T>
92 concept HasModFunction = requires (T x, T y) {
93 { mod(x, y) } -> std::same_as<T>;
94 };
95
96 // returns a vector containing `mod(xv, yv)` for each pair `(xv, yv)` in `x` and `y`
97 template<HasModFunction T, size_t N>
98 constexpr Vector<T, N> mod(const Vector<T, N>& x, const Vector<T, N>& y)
99 {
100 return map(x, y, [](const T& xv, const T& yv) { return mod(xv, yv); });
101 }
102
103 // satisfied if `min(x, y)` is a valid expression for type `T`
104 template<typename T>
105 concept HasMinFunction = requires(T x, T y) {
106 { min(x, y) } -> std::convertible_to<T>;
107 };
108
109 // returns a vector containing `min(xv, yv)` for each `(xv, yv)` in `x` and `y`
110 template<HasMinFunction T, size_t N>
112 {
113 return map(x, y, [](const T& xv, const T& yv) { return min(xv, yv); });
114 }
115
116 // satisfied if `max(x, y)` is a valid expression for type `T`
117 template<typename T>
118 concept HasMaxFunction = requires(T x, T y) {
119 { max(x, y) } -> std::convertible_to<T>;
120 };
121
122 // returns a vector containing `max(xv, yv)` for each `(xv, yv)` in `x` and `y`
123 template<HasMaxFunction T, size_t N>
124 requires std::is_arithmetic_v<T>
126 {
127 return map(x, y, [](const T& xv, const T& yv) { return max(xv, yv); });
128 }
129
130 // satisfied if `clamp(v, lo, hi)` is a valid expression for type `T`
131 template<typename T>
132 concept HasClampFunction = requires(T v, T lo, T hi) {
133 { clamp(v, lo, hi) } -> std::convertible_to<T>;
134 };
135
136 // returns a vector containing `clamp(vv, lowv, hiv)` for each `(vv, lowv, hiv)` in `v`, `low`, and `hi`
137 template<HasClampFunction T, size_t N>
139 {
140 return map(v, lo, hi, [](const T& vv, const T& lov, const T& hiv) { return clamp(vv, lov, hiv); });
141 }
142
143 // returns a vector containing `clamp(vv, lo, hi)` for each `vv` in `v`
144 template<HasClampFunction T, size_t N>
145 constexpr Vector<T, N> elementwise_clamp(const Vector<T, N>& v, const T& lo, const T& hi)
146 {
147 return map(v, [&lo, &hi](const T& vv) { return clamp(vv, lo, hi); });
148 }
149
150 // returns `clamp(num, T{0}, T{1})`
151 template<std::floating_point T>
152 constexpr T saturate(T num)
153 {
154 return clamp(num, static_cast<T>(0), static_cast<T>(1));
155 }
156
157 // satisfied if `saturate(x)` is a valid expression for type `T`
158 template<typename T>
159 concept HasSaturateFunction = requires(T x) {
160 { saturate(x) } -> std::convertible_to<T>;
161 };
162
163 // returns a vector containing `saturate(xv)` for each `xv` in `x`
164 template<HasSaturateFunction T, size_t N>
166 {
167 return map(x, [](const T& xv) { return saturate(xv); });
168 }
169
170 // returns the equivalent of `a + t(b - a)` (linear interpolation with extrapolation)
171 template<
172 typename Arithmetic1,
173 typename Arithmetic2,
174 typename Arithmetic3
175 >
176 requires
177 std::is_arithmetic_v<Arithmetic1> and
178 std::is_arithmetic_v<Arithmetic2> and
179 std::is_arithmetic_v<Arithmetic3>
180 constexpr auto lerp(const Arithmetic1& a, const Arithmetic2& b, const Arithmetic3& t)
181 {
182 return std::lerp(a, b, t);
183 }
184
185 // satisfied if `lerp(a, b, t)` is a valid expression for type `T` and interpolant type `Arithmetic`
186 template<typename T, typename TInterpolant>
187 concept HasLerpFunction = requires(T a, T b, TInterpolant t) {
188 { lerp(a, b, t) } -> std::convertible_to<T>;
189 };
190
191 // returns a vector containing `lerp(xv, yv, t)` for each `(xv, yv)` in `x` and `y`
192 template<typename T, size_t N, typename TInterpolant>
194 constexpr auto lerp(const Vector<T, N>& x, const Vector<T, N>& y, const TInterpolant& t) -> Vector<decltype(lerp(x[0], y[0], t)), N>
195 {
196 return map(x, y, [&t](const T& xv, const T& yv) { return lerp(xv, yv, t); });
197 }
198
199 // returns a vector containing `xv == yv` for each `(xv, yv)` in `x` and `y`
200 template<std::equality_comparable T, size_t N>
202 {
203 return map(x, y, std::equal_to<T>{});
204 }
205
206 // satisfied if `x < y` is a valid expression that yields a `bool`
207 template<typename T>
208 concept LessThanComparable = requires(T x, T y) {
209 { x < y } -> std::convertible_to<bool>;
210 };
211
212 // returns a vector containing `xv < yv` for each `(xv, yv)` in `x` and `y`
213 template<LessThanComparable T, size_t N>
215 {
216 return map(x, y, std::less<T>{});
217 }
218
219 // returns a vector containing `xv < v` for each `xv` in `x`
220 template<LessThanComparable T, size_t N>
221 constexpr Vector<bool, N> elementwise_less(const Vector<T, N>& x, const T& v)
222 {
223 return map(x, [&v](const T& el) { return std::less<T>{}(el, v); });
224 }
225
226 // satisfied if `x <= y` is a valid expression that yields a `bool`
227 template<typename T>
228 concept LessThanOrEqualToComparable = requires(T x, T y) {
229 { x <= y } -> std::convertible_to<bool>;
230 };
231
232 // returns a vector containing `xv <= yv` for each `(xv, yv)` in `x` and `y`
233 template<LessThanOrEqualToComparable T, size_t N>
235 {
236 return map(x, y, std::less_equal<T>{});
237 }
238
239 // tests if the absolute difference between `x` and `y` is less than `absdiff`
240 template<typename T>
243 {
244 return abs(x - y) <= absdiff;
245 }
246
247 // returns a vector containing `equal_within_absdiff(xv, yv, absdiffv)` for each `(xv, yv, absdiffv)` in `x`, `y`, and `absdiff`
248 template<typename T, size_t N>
254
255 // returns a vector containing `equal_within_absdiff(xv, yv, absdiff)` for each `(xv, yv)` in `x` and `y`
256 template<typename T, size_t N>
259 {
260 return elementwise_less(abs(x - y), absdiff);
261 }
262
263 // tests if the absolute difference between `x` and `y` is less than epsilon (machine precision)
264 template<std::floating_point T>
266 {
268 }
269
270 // returns a vector containing `equal_within_epsilon(xv, yv)` for each `(xv, yv)` in `x` and `y`
271 template<std::floating_point T, size_t N>
276
277 // tests if the absolute difference between `x` and `y` is less than epsilon (machine precision) after
278 // accounting for scaling epsilon to the the magnitude of `x` and `y`
279 template<std::floating_point T>
281 {
282 // why:
283 //
284 // http://realtimecollisiondetection.net/blog/?p=89
285 // https://stackoverflow.com/questions/17333/what-is-the-most-effective-way-for-float-and-double-comparison
286 //
287 // machine epsilon is only relevant for numbers < 1.0, so the epsilon
288 // value must be scaled up to the magnitude of the operands if you need
289 // a more-correct equality comparison
290
291 const T scaled_epsilon = max(static_cast<T>(1.0), max(abs(x), abs(y))) * epsilon_v<T>;
292 return abs(x - y) < scaled_epsilon;
293 }
294
295 // tests if the relative difference between `x` and `y` is less than `reldiff` (fraction)
296 template<std::floating_point T>
298 {
299 // inspired from:
300 //
301 // - https://stackoverflow.com/questions/17333/what-is-the-most-effective-way-for-float-and-double-comparison
302 //
303 // but, specifically, you should read the section `Epsilon comparisons` here:
304 //
305 // - https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
306
307 return abs(x - y) <= reldiff * max(abs(x), abs(y));
308 }
309
310 // returns a vector containing `equal_within_reldiff(xv, yv, reldiff)` for each `(xv, yv)` in `x` and `y`
311 template<std::floating_point T, size_t N>
316
317 // tests if `num` is NaN
318 template<std::floating_point T>
319 bool isnan(T num)
320 {
321 return std::isnan(num);
322 }
323
324 // returns a vector containing `isnan(xv)` for each `xv` in `x`
325 template<std::floating_point T, size_t N>
327 {
328 return map(x, isnan<T>);
329 }
330
331 // returns the natural (base e) logarithm of `num`
332 template<std::floating_point T>
334 {
335 return std::log(num);
336 }
337
338 // returns the value of `base` raised to the power of `exp`
339 template<std::floating_point T>
341 {
342 return std::pow(base, exp);
343 }
344
345 // returns the midpoint between `a` and `b` while accounting for overflow
346 template<typename T>
347 requires std::is_integral_v<T> or std::is_floating_point_v<T> or std::is_pointer_v<T>
348 constexpr T midpoint(T a, T b)
349 {
350 return std::midpoint(a, b);
351 }
352
353 // satisfied if `midpoint(x, y)` is a valid expresssion for type `T`
354 template<typename T>
355 concept HasMidpointFunction = requires(T x, T y) {
356 { midpoint(x, y) } -> std::convertible_to<T>;
357 };
358
359 // returns a vector containing `midpoint(xv, yv)` for each `(xv, yv)` in `x` and `y`
360 template<typename T, size_t N>
362 {
363 return map(x, y, [](const T& xv, const T& yv) { return midpoint(xv, yv); });
364 }
365
366 // returns the arithmetic mean of the provided vectors, or `Vector<T, N>{}/T{0}` if provided no vectors
367 template<
368 std::ranges::range R,
369 typename T = typename std::ranges::range_value_t<R>::value_type,
370 size_t N = std::tuple_size_v<typename std::ranges::range_value_t<R>>
371 >
372 requires std::is_arithmetic_v<T>
373 constexpr Vector<T, N> centroid_of(const R& r)
374 {
375 return std::reduce(std::ranges::begin(r), std::ranges::end(r)) / static_cast<T>(std::ranges::size(r));
376 }
377
378 // returns the arithmetic mean of the provided vectors, or `Vector<T, N>{}/T{0}` if provided no vectors
379 template<typename T, size_t N>
380 requires std::is_arithmetic_v<T>
381 constexpr Vector<T, N> centroid_of(const std::initializer_list<Vector<T, N>>& vs)
382 {
383 return centroid_of(std::span<const Vector<T, N>>{vs});
384 }
385}
Definition vector.h:63
Definition common_functions.h:38
Definition common_functions.h:132
Definition common_functions.h:58
Definition common_functions.h:187
Definition common_functions.h:118
Definition common_functions.h:355
Definition common_functions.h:105
Definition common_functions.h:92
Definition common_functions.h:159
Definition common_functions.h:208
Definition common_functions.h:228
Definition custom_decoration_generator.h:5
bool equal_within_epsilon(T x, T y)
Definition common_functions.h:265
constexpr auto min(Angle< Rep1, Units1 > x, Angle< Rep2, Units2 > y) -> std::common_type_t< decltype(x), decltype(y)>
Definition angle.h:267
constexpr Angle< Rep, Units > clamp(const Angle< Rep, Units > &v, const AngleMin &min, const AngleMax &max)
Definition angle.h:303
constexpr auto map(const Rgba< T > &x, UnaryOperation op) -> Rgba< decltype(std::invoke(op, x[0]))>
Definition rgba.h:208
constexpr Vector3 centroid_of(const AABB &aabb)
Definition aabb_functions.h:20
bool equal_within_reldiff(T x, T y, T reldiff)
Definition common_functions.h:297
constexpr auto max(Angle< Rep1, Units1 > x, Angle< Rep2, Units2 > y) -> std::common_type_t< decltype(x), decltype(y)>
Definition angle.h:283
constexpr Vector< T, N > elementwise_clamp(const Vector< T, N > &v, const Vector< T, N > &lo, const Vector< T, N > &hi)
Definition common_functions.h:138
constexpr auto lerp(const Rgba< T > &x, const Rgba< T > &y, TInterpolant t)
Definition rgba.h:230
and LessThanComparable< T > bool equal_within_absdiff(T x, T y, T absdiff)
Definition common_functions.h:242
constexpr Rgba< T > saturate(const Rgba< T > &x)
Definition rgba.h:237
T abs(T num)
Definition common_functions.h:24
auto mod(Angle< Rep1, Units1 > x, Angle< Rep2, Units2 > y) -> std::common_type_t< decltype(x), decltype(y)>
Definition angle.h:251
T pow(T base, T exp)
Definition common_functions.h:340
or std::is_floating_point_v< T > or std::is_pointer_v< T > constexpr T midpoint(T a, T b)
Definition common_functions.h:348
bool equal_within_scaled_epsilon(T x, T y)
Definition common_functions.h:280
constexpr U to(T &&value)
Definition conversion.h:56
constexpr Vector< bool, N > elementwise_less(const Vector< T, N > &x, const Vector< T, N > &y)
Definition common_functions.h:214
bool isnan(T num)
Definition common_functions.h:319
constexpr Vector< bool, N > elementwise_equal(const Vector< T, N > &x, const Vector< T, N > &y)
Definition common_functions.h:201
constexpr Vector< T, N > elementwise_max(const Vector< T, N > &x, const Vector< T, N > &y)
Definition common_functions.h:125
constexpr Vector< T, N > elementwise_min(const Vector< T, N > &x, const Vector< T, N > &y)
Definition common_functions.h:111
and
Definition algorithms.h:158
T copysign(T mag, T sgn)
Definition common_functions.h:71
T floor(T num)
Definition common_functions.h:51
T log(T num)
Definition common_functions.h:333
constexpr Vector< bool, N > elementwise_less_equal(const Vector< T, N > &x, const Vector< T, N > &y)
Definition common_functions.h:234