From 1c0d716b0962d5ddad89b54575f8883384c8ed08 Mon Sep 17 00:00:00 2001 From: Christian Godenschwager <christian.godenschwager@fau.de> Date: Fri, 3 Feb 2017 17:38:56 +0100 Subject: [PATCH] Added functions to compute distances between AABBs --- src/core/math/GenericAABB.h | 4 ++ src/core/math/GenericAABB.impl.h | 68 ++++++++++++++++++++++ tests/core/math/GenericAABBTest.cpp | 88 +++++++++++++++++++++++++++-- 3 files changed, 156 insertions(+), 4 deletions(-) diff --git a/src/core/math/GenericAABB.h b/src/core/math/GenericAABB.h index 502b45c2e..99e1ac647 100644 --- a/src/core/math/GenericAABB.h +++ b/src/core/math/GenericAABB.h @@ -23,6 +23,7 @@ #include "core/DataTypes.h" #include "core/math/Vector3.h" +#include "core/math/Shims.h" #include "core/mpi/RecvBuffer.h" #include "core/mpi/SendBuffer.h" @@ -144,6 +145,9 @@ public: inline value_type signedDistance( const vector_type & point ) const; inline value_type maxDistance( const vector_type & point ) const; + inline value_type sqDistance( const GenericAABB & other ) const; + inline value_type sqMaxDistance( const GenericAABB & other ) const; + inline boost::array< vector_type, 8 > corners() const; // Modifiers diff --git a/src/core/math/GenericAABB.impl.h b/src/core/math/GenericAABB.impl.h index e706d1fa2..ef6f12e1a 100644 --- a/src/core/math/GenericAABB.impl.h +++ b/src/core/math/GenericAABB.impl.h @@ -1196,6 +1196,74 @@ typename GenericAABB< T >::value_type GenericAABB< T >::maxDistance( const vecto } +/** +* \brief Computes the distance between two GenericAABBs +* +* \param other The other AABB to which the distance to *this should be computed +* +* \returns The (positive) distance of the surface of other to the surface of *this. 0 if *this and other are intersecting. +*/ +template< typename T > +inline typename GenericAABB< T >::value_type GenericAABB< T >::sqDistance( const GenericAABB & other ) const +{ + value_type theSqDistance = value_type(0); + + if( other.maxCorner_[0] < minCorner_[0] ) + { + theSqDistance += sq( minCorner_[0] - other.maxCorner_[0] ); + } + else if( other.minCorner_[0] > maxCorner_[0] ) + { + theSqDistance += sq( other.minCorner_[0] - maxCorner_[0] ); + } + + if( other.maxCorner_[1] < minCorner_[1] ) + { + theSqDistance += sq( minCorner_[1] - other.maxCorner_[1] ); + } + else if( other.minCorner_[1] > maxCorner_[1] ) + { + theSqDistance += sq( other.minCorner_[1] - maxCorner_[1] ); + } + + if( other.maxCorner_[2] < minCorner_[2] ) + { + theSqDistance += sq( minCorner_[2] - other.maxCorner_[2] ); + } + else if( other.minCorner_[2] > maxCorner_[2] ) + { + theSqDistance += sq( other.minCorner_[2] - maxCorner_[2] ); + } + + WALBERLA_ASSERT_GREATER_EQUAL( theSqDistance, value_type(0) ); + WALBERLA_ASSERT( !intersects( other ) || walberla::isIdentical( theSqDistance, value_type(0) ) ); // intersect => distance == 0 + + return theSqDistance; +} + + +/** +* \brief Computes the maximal distance of any two points from two GenericAABBs +* +* \param other The other AABB to which the maximal distance to *this should be computed +* +* \returns The maximal (positive) distance of any point in other to any point in this. +*/ +template< typename T > +inline typename GenericAABB< T >::value_type GenericAABB< T >::sqMaxDistance( const GenericAABB & other ) const +{ + value_type theSqMaxDistance = value_type(0); + + theSqMaxDistance += sq( std::max( maxCorner_[0] - other.minCorner_[0], other.maxCorner_[0] - minCorner_[0] ) ); + theSqMaxDistance += sq( std::max( maxCorner_[1] - other.minCorner_[1], other.maxCorner_[1] - minCorner_[1] ) ); + theSqMaxDistance += sq( std::max( maxCorner_[2] - other.minCorner_[2], other.maxCorner_[2] - minCorner_[2] ) ); + + WALBERLA_ASSERT_GREATER_EQUAL( theSqMaxDistance, value_type(0) ); + + return theSqMaxDistance; +} + + /** * \brief Computes the eight corners of this GenericAABB diff --git a/tests/core/math/GenericAABBTest.cpp b/tests/core/math/GenericAABBTest.cpp index 6c19fea28..6a5d4ce9a 100644 --- a/tests/core/math/GenericAABBTest.cpp +++ b/tests/core/math/GenericAABBTest.cpp @@ -22,6 +22,7 @@ #include "core/Environment.h" #include "core/debug/TestSubsystem.h" #include "core/math/GenericAABB.h" +#include "core/math/Shims.h" #include "core/math/Utility.h" #include "stencil/D3CornerStencil.h" @@ -555,6 +556,79 @@ void randomTest() } +template< typename T > +void testAABBDistancesFixed() +{ + GenericAABB< T > aabb0( T(-1), T(-1), T(-1), T(1), T(1), T(1) ); + GenericAABB< T > aabb1( T(-0.5), T(-0.5), T(-0.5), T(0.5), T(0.5), T(0.5) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqDistance( aabb1 ), T(0) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqDistance( aabb0 ), T(0) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqMaxDistance( aabb1 ), T(3) * math::sq( T(1.5) ) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqMaxDistance( aabb0 ), T(3) * math::sq( T(1.5) ) ); + + aabb1.init( T(1.5), T(1.5), T(1.5), T(2), T(2), T(2) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqDistance( aabb1 ), T(3) * math::sq( T(0.5) ) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqDistance( aabb0 ), T(3) * math::sq( T(0.5) ) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqMaxDistance( aabb1 ), T(3) * math::sq( T(3) ) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqMaxDistance( aabb0 ), T(3) * math::sq( T(3) ) ); + + + aabb1.init( T(0), T(0), T(0), T(2), T(2), T(2) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqDistance( aabb1 ), T(0) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqDistance( aabb0 ), T(0) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqMaxDistance( aabb1 ), T(3) * math::sq( T(3) ) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqMaxDistance( aabb0 ), T(3) * math::sq( T(3) ) ); + + aabb1.init( T(-2), T(-2), T(-2), T(0), T(0), T(0) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqDistance( aabb1 ), T(0) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqDistance( aabb0 ), T(0) ); + + WALBERLA_CHECK_IDENTICAL( aabb0.sqMaxDistance( aabb1 ), T(3) * math::sq( T(3) ) ); + WALBERLA_CHECK_IDENTICAL( aabb1.sqMaxDistance( aabb0 ), T(3) * math::sq( T(3) ) ); +} + + +template< typename T > +void testAABBDistancesRandom( const GenericAABB< T > & baseAABB ) +{ + static const uint_t NUM_BOXES = 100; + static const uint_t NUM_POINTS = 1000; + boost::random::mt19937 rng; + + for( uint_t i = 0; i < NUM_BOXES; ++i ) + { + math::GenericAABB< T > subAabb0( baseAABB.randomPoint( rng ), baseAABB.randomPoint( rng ) ); + math::GenericAABB< T > subAabb1( baseAABB.randomPoint( rng ), baseAABB.randomPoint( rng ) ); + + WALBERLA_CHECK_IDENTICAL( subAabb0.sqDistance( subAabb1 ), subAabb1.sqDistance( subAabb0 ) ); + WALBERLA_CHECK_IDENTICAL( subAabb0.sqMaxDistance( subAabb1 ), subAabb1.sqMaxDistance( subAabb0 ) ); + + const T minSqDistance = subAabb0.sqDistance( subAabb1 ); + const T maxSqDistance = subAabb0.sqMaxDistance( subAabb1 ); + + WALBERLA_CHECK_GREATER_EQUAL( maxSqDistance, minSqDistance ); + + for( uint_t j = 0; j < NUM_POINTS; ++j ) + { + auto p0 = subAabb0.randomPoint( rng ); + auto p1 = subAabb1.randomPoint( rng ); + + const auto sqPointDistance = (p0 - p1).sqrLength(); + + WALBERLA_CHECK_GREATER_EQUAL( sqPointDistance, minSqDistance ); + WALBERLA_CHECK_LESS_EQUAL( sqPointDistance, maxSqDistance ); + } + } +} + + int main(int argc, char**argv) { walberla::debug::enterTestMode(); @@ -563,18 +637,24 @@ int main(int argc, char**argv) testConstructors<float>( 1.0f, 2.0f, 3.0f, -1.0f, 3.0f, 2.0f ); testConstructors<double>( 1.0, 2.0, 3.0, -1.0, 3.0, 2.0 ); - + testFixedAABB<float>(); testFixedAABB<double>(); - + GenericAABB< float > floatAABB( 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f ); GenericAABB< double > doubleAABB( 1.0, 1.0, 1.0, 2.0, 2.0 ,2.0 ); - + GenericAABB< double > copiedAABB0( floatAABB ); GenericAABB< double > copiedAABB1( doubleAABB ); - + randomTest<float>(); randomTest<double>(); + testAABBDistancesFixed<float>(); + testAABBDistancesFixed<double>(); + + testAABBDistancesRandom<float>( GenericAABB<float>( -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f ) ); + testAABBDistancesRandom<double>( GenericAABB<double>( -1.0, -1.0, -1.0, 1.0, 1.0, 1.0 ) ); + return 0; } -- GitLab