Skip to content

Commit

Permalink
[Type] Test and clean BoundingBox (#5138)
Browse files Browse the repository at this point in the history
[Type] Test for BoundingBox
  • Loading branch information
alxbilger authored Dec 20, 2024
1 parent 3ecd69c commit 3e508d3
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,9 @@ void MeshROI<DataTypes>::roiComputeBBox(const core::ExecParams* params, type::Bo

for (const auto& p : roiPositions)
{
bbox.include(DataTypes::getCPos(p));
Real x, y, z;
DataTypes::get(x, y, z, p);
bbox.include({x, y, z});
}
}

Expand Down
50 changes: 11 additions & 39 deletions Sofa/framework/Type/src/sofa/type/BoundingBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,56 +36,23 @@ BoundingBox::bbox_t make_neutralBBox()
return std::make_pair(minBBox,maxBBox);
}

BoundingBox::BoundingBox()
:bbox(make_neutralBBox())
{
}

BoundingBox::BoundingBox(const bbox_t& bbox)
:bbox(bbox)
{
}

BoundingBox::BoundingBox(const sofa::type::Vec3& minBBox, const sofa::type::Vec3& maxBBox)
:bbox(std::make_pair(minBBox,maxBBox))
{
}

BoundingBox::BoundingBox(SReal xmin, SReal xmax, SReal ymin, SReal ymax, SReal zmin, SReal zmax )
:bbox(std::make_pair(sofa::type::Vec3((SReal)xmin, (SReal)ymin, (SReal)zmin),sofa::type::Vec3( (SReal)xmax, (SReal)ymax, (SReal)zmax)))
{
}


BoundingBox::BoundingBox(const Vec6f& v )
:bbox(std::make_pair(sofa::type::Vec3(v[0],v[2],v[4]),sofa::type::Vec3(v[1],v[3],v[5])))
{
}

BoundingBox::BoundingBox(const Vec6d& v )
:bbox(std::make_pair(sofa::type::Vec3((SReal)v[0],(SReal)v[2],(SReal)v[4]),sofa::type::Vec3((SReal)v[1],(SReal)v[3],(SReal)v[5])))
{
}


/*static*/
BoundingBox BoundingBox::neutral_bbox()
{
return BoundingBox(make_neutralBBox());
}

void BoundingBox::invalidate()
{
this->bbox = make_neutralBBox();
}

bool BoundingBox::isNegligeable() const
bool BoundingBox::isNegligible() const
{
return minBBox().x() >= maxBBox().x() &&
minBBox().y() >= maxBBox().y() &&
minBBox().z() >= maxBBox().z();
}

bool BoundingBox::isNegligeable() const
{
return isNegligible();
}

bool BoundingBox::isValid() const
{
return minBBox().x() <= maxBBox().x() &&
Expand All @@ -112,6 +79,11 @@ BoundingBox::operator bbox_t() const
return bbox;
}

bool BoundingBox::operator==(const BoundingBox& other) const
{
return this->bbox == other.bbox;
}

SReal* BoundingBox::minBBoxPtr()
{
return bbox.first.ptr();
Expand Down
79 changes: 53 additions & 26 deletions Sofa/framework/Type/src/sofa/type/BoundingBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,52 +35,79 @@ class SOFA_TYPE_API BoundingBox

public:
typedef std::pair< sofa::type::Vec3, sofa::type::Vec3 > bbox_t;
using Real = sofa::type::Vec3::value_type;

BoundingBox();
/// Define using the endpoints of the main diagonal
BoundingBox(const sofa::type::Vec3& minBBox, const sofa::type::Vec3& maxBBox);
BoundingBox(const bbox_t& bbox);
/// Define using xmin, xmax, ymin, ymax, zmin, zmax in this order
BoundingBox(SReal xmin, SReal xmax, SReal ymin, SReal ymax, SReal zmin, SReal zmax );
/// Define using xmin, xmax, ymin, ymax, zmin, zmax in this order
BoundingBox(const Vec6f& bbox);
/// Define using xmin, xmax, ymin, ymax, zmin, zmax in this order
BoundingBox(const Vec6d& bbox);
constexpr BoundingBox()
: BoundingBox(neutral_bbox().bbox)
{}

static BoundingBox neutral_bbox();
/// Define using the endpoints of the main diagonal
constexpr BoundingBox(const sofa::type::Vec3& minBBox, const sofa::type::Vec3& maxBBox)
: bbox({minBBox, maxBBox}) {}

constexpr explicit BoundingBox(const bbox_t& bbox)
: bbox(bbox)
{}

/// Define using xMin, xMax, yMin, yMax, zMin, zMax in this order
constexpr BoundingBox(
const Real xMin, const Real xMax,
const Real yMin, const Real yMax,
const Real zMin, const Real zMax )
: BoundingBox({xMin, yMin, zMin}, {xMax, yMax, zMax})
{}

template<typename Scalar>
constexpr explicit BoundingBox(const Vec<6, Scalar>& bbox)
: BoundingBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5])
{}

