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