2022-02-16 10:28:18 -06:00
|
|
|
/* 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_utildefines.h"
|
|
|
|
|
|
|
|
namespace blender::math {
|
|
|
|
|
2022-05-31 16:55:14 +02:00
|
|
|
template<typename T> inline constexpr bool is_math_float_type = std::is_floating_point_v<T>;
|
2022-03-25 09:57:10 -05:00
|
|
|
template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>;
|
|
|
|
|
2022-02-16 10:28:18 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-01-13 22:58:45 +01:00
|
|
|
template<typename T> inline T sign(const T &a)
|
|
|
|
{
|
|
|
|
return (T(0) < a) - (a < T(0));
|
|
|
|
}
|
|
|
|
|
2022-02-16 10:28:18 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-06-20 16:22:04 +02:00
|
|
|
template<typename T> inline void max_inplace(T &a, const T &b)
|
|
|
|
{
|
|
|
|
a = math::max(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> inline void min_inplace(T &a, const T &b)
|
|
|
|
{
|
|
|
|
a = math::min(a, b);
|
|
|
|
}
|
|
|
|
|
2022-02-16 10:28:18 -06:00
|
|
|
template<typename T> inline T clamp(const T &a, const T &min, const T &max)
|
|
|
|
{
|
|
|
|
return std::clamp(a, min, max);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T> inline T mod(const T &a, const T &b)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
|
|
|
return std::fmod(a, b);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T> inline T safe_mod(const T &a, const T &b)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T> inline T safe_divide(const T &a, const T &b)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
|
|
|
return (b != 0) ? a / b : T(0.0f);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T> inline T floor(const T &a)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
|
|
|
return std::floor(a);
|
|
|
|
}
|
|
|
|
|
2023-03-10 12:58:10 +11:00
|
|
|
/**
|
|
|
|
* Repeats the saw-tooth pattern even on negative numbers.
|
|
|
|
* ex: `mod_periodic(-3, 4) = 1`, `mod(-3, 4)= -3`
|
|
|
|
*/
|
2023-03-09 18:15:22 +01:00
|
|
|
template<typename T> inline T mod_periodic(const T &a, const T &b)
|
|
|
|
{
|
|
|
|
return a - (b * math::floor(a / b));
|
|
|
|
}
|
|
|
|
template<> inline int64_t mod_periodic(const int64_t &a, const int64_t &b)
|
|
|
|
{
|
|
|
|
int64_t c = (a >= 0) ? a : (-1 - a);
|
|
|
|
int64_t tmp = c - (b * (c / b));
|
|
|
|
/* Negative integers have different rounding that do not match floor(). */
|
|
|
|
return (a >= 0) ? tmp : (b - 1 - tmp);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T> inline T ceil(const T &a)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
|
|
|
return std::ceil(a);
|
|
|
|
}
|
|
|
|
|
2022-03-25 09:57:10 -05:00
|
|
|
template<typename T> inline T distance(const T &a, const T &b)
|
|
|
|
{
|
|
|
|
return std::abs(a - b);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T> inline T fract(const T &a)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
|
|
|
return a - std::floor(a);
|
|
|
|
}
|
|
|
|
|
2022-12-01 21:44:45 +01:00
|
|
|
template<typename T> inline T sqrt(const T &a)
|
|
|
|
{
|
|
|
|
return std::sqrt(a);
|
|
|
|
}
|
|
|
|
|
2022-11-28 17:20:31 +01:00
|
|
|
template<typename T> inline T cos(const T &a)
|
|
|
|
{
|
|
|
|
return std::cos(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> inline T sin(const T &a)
|
|
|
|
{
|
|
|
|
return std::sin(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> inline T tan(const T &a)
|
|
|
|
{
|
|
|
|
return std::tan(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> inline T acos(const T &a)
|
|
|
|
{
|
|
|
|
return std::acos(a);
|
|
|
|
}
|
|
|
|
|
2023-03-09 18:15:22 +01:00
|
|
|
template<typename T> inline T pow(const T &x, const T &power)
|
|
|
|
{
|
|
|
|
return std::pow(x, power);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> inline T safe_acos(const T &a)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(a <= T(-1))) {
|
|
|
|
return T(M_PI);
|
|
|
|
}
|
|
|
|
else if (UNLIKELY(a >= T(1))) {
|
|
|
|
return T(0);
|
|
|
|
}
|
|
|
|
return math::acos((a));
|
|
|
|
}
|
|
|
|
|
2022-11-28 17:20:31 +01:00
|
|
|
template<typename T> inline T asin(const T &a)
|
|
|
|
{
|
|
|
|
return std::asin(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> inline T atan(const T &a)
|
|
|
|
{
|
|
|
|
return std::atan(a);
|
|
|
|
}
|
|
|
|
|
2022-12-01 21:45:08 +01:00
|
|
|
template<typename T> inline T atan2(const T &y, const T &x)
|
2022-11-28 17:20:31 +01:00
|
|
|
{
|
2022-12-01 21:45:08 +01:00
|
|
|
return std::atan2(y, x);
|
2022-11-28 17:20:31 +01:00
|
|
|
}
|
|
|
|
|
BLI: Refactor matrix types & functions to use templates
This patch implements the matrix types (i.e:float4x4) by making heavy
usage of templating. All matrix functions are now outside of the vector
classes (inside the blender::math namespace) and are not vector size
dependent for the most part.
###Motivations
The goal/motivations of this rewrite are the same as the Vector C++ API (D13791):
- Template everything for making it work with any types and avoid code duplication.
- Use functional style instead of Object Oriented function call to allow a simple compatibility layer with GLSL syntax (see T103026 for more details).
- Allow most convenient constructor syntax and accessors (array subscript `matrix[c][r]`, or component alias `matrix.y.z`).
- Make it cover all features the current C API supports for adoption.
- Keep compilation time and debug performance somehow acceptable.
###Consideration:
- The new `MatView` class can be generated by `my_float.view<NumCol, NumRow, StartCol, StartRow>()` (with the last 2 being optionnal). This one allows modifying parts of the source matrix in place. It isn't pretty and duplicates a lot of code, but it is needed mainly to replace `normalize_m4`. At least I think it is a good starting point that can refined further.
- An exhaustive list of missing `BLI_math_matrix.h` functions from the new API can be found here P3373.
- This adds new Rotation types in order to have a clean API. This will be extended when we port the full Rotation API. The types are made so that they don't allow implicit down-casting to their vector representation.
- Some functions make direct use of the Eigen library, bypassing the Eigen C API defined in `intern/eigen`. Its use is contained inside `math_matrix.cc`. There is conflicting opinion wether we should use it more so I contained its usage to almost the tasks as in the C API for now.
Reviewed By: sergey, JacquesLucke, HooglyBoogly, Severin, brecht
Differential Revision: https://developer.blender.org/D16625
2023-01-06 17:02:28 +01:00
|
|
|
template<typename T> inline T hypot(const T &y, const T &x)
|
|
|
|
{
|
|
|
|
return std::hypot(y, x);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:59:14 +01:00
|
|
|
template<typename T, typename FactorT>
|
2022-03-25 09:57:10 -05:00
|
|
|
inline T interpolate(const T &a, const T &b, const FactorT &t)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
2022-05-18 17:00:19 +02:00
|
|
|
auto result = a * (1 - t) + b * t;
|
|
|
|
if constexpr (std::is_integral_v<T> && std::is_floating_point_v<FactorT>) {
|
|
|
|
result = std::round(result);
|
|
|
|
}
|
|
|
|
return result;
|
2022-02-16 10:28:18 -06:00
|
|
|
}
|
|
|
|
|
2022-03-25 09:57:10 -05:00
|
|
|
template<typename T> inline T midpoint(const T &a, const T &b)
|
2022-02-16 10:28:18 -06:00
|
|
|
{
|
2022-05-18 17:00:19 +02:00
|
|
|
auto result = (a + b) * T(0.5);
|
|
|
|
if constexpr (std::is_integral_v<T>) {
|
|
|
|
result = std::round(result);
|
|
|
|
}
|
|
|
|
return result;
|
2022-02-16 10:28:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace blender::math
|