BLI: Adjust interpolation to support integers, other tweaks

In order to allow interpolation of integers with a float, add a separate
template parameter for the factor and multiplication types.
Also move some helper constexpr variables to the "base" header
(reversing the dependency to "base" -> "vector").

This also adds a distance function for scalar types, which is
helpful to allow sharing code between vectors and basic types.

Differential Revision: https://developer.blender.org/D14446
This commit is contained in:
Hans Goudey 2022-03-25 09:57:10 -05:00
parent 1243cb803e
commit 378022c797
5 changed files with 46 additions and 18 deletions

View File

@ -12,7 +12,6 @@
#include <type_traits>
#include "BLI_math_base_safe.h"
#include "BLI_math_vec_types.hh"
#include "BLI_utildefines.h"
#ifdef WITH_GMP
@ -21,6 +20,15 @@
namespace blender::math {
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>;
template<typename T> inline bool is_zero(const T &a)
{
return a == T(0);
@ -84,19 +92,23 @@ template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T ceil(const
return std::ceil(a);
}
template<typename T> inline T distance(const T &a, const T &b)
{
return std::abs(a - b);
}
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)
template<typename T, typename FactorT, BLI_ENABLE_IF((is_math_float_type<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((is_math_float_type<T>))>
inline T midpoint(const T &a, const T &b)
template<typename T> inline T midpoint(const T &a, const T &b)
{
return (a + b) * T(0.5);
}

View File

@ -321,7 +321,7 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b[i]);
}
friend vec_base operator*(const vec_base &a, T b)
template<typename FactorT> friend vec_base operator*(const vec_base &a, FactorT b)
{
BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b);
}
@ -579,13 +579,4 @@ 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

View File

@ -10,7 +10,7 @@
#include <cmath>
#include <type_traits>
#include "BLI_math_base_safe.h"
#include "BLI_math_base.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
@ -339,10 +339,10 @@ inline vec_base<T, 3> cross_poly(Span<vec_base<T, 3>> poly)
return n;
}
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
template<typename T, typename FactorT, int Size, BLI_ENABLE_IF((is_math_float_type<FactorT>))>
inline vec_base<T, Size> interpolate(const vec_base<T, Size> &a,
const vec_base<T, Size> &b,
const T &t)
const FactorT &t)
{
return a * (1 - t) + b * t;
}

View File

@ -151,4 +151,9 @@ TEST(math_base, Midpoint)
EXPECT_NEAR(math::midpoint(100.0f, 200.0f), 150.0f, 1e-4f);
}
TEST(math_base, InterpolateInt)
{
EXPECT_EQ(math::interpolate(100, 200, 0.4f), 140);
}
} // namespace blender::tests

View File

@ -85,4 +85,24 @@ TEST(math_vector, Clamp)
EXPECT_EQ(result_2.z, -50);
}
TEST(math_vector, InterpolateInt)
{
const int3 a(0, -100, 50);
const int3 b(0, 100, 100);
const int3 result = math::interpolate(a, b, 0.75);
EXPECT_EQ(result.x, 0);
EXPECT_EQ(result.y, 50);
EXPECT_EQ(result.z, 87);
}
TEST(math_vector, InterpolateFloat)
{
const float3 a(40.0f, -100.0f, 50.0f);
const float3 b(20.0f, 100.0f, 100.0f);
const float3 result = math::interpolate(a, b, 0.5);
EXPECT_FLOAT_EQ(result.x, 30.0f);
EXPECT_FLOAT_EQ(result.y, 0.0f);
EXPECT_FLOAT_EQ(result.z, 75.0f);
}
} // namespace blender::tests