static constexpr BoundingBox neutral_bbox()
{
constexpr Real max_real = std::numeric_limits<Real>::max();
constexpr Real min_real = std::numeric_limits<Real>::lowest();
return BoundingBox{
{max_real, max_real, max_real},
{min_real, min_real, min_real}
};
}

operator bbox_t() const;

[[nodiscard]] bool operator==(const BoundingBox& other) const;

void invalidate();
bool isValid() const;
bool isFlat() const;
bool isNegligeable() const; // !valid || flat
bool isNull() const;
[[nodiscard]] bool isValid() const;
[[nodiscard]] bool isFlat() const;
[[nodiscard]] bool isNegligible() const; // !valid || flat
SOFA_ATTRIBUTE_DISABLED__BOUNDINGBOX_TYPO()
[[nodiscard]] bool isNegligeable() const;
[[nodiscard]] bool isNull() const;

SReal* minBBoxPtr();
SReal* maxBBoxPtr();
const SReal* minBBoxPtr() const;
const SReal* maxBBoxPtr() const;
const sofa::type::Vec3& minBBox() const;
const sofa::type::Vec3& maxBBox() const;
[[nodiscard]] const SReal* minBBoxPtr() const;
[[nodiscard]] const SReal* maxBBoxPtr() const;
[[nodiscard]] const sofa::type::Vec3& minBBox() const;
[[nodiscard]] const sofa::type::Vec3& maxBBox() const;
sofa::type::Vec3& minBBox();
sofa::type::Vec3& maxBBox();

bool contains( const sofa::type::Vec3& point) const;
bool contains( const BoundingBox& other) const;
[[nodiscard]] bool contains( const sofa::type::Vec3& point) const;
[[nodiscard]] bool contains( const BoundingBox& other) const;

bool intersect( const BoundingBox& other) const;
[[nodiscard]] bool intersect( const BoundingBox& other) const;
void intersection( const BoundingBox& other);

void include( const sofa::type::Vec3& point);
void include( const BoundingBox& other);

void inflate( SReal amount );

BoundingBox getIntersection( const BoundingBox& other ) const;
BoundingBox getInclude( const sofa::type::Vec3& point ) const;
BoundingBox getInclude( const BoundingBox& other ) const;
BoundingBox getInflate( SReal amount ) const;
[[nodiscard]] BoundingBox getIntersection( const BoundingBox& other ) const;
[[nodiscard]] BoundingBox getInclude( const sofa::type::Vec3& point ) const;
[[nodiscard]] BoundingBox getInclude( const BoundingBox& other ) const;
[[nodiscard]] BoundingBox getInflate( SReal amount ) const;

friend std::ostream& operator << ( std::ostream& out, const BoundingBox& bbox)
{
Expand Down
9 changes: 9 additions & 0 deletions Sofa/framework/Type/src/sofa/type/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@
"v23.12", "v24.06", \
"RGBAColor does not inherit anymore from sofa::type::fixed_array. Use respective functions accordingly.")
#endif

#ifdef SOFA_BUILD_SOFA_TYPE
#define SOFA_ATTRIBUTE_DISABLED__BOUNDINGBOX_TYPO()
#else
#define SOFA_ATTRIBUTE_DISABLED__BOUNDINGBOX_TYPO() \
SOFA_ATTRIBUTE_DISABLED( \
"v24.12", "v25.06", \
"Use isNegligible instead.")
#endif
123 changes: 123 additions & 0 deletions Sofa/framework/Type/test/BoundingBox_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture *
* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: [email protected] *
******************************************************************************/
#include <sofa/type/BoundingBox.h>
#include <gtest/gtest.h>

