Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenlib/BLI_math_base.hh121
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh23
-rw-r--r--source/blender/blenlib/BLI_math_vector.hh40
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/tests/BLI_math_base_test.cc23
5 files changed, 193 insertions, 15 deletions
diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh
new file mode 100644
index 00000000000..89a3fd3b826
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_base.hh
@@ -0,0 +1,121 @@
+/* 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 {
+
+/* To avoid being overly specific about what a "basic" type is, for now simply allow anything that
+ * isn't a `vec_base` type. In the future, if another implementation of these functions is needed,
+ * this would have to become more specific. */
+#define BLI_ENABLE_IF_BASE(T) BLI_ENABLE_IF((!is_math_vec_type<T>))
+
+#ifdef WITH_GMP
+# define BLI_ENABLE_IF_FLT(T) \
+ BLI_ENABLE_IF_BASE(T), \
+ BLI_ENABLE_IF((std::is_floating_point_v<T> || std::is_same_v<T, mpq_class>))
+#else
+# define BLI_ENABLE_IF_FLT(T) BLI_ENABLE_IF_BASE(T), BLI_ENABLE_IF((std::is_floating_point_v<T>))
+#endif
+
+#define BLI_ENABLE_IF_INT(T) BLI_ENABLE_IF_BASE(T), BLI_ENABLE_IF((std::is_integral_v<T>))
+
+template<typename T, BLI_ENABLE_IF_BASE(T)> inline bool is_zero(const T &a)
+{
+ return a == T(0);
+}
+
+template<typename T, BLI_ENABLE_IF_BASE(T)> inline bool is_any_zero(const T &a)
+{
+ return is_zero(a);
+}
+
+template<typename T, BLI_ENABLE_IF_BASE(T)> inline T abs(const T &a)
+{
+ return std::abs(a);
+}
+
+template<typename T, BLI_ENABLE_IF_BASE(T)> inline T min(const T &a, const T &b)
+{
+ return std::min(a, b);
+}
+
+template<typename T, BLI_ENABLE_IF_BASE(T)> inline T max(const T &a, const T &b)
+{
+ return std::max(a, b);
+}
+
+template<typename T, BLI_ENABLE_IF_BASE(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_FLT(T)> inline T mod(const T &a, const T &b)
+{
+ return std::fmod(a, b);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT(T)> inline T safe_mod(const T &a, const T &b)
+{
+ return (b != 0) ? std::fmod(a, b) : 0;
+}
+
+template<typename T, BLI_ENABLE_IF_BASE(T)>
+inline void min_max(const T &vector, T &min_vec, T &max_vec)
+{
+ min_vec = min(vector, min_vec);
+ max_vec = max(vector, max_vec);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT(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_FLT(T)> inline T floor(const T &a)
+{
+ return std::floor(a);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT(T)> inline T ceil(const T &a)
+{
+ return std::ceil(a);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT(T)> inline T fract(const T &a)
+{
+ return a - std::floor(a);
+}
+
+template<typename T, typename FactorT, BLI_ENABLE_IF_FLT(T), BLI_ENABLE_IF_FLT(FactorT)>
+inline T interpolate(const T &a, const T &b, const FactorT &t)
+{
+ return a * (1 - t) + b * t;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT(T)> inline T midpoint(const T &a, const T &b)
+{
+ return (a + b) * 0.5;
+}
+
+#undef BLI_ENABLE_IF_BASE
+#undef BLI_ENABLE_IF_FLT
+#undef BLI_ENABLE_IF_INT
+
+} // namespace blender::math
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
index ad885bde27d..b8a208f0a0d 100644
--- a/source/blender/blenlib/BLI_math_vec_types.hh
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -265,6 +265,16 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
} \
return *this;
+ bool is_any_zero() const
+ {
+ for (int i = 0; i < Size; i++) {
+ if ((*this)[i] == T(0)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** Arithmetic operators. */
friend vec_base operator+(const vec_base &a, const vec_base &b)
@@ -367,7 +377,7 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
vec_base &operator/=(T b)
{
- BLI_assert(b != T(0));
+ BLI_assert(!b.is_any_zero());
BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b);
}
@@ -579,4 +589,15 @@ using double2 = vec_base<double, 2>;
using double3 = vec_base<double, 3>;
using double4 = vec_base<double, 4>;
+template<typename T> constexpr bool is_math_vec_type = false;
+template<typename BaseType, int Size>
+constexpr bool is_math_vec_type<vec_base<BaseType, Size>> = true;
+
+static_assert(is_math_vec_type<int2>);
+static_assert(is_math_vec_type<uint4>);
+static_assert(is_math_vec_type<float2>);
+static_assert(is_math_vec_type<vec_base<float, 20>>);
+static_assert(!is_math_vec_type<int>);
+static_assert(!is_math_vec_type<float>);
+
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh
index d2ef2a1c5c8..32cc15e44a4 100644
--- a/source/blender/blenlib/BLI_math_vector.hh
+++ b/source/blender/blenlib/BLI_math_vector.hh
@@ -35,17 +35,25 @@ namespace blender::math {
#define bT typename T::base_type
+template<typename T>
+inline constexpr bool is_float_vector = (std::is_floating_point_v<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>))
+ || std::is_same_v<typename T::base_type, mpq_class>
#endif
+);
+
+template<typename T>
+inline constexpr bool is_integral_vector = std::is_integral_v<typename T::base_type>;
+
+/* In this file, only implement math functions for the vector types. This allows other
+ * files to use overloading to implement the same functions with different types. */
+#define BLI_ENABLE_IF_VEC(T) BLI_ENABLE_IF((is_math_vec_type<T>))
+
+#define BLI_ENABLE_IF_FLT_VEC(T) BLI_ENABLE_IF_VEC(T), BLI_ENABLE_IF((is_float_vector<T>))
-#define BLI_ENABLE_IF_INT_VEC(T) BLI_ENABLE_IF((std::is_integral_v<typename T::base_type>))
+#define BLI_ENABLE_IF_INT_VEC(T) BLI_ENABLE_IF_VEC(T), BLI_ENABLE_IF((is_integral_vector<T>))
-template<typename T> inline bool is_zero(const T &a)
+template<typename T, BLI_ENABLE_IF_VEC(T)> inline bool is_zero(const T &a)
{
for (int i = 0; i < T::type_length; i++) {
if (a[i] != bT(0)) {
@@ -55,7 +63,7 @@ template<typename T> inline bool is_zero(const T &a)
return true;
}
-template<typename T> inline T abs(const T &a)
+template<typename T, BLI_ENABLE_IF_VEC(T)> inline T abs(const T &a)
{
T result;
for (int i = 0; i < T::type_length; i++) {
@@ -64,7 +72,7 @@ template<typename T> inline T abs(const T &a)
return result;
}
-template<typename T> inline T min(const T &a, const T &b)
+template<typename T, BLI_ENABLE_IF_VEC(T)> inline T min(const T &a, const T &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
@@ -73,7 +81,7 @@ template<typename T> inline T min(const T &a, const T &b)
return result;
}
-template<typename T> inline T max(const T &a, const T &b)
+template<typename T, BLI_ENABLE_IF_VEC(T)> inline T max(const T &a, const T &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
@@ -82,7 +90,8 @@ template<typename T> inline T max(const T &a, const T &b)
return result;
}
-template<typename T> inline T clamp(const T &a, const T &min_v, const T &max_v)
+template<typename T, BLI_ENABLE_IF_VEC(T)>
+inline T clamp(const T &a, const T &min_v, const T &max_v)
{
T result = a;
for (int i = 0; i < T::type_length; i++) {
@@ -91,7 +100,8 @@ template<typename T> inline T clamp(const T &a, const T &min_v, const T &max_v)
return result;
}
-template<typename T> inline T clamp(const T &a, const bT &min_v, const bT &max_v)
+template<typename T, BLI_ENABLE_IF_VEC(T)>
+inline T clamp(const T &a, const bT &min_v, const bT &max_v)
{
T result = a;
for (int i = 0; i < T::type_length; i++) {
@@ -141,7 +151,8 @@ template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, bT
return result;
}
-template<typename T> inline void min_max(const T &vector, T &min_vec, T &max_vec)
+template<typename T, BLI_ENABLE_IF_VEC(T)>
+inline void min_max(const T &vector, T &min_vec, T &max_vec)
{
min_vec = min(vector, min_vec);
max_vec = max(vector, max_vec);
@@ -197,7 +208,7 @@ template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT dot(const T &a, const T
return result;
}
-template<typename T> inline bT length_manhattan(const T &a)
+template<typename T, BLI_ENABLE_IF_VEC(T)> inline bT length_manhattan(const T &a)
{
bT result = std::abs(a[0]);
for (int i = 1; i < T::type_length; i++) {
@@ -354,6 +365,7 @@ template<typename T> struct isect_result {
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
isect_result<T> isect_seg_seg(const T &v1, const T &v2, const T &v3, const T &v4);
+#undef BLI_ENABLE_IF_VEC
#undef BLI_ENABLE_IF_FLT_VEC
#undef BLI_ENABLE_IF_INT_VEC
#undef bT
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 29015084679..e67d673eb73 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -220,6 +220,7 @@ set(SRC
BLI_map.hh
BLI_map_slots.hh
BLI_math.h
+ BLI_math_base.hh
BLI_math_base.h
BLI_math_base_safe.h
BLI_math_bits.h
diff --git a/source/blender/blenlib/tests/BLI_math_base_test.cc b/source/blender/blenlib/tests/BLI_math_base_test.cc
index 33acefeeac2..34da00cb4bf 100644
--- a/source/blender/blenlib/tests/BLI_math_base_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_base_test.cc
@@ -4,6 +4,12 @@
#include "BLI_math.h"
+#include "BLI_math_vector.hh"
+
+#include "BLI_math_base.hh"
+
+namespace blender::tests {
+
/* In tests below, when we are using -1.0f as max_diff value, we actually turn the function into a
* pure-ULP one. */
@@ -131,3 +137,20 @@ TEST(math_base, FloorPowerOf10)
EXPECT_NEAR(floor_power_of_10(100.1f), 100.0f, 1e-4f);
EXPECT_NEAR(floor_power_of_10(99.9f), 10.0f, 1e-4f);
}
+
+TEST(math_base, MinVectorAndFloat)
+{
+ EXPECT_EQ(math::min(1.0f, 2.0f), 1.0f);
+}
+
+TEST(math_base, ClampInt)
+{
+ EXPECT_EQ(math::clamp(111, -50, 101), 101);
+}
+
+TEST(math_base, Midpoint)
+{
+ EXPECT_NEAR(math::midpoint(100.0f, 200.0f), 150.0f, 1e-4f);
+}
+
+} // namespace blender::tests