BLI: Add more per-element functions for vectors #108705

Merged
Sergey Sharybin merged 2 commits from Sergey/blender:vector_math into main 2023-06-07 15:15:42 +02:00
3 changed files with 128 additions and 18 deletions

View File

@ -91,6 +91,11 @@ template<typename T> inline T floor(const T &a)
return std::floor(a);
}
template<typename T> inline T round(const T &a)
{
return std::round(a);
}
/**
* Repeats the saw-tooth pattern even on negative numbers.
* ex: `mod_periodic(-3, 4) = 1`, `mod(-3, 4)= -3`
@ -127,6 +132,20 @@ template<typename T> inline T sqrt(const T &a)
return std::sqrt(a);
}
/* Inverse value.
* If the input is zero the output is NaN. */
template<typename T> inline T rcp(const T &a)
{
return T(1) / a;
}
/* Inverse value.
* If the input is zero the output is zero. */
template<typename T> inline T safe_rcp(const T &a)
{
return a ? T(1) / a : T(0);
}
template<typename T> inline T cos(const T &a)
{
return std::cos(a);

View File

@ -111,7 +111,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result = a;
for (int i = 0; i < Size; i++) {
result[i] = std::clamp(result[i], min[i], max[i]);
result[i] = math::clamp(result[i], min[i], max[i]);
}
return result;
}
@ -121,7 +121,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result = a;
for (int i = 0; i < Size; i++) {
result[i] = std::clamp(result[i], min, max);
result[i] = math::clamp(result[i], min, max);
}
return result;
}
@ -132,7 +132,7 @@ template<typename T, int Size>
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
BLI_assert(b[i] != 0);
result[i] = std::fmod(a[i], b[i]);
result[i] = math::mod(a[i], b[i]);
}
return result;
}
@ -143,7 +143,7 @@ template<typename T, int Size>
BLI_assert(b != 0);
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::fmod(a[i], b);
result[i] = math::mod(a[i], b);
}
return result;
}
@ -157,7 +157,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = (b[i] != 0) ? std::fmod(a[i], b[i]) : 0;
result[i] = (b[i] != 0) ? math::mod(a[i], b[i]) : 0;
}
return result;
}
@ -173,7 +173,7 @@ template<typename T, int Size>
}
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::fmod(a[i], b);
result[i] = math::mod(a[i], b);
}
return result;
}
@ -187,7 +187,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::pow(x[i], y);
result[i] = math::pow(x[i], y);
}
return result;
}
@ -201,7 +201,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::pow(x[i], y[i]);
result[i] = math::pow(x[i], y[i]);
}
return result;
}
@ -276,7 +276,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::floor(a[i]);
result[i] = math::floor(a[i]);
}
return result;
}
@ -286,7 +286,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::round(a[i]);
result[i] = math::round(a[i]);
}
return result;
}
@ -296,7 +296,62 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::ceil(a[i]);
result[i] = math::ceil(a[i]);
}
return result;
}
/**
* Per-element square root.
* Negative elements are evaluated to NaN.
*/
template<typename T, int Size>
[[nodiscard]] inline VecBase<T, Size> sqrt(const VecBase<T, Size> &a)
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = math::sqrt(a[i]);
}
return result;
}
/**
* Per-element square root.
* Negative elements are evaluated to zero.
*/
template<typename T, int Size>
[[nodiscard]] inline VecBase<T, Size> safe_sqrt(const VecBase<T, Size> &a)
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = a[i] >= T(0) ? math ::sqrt(a[i]) : T(0);
}
return result;
}
/**
* Per-element inverse.
* Zero elements are evaluated to NaN.
*/
template<typename T, int Size> [[nodiscard]] inline VecBase<T, Size> rcp(const VecBase<T, Size> &a)
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = math::rcp(a[i]);
}
return result;
}
/**
* Per-element inverse.
* Zero elements are evaluated to zero.
*/
template<typename T, int Size>
[[nodiscard]] inline VecBase<T, Size> safe_rcp(const VecBase<T, Size> &a)
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = math::safe_rcp(a[i]);
}
return result;
}
@ -306,7 +361,7 @@ template<typename T, int Size>
{
VecBase<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = a[i] - std::floor(a[i]);
result[i] = math::fract(a[i]);
}
return result;
}
@ -332,9 +387,9 @@ template<typename T, int Size>
*/
template<typename T, int Size> [[nodiscard]] inline T length_manhattan(const VecBase<T, Size> &a)
{
T result = std::abs(a[0]);
T result = math::abs(a[0]);
for (int i = 1; i < Size; i++) {
result += std::abs(a[i]);
result += math::abs(a[i]);
}
return result;
}
@ -346,7 +401,7 @@ template<typename T, int Size> [[nodiscard]] inline T length_squared(const VecBa
template<typename T, int Size> [[nodiscard]] inline T length(const VecBase<T, Size> &a)
{
return std::sqrt(length_squared(a));
return math::sqrt(length_squared(a));
}
/** Return true if each individual column is unit scaled. Mainly for assert usage. */
@ -356,8 +411,8 @@ template<typename T, int Size> [[nodiscard]] inline bool is_unit_scale(const Vec
* normalized and in the case we don't want NAN to be raising asserts since there
* is nothing to be done in that case. */
const T test_unit = math::length_squared(v);
return (!(std::abs(test_unit - T(1)) >= AssertUnitEpsilon<T>::value) ||
!(std::abs(test_unit) >= AssertUnitEpsilon<T>::value));
return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon<T>::value) ||
!(math::abs(test_unit) >= AssertUnitEpsilon<T>::value));
}
template<typename T, int Size>
@ -593,7 +648,7 @@ template<typename T, int Size>
const T epsilon = T(0))
{
for (int i = 0; i < Size; i++) {
if (std::abs(a[i] - b[i]) > epsilon) {
if (math::abs(a[i] - b[i]) > epsilon) {
return false;
}
}

View File

@ -136,4 +136,40 @@ TEST(math_vector, Sign)
EXPECT_FLOAT_EQ(result.z, 0);
}
TEST(math_vector, sqrt)
{
const float3 a(1.0f, 4.0f, 9.0f);
const float3 result = math::sqrt(a);
EXPECT_NEAR(result.x, 1.0f, 1e-6f);
EXPECT_NEAR(result.y, 2.0f, 1e-6f);
EXPECT_NEAR(result.z, 3.0f, 1e-6f);
}
TEST(math_vector, safe_sqrt)
{
const float3 a(1.0f, -4.0f, 9.0f);
const float3 result = math::safe_sqrt(a);
EXPECT_NEAR(result.x, 1.0f, 1e-6f);
EXPECT_NEAR(result.y, 0.0f, 1e-6f);
EXPECT_NEAR(result.z, 3.0f, 1e-6f);
}
TEST(math_vector, rcp)
{
const float3 a(1.0f, 2.0f, 4.0f);
const float3 result = math::rcp(a);
EXPECT_NEAR(result.x, 1.0f, 1e-6f);
EXPECT_NEAR(result.y, 0.5f, 1e-6f);
EXPECT_NEAR(result.z, 0.25f, 1e-6f);
}
TEST(math_vector, safe_rcp)
{
const float3 a(1.0f, 0.0f, 4.0f);
const float3 result = math::safe_rcp(a);
EXPECT_NEAR(result.x, 1.0f, 1e-6f);
EXPECT_NEAR(result.y, 0.0f, 1e-6f);
EXPECT_NEAR(result.z, 0.25f, 1e-6f);
}
} // namespace blender::tests