namespace sofa
{

using sofa::type::BoundingBox;
using sofa::type::Vec3;

TEST(BoundingBoxTest, DefaultConstructor)
{
static constexpr BoundingBox bbox;
EXPECT_TRUE(bbox.isNegligible()); // Default neutral box should be negligible
}

TEST(BoundingBoxTest, ConstructorWithEndpoints) {
static constexpr Vec3 minVec(0.0, 0.0, 0.0);
static constexpr Vec3 maxVec(1.0, 1.0, 1.0);
static constexpr BoundingBox bbox(minVec, maxVec);

EXPECT_EQ(bbox.minBBox(), minVec);
EXPECT_EQ(bbox.maxBBox(), maxVec);
}

TEST(BoundingBoxTest, ConstructorWithLimits) {
static constexpr BoundingBox bbox(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
EXPECT_EQ(bbox.minBBox(), Vec3(0.0, 0.0, 0.0));
EXPECT_EQ(bbox.maxBBox(), Vec3(1.0, 1.0, 1.0));
}

TEST(BoundingBoxTest, NeutralBoundingBox) {
static constexpr auto neutral = BoundingBox::neutral_bbox();
EXPECT_FALSE(neutral.isValid()); // Neutral bbox is invalid
}

TEST(BoundingBoxTest, Invalidate) {
BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0));
bbox.invalidate();
EXPECT_FALSE(bbox.isValid());
}

TEST(BoundingBoxTest, IsFlat) {
static constexpr BoundingBox flatBBox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 0.0, 0.0));
EXPECT_TRUE(flatBBox.isFlat());

static constexpr BoundingBox nonFlatBBox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0));
EXPECT_FALSE(nonFlatBBox.isFlat());
}

TEST(BoundingBoxTest, ContainsPoint) {
static constexpr BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0));
static constexpr Vec3 pointInside(0.5, 0.5, 0.5);
static constexpr Vec3 pointOutside(1.5, 1.5, 1.5);

EXPECT_TRUE(bbox.contains(pointInside));
EXPECT_FALSE(bbox.contains(pointOutside));
}

TEST(BoundingBoxTest, ContainsBoundingBox) {
static constexpr BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(2.0, 2.0, 2.0));
static constexpr BoundingBox containedBBox(Vec3(0.5, 0.5, 0.5), Vec3(1.5, 1.5, 1.5));
static constexpr BoundingBox outsideBBox(Vec3(2.5, 2.5, 2.5), Vec3(3.0, 3.0, 3.0));

EXPECT_TRUE(bbox.contains(containedBBox));
EXPECT_FALSE(bbox.contains(outsideBBox));
}

TEST(BoundingBoxTest, Intersection) {
static constexpr BoundingBox bbox1(Vec3(0.0, 0.0, 0.0), Vec3(2.0, 2.0, 2.0));
static constexpr BoundingBox bbox2(Vec3(1.0, 1.0, 1.0), Vec3(3.0, 3.0, 3.0));
static constexpr BoundingBox expectedIntersection(Vec3(1.0, 1.0, 1.0), Vec3(2.0, 2.0, 2.0));

EXPECT_TRUE(bbox1.intersect(bbox2));
EXPECT_EQ(bbox1.getIntersection(bbox2), expectedIntersection);
}

TEST(BoundingBoxTest, Inflate) {
BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0));
bbox.inflate(1.0);

EXPECT_EQ(bbox.minBBox(), Vec3(-1.0, -1.0, -1.0));
EXPECT_EQ(bbox.maxBBox(), Vec3(2.0, 2.0, 2.0));
}

TEST(BoundingBoxTest, IncludePoint) {
BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0));
static constexpr Vec3 point(2.0, 2.0, 2.0);
bbox.include(point);

EXPECT_EQ(bbox.maxBBox(), point);
}

TEST(BoundingBoxTest, IncludeBoundingBox) {
BoundingBox bbox(Vec3(0.0, 0.0, 0.0), Vec3(1.0, 1.0, 1.0));
static constexpr BoundingBox other(Vec3(-1.0, -1.0, -1.0), Vec3(2.0, 2.0, 2.0));
bbox.include(other);

EXPECT_EQ(bbox.minBBox(), other.minBBox());
EXPECT_EQ(bbox.maxBBox(), other.maxBBox());
}

}
1 change: 1 addition & 0 deletions Sofa/framework/Type/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.22)
project(Sofa.Type_test)

set(SOURCE_FILES
BoundingBox_test.cpp
MatSym_test.cpp
MatTypes_test.cpp
Material_test.cpp
Expand Down

0 comments on commit 3e508d3

Please sign in to comment.