BLI: Bounds: Add basic functions
The overall goal is to be able to eventually replace the `BLI_rect.h` C-style API. This only adds come basic functions and tests. Pull Request: https://projects.blender.org/blender/blender/pulls/118964
This commit is contained in:
parent
a58a2b0f5d
commit
a4e5469cc0
|
@ -17,7 +17,9 @@
|
|||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
namespace blender::bounds {
|
||||
namespace blender {
|
||||
|
||||
namespace bounds {
|
||||
|
||||
template<typename T> [[nodiscard]] inline Bounds<T> merge(const Bounds<T> &a, const Bounds<T> &b)
|
||||
{
|
||||
|
@ -115,4 +117,75 @@ template<typename T, typename RadiusT>
|
|||
[](const Bounds<T> &a, const Bounds<T> &b) { return merge(a, b); });
|
||||
}
|
||||
|
||||
} // namespace blender::bounds
|
||||
} // namespace bounds
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, int Size>
|
||||
[[nodiscard]] inline bool less_or_equal_than(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
|
||||
{
|
||||
for (int i = 0; i < Size; i++) {
|
||||
if (a[i] > b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T> inline bool Bounds<T>::is_empty() const
|
||||
{
|
||||
if constexpr (std::is_integral<T>::value || std::is_floating_point<T>::value) {
|
||||
return this->max <= this->min;
|
||||
}
|
||||
else {
|
||||
return detail::less_or_equal_than(this->max, this->min);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> inline T Bounds<T>::center() const
|
||||
{
|
||||
return math::midpoint(this->min, this->max);
|
||||
}
|
||||
|
||||
template<typename T> inline T Bounds<T>::size() const
|
||||
{
|
||||
return math::abs(max - min);
|
||||
}
|
||||
|
||||
template<typename T> inline void Bounds<T>::translate(const T &offset)
|
||||
{
|
||||
this->min += offset;
|
||||
this->max += offset;
|
||||
}
|
||||
|
||||
template<typename T> inline void Bounds<T>::scale_from_center(const T &scale)
|
||||
{
|
||||
const T center = this->center();
|
||||
const T new_half_size = this->size() / T(2) * scale;
|
||||
this->min = center - new_half_size;
|
||||
this->max = center + new_half_size;
|
||||
}
|
||||
|
||||
template<typename T> inline void Bounds<T>::resize(const T &new_size)
|
||||
{
|
||||
this->min = this->center() - (new_size / T(2));
|
||||
this->max = this->min + new_size;
|
||||
}
|
||||
|
||||
template<typename T> inline void Bounds<T>::recenter(const T &new_center)
|
||||
{
|
||||
const T offset = new_center - this->center();
|
||||
this->translate(offset);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename PaddingT>
|
||||
inline void Bounds<T>::pad(const PaddingT &padding)
|
||||
{
|
||||
this->min = this->min - padding;
|
||||
this->max = this->max + padding;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
@ -16,6 +16,52 @@ template<typename T> struct Bounds {
|
|||
Bounds() = default;
|
||||
Bounds(const T &value) : min(value), max(value) {}
|
||||
Bounds(const T &min, const T &max) : min(min), max(max) {}
|
||||
|
||||
/**
|
||||
* Returns true when the size of the bounds is zero (or negative).
|
||||
* This matches the behavior of #BLI_rcti_is_empty/#BLI_rctf_is_empty.
|
||||
*/
|
||||
bool is_empty() const;
|
||||
/**
|
||||
* Return the center (i.e. the midpoint) of the bounds.
|
||||
* This matches the behavior of #BLI_rctf_cent/#BLI_rcti_cent.
|
||||
*/
|
||||
T center() const;
|
||||
/**
|
||||
* Return the size of the bounds.
|
||||
* E.g. for a Bounds<float3> this would return the dimensions of bounding box as a float3.
|
||||
* This matches the behavior of #BLI_rctf_size/#BLI_rcti_size.
|
||||
*/
|
||||
T size() const;
|
||||
|
||||
/**
|
||||
* Translate the bounds by #offset.
|
||||
* This matches the behavior of #BLI_rctf_translate/#BLI_rcti_translate.
|
||||
*/
|
||||
void translate(const T &offset);
|
||||
/**
|
||||
* Scale the bounds from the center.
|
||||
* This matches the behavior of #BLI_rctf_scale/#BLI_rcti_scale.
|
||||
*/
|
||||
void scale_from_center(const T &scale);
|
||||
|
||||
/**
|
||||
* Resize the bounds in-place to ensure their size is #new_size.
|
||||
* The center of the bounds doesn't change.
|
||||
* This matches the behavior of #BLI_rctf_resize/#BLI_rcti_resize.
|
||||
*/
|
||||
void resize(const T &new_size);
|
||||
/**
|
||||
* Translate the bounds such that their center is #new_center.
|
||||
* This matches the behavior of #BLI_rctf_recenter/#BLI_rcti_recenter.
|
||||
*/
|
||||
void recenter(const T &new_center);
|
||||
|
||||
/**
|
||||
* Adds some padding to the bounds.
|
||||
* This matches the behavior of #BLI_rcti_pad/#BLI_rctf_pad.
|
||||
*/
|
||||
template<typename PaddingT> void pad(const PaddingT &padding);
|
||||
};
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
@ -12,6 +12,111 @@
|
|||
namespace blender::tests {
|
||||
|
||||
TEST(bounds, Empty)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(1.0f), float2(-1.0f));
|
||||
Bounds<float2> bounds3(float2(-1.0f), float2(1.0f));
|
||||
EXPECT_TRUE(bounds1.is_empty());
|
||||
EXPECT_TRUE(bounds2.is_empty());
|
||||
EXPECT_FALSE(bounds3.is_empty());
|
||||
}
|
||||
|
||||
TEST(bounds, EmptyInt)
|
||||
{
|
||||
Bounds<int> bounds1(0);
|
||||
Bounds<int> bounds2(1, -1);
|
||||
Bounds<int> bounds3(-1, 1);
|
||||
EXPECT_TRUE(bounds1.is_empty());
|
||||
EXPECT_TRUE(bounds2.is_empty());
|
||||
EXPECT_FALSE(bounds3.is_empty());
|
||||
}
|
||||
|
||||
TEST(bounds, Center)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-1.0f));
|
||||
Bounds<float2> bounds3(float2(-1.0f), float2(1.0f));
|
||||
Bounds<float2> bounds4(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
EXPECT_EQ(bounds1.center(), float2(0.0f));
|
||||
EXPECT_EQ(bounds2.center(), float2(-1.0f));
|
||||
EXPECT_EQ(bounds3.center(), float2(0.0f));
|
||||
EXPECT_EQ(bounds4.center(), float2(-0.5f, -0.5f));
|
||||
}
|
||||
|
||||
TEST(bounds, Size)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-1.0f));
|
||||
Bounds<float2> bounds3(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
EXPECT_EQ(bounds1.size(), float2(0.0f));
|
||||
EXPECT_EQ(bounds2.size(), float2(0.0f));
|
||||
EXPECT_EQ(bounds3.size(), float2(5.0f, 9.0f));
|
||||
}
|
||||
|
||||
TEST(bounds, Translate)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
bounds1.translate(float2(-1.0f));
|
||||
bounds2.translate(float2(2.0f));
|
||||
EXPECT_EQ(bounds1.min, float2(-1.0f));
|
||||
EXPECT_EQ(bounds1.max, float2(-1.0f));
|
||||
EXPECT_EQ(bounds2.min, float2(-1.0f, -3.0f));
|
||||
EXPECT_EQ(bounds2.max, float2(4.0f, 6.0f));
|
||||
}
|
||||
|
||||
TEST(bounds, ScaleFromCenter)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
bounds1.scale_from_center(float2(2.0f));
|
||||
const float2 bound2_size = bounds2.size();
|
||||
bounds2.scale_from_center(float2(2.0f, 1.0f));
|
||||
EXPECT_EQ(bounds1.min, float2(0.0f));
|
||||
EXPECT_EQ(bounds1.max, float2(0.0f));
|
||||
EXPECT_EQ(bounds2.min, float2(-5.5f, -5.0f));
|
||||
EXPECT_EQ(bounds2.max, float2(4.5f, 4.0f));
|
||||
EXPECT_EQ(bounds2.size(), bound2_size * float2(2.0f, 1.0f));
|
||||
}
|
||||
|
||||
TEST(bounds, Resize)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
bounds1.resize(float2(1.0f));
|
||||
bounds2.resize(float2(7.0f, 10.0f));
|
||||
EXPECT_EQ(bounds1.center(), float2(0.0f));
|
||||
EXPECT_EQ(bounds1.size(), float2(1.0f));
|
||||
EXPECT_EQ(bounds2.size(), float2(7.0f, 10.0f));
|
||||
}
|
||||
|
||||
TEST(bounds, Recenter)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
bounds1.recenter(float2(-1.0f));
|
||||
bounds2.recenter(float2(2.0f, 3.0f));
|
||||
EXPECT_EQ(bounds1.center(), float2(-1.0f));
|
||||
EXPECT_EQ(bounds2.center(), float2(2.0f, 3.0f));
|
||||
}
|
||||
|
||||
TEST(bounds, Pad)
|
||||
{
|
||||
Bounds<float2> bounds1(float2(0.0f));
|
||||
Bounds<float2> bounds2(float2(-1.0f), float2(1.0f));
|
||||
Bounds<float2> bounds3(float2(-3.0f, -5.0f), float2(2.0f, 4.0f));
|
||||
bounds1.pad(float2(1.0f));
|
||||
bounds2.pad(1.0f);
|
||||
bounds3.pad(float2(1.0f, 2.0f));
|
||||
EXPECT_EQ(bounds1.min, float2(-1.0f));
|
||||
EXPECT_EQ(bounds1.max, float2(1.0f));
|
||||
EXPECT_EQ(bounds2.min, float2(-2.0f));
|
||||
EXPECT_EQ(bounds2.max, float2(2.0f));
|
||||
EXPECT_EQ(bounds3.min, float2(-4.0f, -7.0f));
|
||||
EXPECT_EQ(bounds3.max, float2(3.0f, 6.0f));
|
||||
}
|
||||
|
||||
TEST(bounds, MinMaxEmpty)
|
||||
{
|
||||
Span<float2> empty_span{};
|
||||
EXPECT_TRUE(empty_span.is_empty());
|
||||
|
|
Loading…
Reference in New Issue