BLI math: Do not use BLI_ASSERT_
C-style checks in modern cpp code.
The old C-style `BLI_ASSERT_UNIT_V...` assert macros have a few issues: * They are named `unit`, but also consider a zero-length vector as valid. * They use a fairly high epsilon value, which was defined because vertex normals used to be stored as shorts. Fortunately, these are used only in one place in the modern BLI_math C++ code AFAICS, which is `math::rotate_direction_around_axis`. This commit adds some utils to check for vectors being (almost) unit or zero length, using more modern bases for epsilon values (from `std::numeric_limits`). * `is_zero` keeps its existing default arror of `0` (i.e. strictly null vector by default). That way, current behavior is not changed, and in most cases null vectors are explicitely created as exactly null. * `is_unit` uses a default 10 times the type's epsilon, as a zero epsilon would virtually never succeed here. And it modifies `rotate_direction_around_axis` to: * Assert that `axis` is a unit vector. * Early-out in case given `direction` is a null vector, or rotating angle is zero. * Assert about `direction` being a unit vector otherwise. Note that this will make `rotate_direction_around_axis` use much stricter epsilon error factors. This does not seem to affect any of the files that triggered asserts prior to recent fix in e18dd894b8 though. Pull Request: https://projects.blender.org/blender/blender/pulls/122482
This commit is contained in:
parent
43a47f39f9
commit
dd3222d2f8
@ -18,32 +18,6 @@
|
||||
|
||||
namespace blender::math {
|
||||
|
||||
/**
|
||||
* Returns true if all components are exactly equal to 0.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline bool is_zero(const VecBase<T, Size> &a)
|
||||
{
|
||||
for (int i = 0; i < Size; i++) {
|
||||
if (a[i] != T(0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if at least one component is exactly equal to 0.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline bool is_any_zero(const VecBase<T, Size> &a)
|
||||
{
|
||||
for (int i = 0; i < Size; i++) {
|
||||
if (a[i] == T(0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given vectors are equal within the given epsilon.
|
||||
* The epsilon is scaled for each component by magnitude of the matching component of `a`.
|
||||
@ -745,6 +719,48 @@ template<typename T, int Size>
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the absolute values of all components are smaller than given epsilon (0 by
|
||||
* default).
|
||||
*
|
||||
* \note Does not compute the actual length of the vector, for performance.
|
||||
*/
|
||||
template<typename T, int Size>
|
||||
[[nodiscard]] inline bool is_zero(const VecBase<T, Size> &a, const T epsilon = T(0))
|
||||
{
|
||||
for (int i = 0; i < Size; i++) {
|
||||
if (math::abs(a[i]) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if at least one component is exactly equal to 0.
|
||||
*/
|
||||
template<typename T, int Size> [[nodiscard]] inline bool is_any_zero(const VecBase<T, Size> &a)
|
||||
{
|
||||
for (int i = 0; i < Size; i++) {
|
||||
if (a[i] == T(0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the squared length of the vector is (almost) equal to 1 (with a
|
||||
* `10 * std::numeric_limits<T>::epsilon()` epsilon error by default).
|
||||
*/
|
||||
template<typename T, int Size>
|
||||
[[nodiscard]] inline bool is_unit(const VecBase<T, Size> &a,
|
||||
const T epsilon = T(10) * std::numeric_limits<T>::epsilon())
|
||||
{
|
||||
const T length = length_squared(a);
|
||||
return math::abs(length - T(1)) <= epsilon;
|
||||
}
|
||||
|
||||
/** Intersections. */
|
||||
|
||||
template<typename T> struct isect_result {
|
||||
|
@ -111,9 +111,13 @@ void generate_axes_to_quaternion_switch_cases()
|
||||
|
||||
float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, const float angle)
|
||||
{
|
||||
BLI_ASSERT_UNIT_V3(direction);
|
||||
BLI_ASSERT_UNIT_V3(axis);
|
||||
BLI_assert(!math::is_zero(axis));
|
||||
BLI_assert(math::is_unit(axis));
|
||||
|
||||
if (UNLIKELY(angle == 0.0f || math::is_zero(direction, std::numeric_limits<float>::epsilon()))) {
|
||||
return direction;
|
||||
}
|
||||
|
||||
BLI_assert(math::is_unit(direction));
|
||||
|
||||
const float3 axis_scaled = axis * math::dot(direction, axis);
|
||||
const float3 diff = direction - axis_scaled;
|
||||
|
Loading…
Reference in New Issue
Block a user