Commit: 399168f3c13fadb41c9fbec8a1b5c56cb6609343 Author: Hans Goudey Date: Wed Feb 16 10:28:18 2022 -0600 Branches: master https://developer.blender.org/rB399168f3c13fadb41c9fbec8a1b5c56cb6609343
BLI: Implement templated math functions for basic types This is meant to complement the `blender::math` functions recently added by D13791. It's sometimes desired to template an operation to work on vector types, but also basic types like `float` and `int`. This patch adds that ability with a new `BLI_math_base.hh` header. The existing vector math header is changed to use the `vec_base` type more explicitly, to allow the compiler's generic function overload resolution to determine which implementation of each math function to use. This is a relatively large change, but it also makes the file significantly easier to understand by reducing the use of macros. Differential Revision: https://developer.blender.org/D14113 =================================================================== A source/blender/blenlib/BLI_math_base.hh M source/blender/blenlib/BLI_math_vec_types.hh M source/blender/blenlib/BLI_math_vector.hh M source/blender/blenlib/CMakeLists.txt M source/blender/blenlib/intern/delaunay_2d.cc M source/blender/blenlib/tests/BLI_math_base_test.cc =================================================================== diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh new file mode 100644 index 00000000000..6a988eda8a9 --- /dev/null +++ b/source/blender/blenlib/BLI_math_base.hh @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#include <algorithm> +#include <cmath> +#include <type_traits> + +#include "BLI_math_base_safe.h" +#include "BLI_math_vec_types.hh" +#include "BLI_utildefines.h" + +#ifdef WITH_GMP +# include "BLI_math_mpq.hh" +#endif + +namespace blender::math { + +template<typename T> inline bool is_zero(const T &a) +{ + return a == T(0); +} + +template<typename T> inline bool is_any_zero(const T &a) +{ + return is_zero(a); +} + +template<typename T> inline T abs(const T &a) +{ + return std::abs(a); +} + +template<typename T> inline T min(const T &a, const T &b) +{ + return std::min(a, b); +} + +template<typename T> inline T max(const T &a, const T &b) +{ + return std::max(a, b); +} + +template<typename T> inline T clamp(const T &a, const T &min, const T &max) +{ + return std::clamp(a, min, max); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T mod(const T &a, const T &b) +{ + return std::fmod(a, b); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> +inline T safe_mod(const T &a, const T &b) +{ + return (b != 0) ? std::fmod(a, b) : 0; +} + +template<typename T> inline void min_max(const T &value, T &min, T &max) +{ + min = math::min(value, min); + max = math::max(value, max); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> +inline T safe_divide(const T &a, const T &b) +{ + return (b != 0) ? a / b : T(0.0f); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T floor(const T &a) +{ + return std::floor(a); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T ceil(const T &a) +{ + return std::ceil(a); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T fract(const T &a) +{ + return a - std::floor(a); +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> +inline T interpolate(const T &a, const T &b, const T &t) +{ + return a * (1 - t) + b * t; +} + +template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> +inline T midpoint(const T &a, const T &b) +{ + return (a + b) * T(0.5); +} + +} // namespace blender::math diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh index 8d6f04ab15f..b6b3d15aefe 100644 --- a/source/blender/blenlib/BLI_math_vec_types.hh +++ b/source/blender/blenlib/BLI_math_vec_types.hh @@ -14,6 +14,10 @@ #include "BLI_utildefines.h" +#ifdef WITH_GMP +# include "BLI_math_mpq.hh" +#endif + namespace blender { /* clang-format off */ @@ -60,10 +64,10 @@ template<typename T> uint64_t vector_hash(const T &vec) return result; } -template<typename T> inline bool is_any_zero(const T &a) +template<typename T, int Size> inline bool is_any_zero(const vec_struct_base<T, Size> &a) { - for (int i = 0; i < T::type_length; i++) { - if (a[i] == typename T::base_type(0)) { + for (int i = 0; i < Size; i++) { + if (a[i] == T(0)) { return true; } } @@ -579,4 +583,13 @@ using double2 = vec_base<double, 2>; using double3 = vec_base<double, 3>; using double4 = vec_base<double, 4>; +template<typename T> +inline constexpr bool is_math_float_type = (std::is_floating_point_v<T> +#ifdef WITH_GMP + || std::is_same_v<T, mpq_class> +#endif +); + +template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>; + } // namespace blender diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh index d2ef2a1c5c8..3bb89bb26b2 100644 --- a/source/blender/blenlib/BLI_math_vector.hh +++ b/source/blender/blenlib/BLI_math_vector.hh @@ -15,10 +15,6 @@ #include "BLI_span.hh" #include "BLI_utildefines.h" -#ifdef WITH_GMP -# include "BLI_math_mpq.hh" -#endif - namespace blender::math { #ifndef NDEBUG @@ -33,277 +29,293 @@ namespace blender::math { # define BLI_ASSERT_UNIT(v) (void)(v) #endif -#define bT typename T::base_type - -#ifdef WITH_GMP -# define BLI_ENABLE_IF_FLT_VEC(T) \ - BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type> || \ - std::is_same_v<typename T::base_type, mpq_class>)) -#else -# define BLI_ENABLE_IF_FLT_VEC(T) BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type>)) -#endif - -#define BLI_ENABLE_IF_INT_VEC(T) BLI_ENABLE_IF((std::is_integral_v<typename T::base_type>)) - -template<typename T> inline bool is_zero(const T &a) +template<typename T, int Size> inline bool is_zero(const vec_base<T, Size> &a) { - for (int i = 0; i < T::type_length; i++) { - if (a[i] != bT(0)) { + for (int i = 0; i < Size; i++) { + if (a[i] != T(0)) { return false; } } return true; } -template<typename T> inline T abs(const T &a) +template<typename T, int Size> inline vec_base<T, Size> abs(const vec_base<T, Size> &a) { - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = a[i] >= 0 ? a[i] : -a[i]; } return result; } -template<typename T> inline T min(const T &a, const T &b) +template<typename T, int Size> +inline vec_base<T, Size> min(const vec_base<T, Size> &a, const vec_base<T, Size> &b) { - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = a[i] < b[i] ? a[i] : b[i]; } return result; } -template<typename T> inline T max(const T &a, const T &b) +template<typename T, int Size> +inline vec_base<T, Size> max(const vec_base<T, Size> &a, const vec_base<T, Size> &b) { - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = a[i] > b[i] ? a[i] : b[i]; } return result; } -template<typename T> inline T clamp(const T &a, const T &min_v, const T &max_v) +template<typename T, int Size> +inline T clamp(const vec_base<T, Size> &a, + const vec_base<T, Size> &min, + const vec_base<T, Size> &max) { - T result = a; - for (int i = 0; i < T::type_length; i++) { - CLAMP(result[i], min_v[i], max_v[i]); + vec_base<T, Size> result = a; + for (int i = 0; i < Size; i++) { + std::clamp(result[i], min[i], max[i]); } return result; } -template<typename T> inline T clamp(const T &a, const bT &min_v, const bT &max_v) +template<typename T, int Size> +inline vec_base<T, Size> clamp(const vec_base<T, Size> &a, const T &min, const T &max) { - T result = a; - for (int i = 0; i < T::type_length; i++) { - CLAMP(result[i], min_v, max_v); + vec_base<T, Size> result = a; + for (int i = 0; i < Size; i++) { + std::clamp(result[i], min, max); } return result; } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, const T &b) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))> +inline vec_base<T, Size> mod(const vec_base<T, Size> &a, const vec_base<T, Size> &b) { - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { BLI_assert(b[i] != 0); result[i] = std::fmod(a[i], b[i]); } return result; } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, bT b) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))> +inline vec_base<T, Size> mod(const vec_base<T, Size> &a, const T &b) { BLI_assert(b != 0); - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = std::fmod(a[i], b); } return result; } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, const T &b) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))> +inline T safe_mod(const vec_base<T, Size> &a, const vec_base<T, Size> &b) { - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = (b[i] != 0) ? std::fmod(a[i], b[i]) : 0; } return result; } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, bT b) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))> +inline T safe_mod(const vec_base<T, Size> &a, const T &b) { if (b == 0) { - return T(0.0f); + return vec_base<T, Size>(0); } - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = std::fmod(a[i], b); } return result; } -template<typename T> inline void min_max(const T &vector, T &min_vec, T &max_vec) +template<typename T, int Size> +inline void min_max(const vec_base<T, Size> &vector, + vec_base<T, Size> &min, + vec_base<T, Size> &max) { - min_vec = min(vector, min_vec); - max_vec = max(vector, max_vec); + min = math::min(vector, min); + max = math::max(vector, max); } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const T &b) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))> +inline vec_base<T, Size> safe_divide(const vec_base<T, Size> &a, const vec_base<T, Size> &b) { - T result; - for (int i = 0; i < T::type_length; i++) { + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { result[i] = (b[i] == 0) ? 0 : a[i] / b[i]; } return result; } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const bT b) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))> +inline vec_base<T, Size> safe_divide(const vec_base<T, Size> &a, const T &b) { - return (b != 0) ? a / b : T(0.0f); + return (b != 0) ? a / b : vec_base<T, Size>(0.0f); } -template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T floor(const T &a) +template<typename T, int Size, BLI_ENABLE_IF((is_math_float_ @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
