From 46dd3294156664b9103488b10924c9ecaac36a06 Mon Sep 17 00:00:00 2001
From: jpan <jpan@253336fb-580f-4252-a368-f3cef5a2a82b>
Date: Sun, 3 Jun 2012 06:50:01 +0000
Subject: [PATCH] Add the broad phase distance

git-svn-id: https://kforge.ros.org/fcl/fcl_ros@89 253336fb-580f-4252-a368-f3cef5a2a82b
---
 trunk/fcl/include/fcl/AABB.h                  |   8 +-
 trunk/fcl/include/fcl/broad_phase_collision.h | 204 ++++++----
 trunk/fcl/include/fcl/collision_data.h        |  13 +
 trunk/fcl/include/fcl/vec_3f.h                |  10 +-
 trunk/fcl/src/AABB.cpp                        |  51 ++-
 trunk/fcl/src/broad_phase_collision.cpp       | 369 +++++++++++++++---
 6 files changed, 520 insertions(+), 135 deletions(-)

diff --git a/trunk/fcl/include/fcl/AABB.h b/trunk/fcl/include/fcl/AABB.h
index 620bb79b..45b78080 100644
--- a/trunk/fcl/include/fcl/AABB.h
+++ b/trunk/fcl/include/fcl/AABB.h
@@ -180,10 +180,12 @@ public:
     return (min_ + max_) * 0.5;
   }
 
-  /** \brief The distance between two AABB 
-   * Not implemented.
-   */
   BVH_REAL distance(const AABB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
+
+  inline bool equal(const AABB& other) const
+  {
+    return min_.equal(other.min_) && max_.equal(other.max_);
+  }
 };
 
 }
diff --git a/trunk/fcl/include/fcl/broad_phase_collision.h b/trunk/fcl/include/fcl/broad_phase_collision.h
index de15ffc1..f9a424d5 100644
--- a/trunk/fcl/include/fcl/broad_phase_collision.h
+++ b/trunk/fcl/include/fcl/broad_phase_collision.h
@@ -55,11 +55,13 @@ namespace fcl
 
 bool defaultCollisionFunction(CollisionObject* o1, CollisionObject* o2, void* cdata);
 
-BVH_REAL defaultDistanceFunction(CollisionObject* o1, CollisionObject* o2, void* cdata);
+bool defaultDistanceFunction(CollisionObject* o1, CollisionObject* o2, void* cdata);
 
 /** \brief return value is whether can stop now */
 typedef bool (*CollisionCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata);
 
+typedef bool (*DistanceCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata);
+
 /** \brief Base class for broad phase collision */
 class BroadPhaseCollisionManager
 {
@@ -87,6 +89,9 @@ public:
   /** \brief perform collision test between one object and all the objects belonging to the manager */
   virtual void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const = 0;
 
+  /** \brief perform distance computation between one object and all the objects belonging to the manager */
+  virtual void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const = 0;
+
   /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
   virtual void collide(void* cdata, CollisionCallBack callback) const = 0;
 
@@ -125,6 +130,9 @@ public:
   /** \brief perform collision test between one object and all the objects belonging to the manager */
   void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
 
+  /** \brief perform distance computation between one object and all the objects belonging to the manager */
+  void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
   /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
   void collide(void* cdata, CollisionCallBack callback) const;
 
@@ -140,7 +148,7 @@ protected:
   std::list<CollisionObject*> objs;
 };
 
-
+/** \brief Spatial hash function: hash an AABB to a set of integer values */
 struct SpatialHash
 {
   SpatialHash(const AABB& scene_limit_, BVH_REAL cell_size_)
@@ -201,33 +209,45 @@ public:
     delete hash_table;
   }
 
+  /** \brief add one object to the manager */
   void registerObject(CollisionObject* obj);
 
+  /** \brief remove one object from the manager */
   void unregisterObject(CollisionObject* obj);
 
+  /** \brief initialize the manager, related with the specific type of manager */
   void setup();
 
+  /** \brief update the condition of manager */
   void update();
 
+  /** \brief clear the manager */
   void clear();
 
+  /** \brief return the objects managed by the manager */
   void getObjects(std::vector<CollisionObject*>& objs) const;
 
+  /** \brief perform collision test between one object and all the objects belonging to the manager */
   void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
 
+  /** \brief perform distance computation between one object and all the objects belonging ot the manager */
+  void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
+  /** \brief perform collision test for the objects belonging to the manager (i.e, N^2 self collision) */
   void collide(void* cdata, CollisionCallBack callback) const;
 
+  /** \brief whether the manager is empty */
   bool empty() const;
 
+  /** \brief the number of objects managed by the manager */
   size_t size() const;
 
+  /** \brief compute the bound for the environent */
   static void computeBound(std::vector<CollisionObject*>& objs, Vec3f& l, Vec3f& u)
   {
     AABB bound;
     for(unsigned int i = 0; i < objs.size(); ++i)
-    {
       bound += objs[i]->getAABB();
-    }
     
     l = bound.min_;
     u = bound.max_;
@@ -243,6 +263,7 @@ protected:
   // objects outside the scene limit are in another list
   std::list<CollisionObject*> objs_outside_scene_limit;
 
+  // the size of the scene
   AABB scene_limit;
 };
 
@@ -263,9 +284,7 @@ void SpatialHashingCollisionManager<HashTable>::registerObject(CollisionObject*
     hash_table->insert(overlap_aabb, obj);
   }
   else
-  {
     objs_outside_scene_limit.push_back(obj);
-  }
 }
 
 template<typename HashTable>
@@ -284,9 +303,7 @@ void SpatialHashingCollisionManager<HashTable>::unregisterObject(CollisionObject
     hash_table->remove(overlap_aabb, obj);
   }
   else
-  {
     objs_outside_scene_limit.remove(obj);
-  }
 }
 
 template<typename HashTable>
@@ -301,9 +318,7 @@ void SpatialHashingCollisionManager<HashTable>::update()
 
   std::list<CollisionObject*>::const_iterator it;
   for(it = objs.begin(); it != objs.end(); ++it)
-  {
     registerObject(*it);
-  }
 }
 
 template<typename HashTable>
@@ -354,6 +369,90 @@ void SpatialHashingCollisionManager<HashTable>::collide(CollisionObject* obj, vo
   }
 }
 
+template<typename HashTable>
+void SpatialHashingCollisionManager<HashTable>::distance(CollisionObject* obj, void* cdata_, DistanceCallBack callback) const
+{
+  DistanceData* cdata = static_cast<DistanceData*>(cdata_);
+  Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5;
+  AABB aabb = obj->getAABB();
+  if(cdata->min_distance < std::numeric_limits<BVH_REAL>::max())
+  {
+    BVH_REAL d = cdata->min_distance;
+    aabb.min_ -= Vec3f(d, d, d);
+    aabb.max_ += Vec3f(d, d, d);
+  }
+  AABB overlap_aabb;
+
+  int status = 1;
+  BVH_REAL old_min_distance;
+
+  while(1)
+  {
+    old_min_distance = cdata->min_distance;
+
+    if(scene_limit.overlap(aabb, overlap_aabb))
+    {
+      if(!scene_limit.contain(aabb))
+      {
+        std::list<CollisionObject*>::const_iterator it;
+        for(it = objs_outside_scene_limit.begin(); it != objs_outside_scene_limit.end(); ++it)
+        {
+          if(callback(obj, *it, cdata)) break;
+        }
+      }
+      
+      std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb);
+      for(unsigned int i = 0; i < query_result.size(); ++i)
+      {
+        if(callback(obj, query_result[i], cdata)) break;
+      }
+    }
+    else
+    {
+      std::list<CollisionObject*>::const_iterator it;
+      for(it = objs_outside_scene_limit.begin(); it != objs_outside_scene_limit.end(); ++it)
+      {
+        if(callback(obj, *it, cdata)) break;
+      }
+    }
+
+    if(status == 1)
+    {
+      if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
+      {
+        if(cdata->min_distance < old_min_distance) break;
+        else
+          cdata->min_distance = std::numeric_limits<BVH_REAL>::max();
+      }
+      else
+      {
+        if(cdata->min_distance < old_min_distance)
+        {
+          BVH_REAL d = cdata->min_distance;
+          aabb.min_ = obj->getAABB().min_ - Vec3f(d, d, d);
+          aabb.max_ = obj->getAABB().max_ + Vec3f(d, d, d);
+          status = 0;
+        }
+        else
+        {
+          if(aabb.equal(obj->getAABB()))
+          {
+            aabb.min_ -= delta;
+            aabb.max_ += delta;
+          }
+          else
+          {
+            aabb.min_ = aabb.min_ * 2 - obj->getAABB().min_;
+            aabb.max_ = aabb.max_ * 2 - obj->getAABB().max_;
+          }
+        }
+      }
+    }
+    else if(status == 0)
+      break;
+  }
+}
+
 template<typename HashTable>
 void SpatialHashingCollisionManager<HashTable>::collide(void* cdata, CollisionCallBack callback) const
 {
@@ -370,20 +469,14 @@ void SpatialHashingCollisionManager<HashTable>::collide(void* cdata, CollisionCa
         std::list<CollisionObject*>::const_iterator it2;
         for(it2 = objs_outside_scene_limit.begin(); it2 != objs_outside_scene_limit.end(); ++it2)
         {
-          if(*it1 < *it2)
-          {
-            if(callback(*it1, *it2, cdata)) return;
-          }
+          if(*it1 < *it2) { if(callback(*it1, *it2, cdata)) return; }
         }
       }
 
       std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb);
       for(unsigned int i = 0; i < query_result.size(); ++i)
       {
-        if(*it1 < query_result[i])
-        {
-          if(callback(*it1, query_result[i], cdata)) return;
-        }
+        if(*it1 < query_result[i]) { if(callback(*it1, query_result[i], cdata)) return; }
       }
     }
     else
@@ -391,10 +484,7 @@ void SpatialHashingCollisionManager<HashTable>::collide(void* cdata, CollisionCa
       std::list<CollisionObject*>::const_iterator it2;
       for(it2 = objs_outside_scene_limit.begin(); it2 != objs_outside_scene_limit.end(); ++it2)
       {
-        if(*it1 < *it2)
-        {
-          if(callback(*it1, *it2, cdata)) return;
-        }
+        if(*it1 < *it2) { if(callback(*it1, *it2, cdata)) return; }
       }
     }
   }
@@ -451,6 +541,9 @@ public:
   /** \brief perform collision test between one object and all the objects belonging to the manager */
   void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
 
+  /** \brief perform distance computation between one object and all the objects belonging to the manager */
+  void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
   /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
   void collide(void* cdata, CollisionCallBack callback) const;
 
@@ -568,6 +661,9 @@ protected:
   std::list<SaPPair> overlap_pairs;
 };
 
+
+
+
 /** Simple SAP collision manager */
 class SSaPCollisionManager : public BroadPhaseCollisionManager
 {
@@ -598,6 +694,9 @@ public:
   /** \brief perform collision test between one object and all the objects belonging to the manager */
   void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
 
+  /** \brief perform distance computation between one object and all the objects belonging to the manager */
+  void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
   /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
   void collide(void* cdata, CollisionCallBack callback) const;
 
@@ -608,56 +707,13 @@ public:
   inline size_t size() const { return objs_x.size(); }
 
 protected:
-
-  /** \brief Functor sorting objects according to the AABB lower x bound */
-  struct SortByXLow
-  {
-    bool operator()(const CollisionObject* a, const CollisionObject* b) const
-    {
-      if(a->getAABB().min_[0] < b->getAABB().min_[0])
-        return true;
-      return false;
-    }
-  };
-
-  /** \brief Functor sorting objects according to the AABB lower y bound */
-  struct SortByYLow
-   {
-     bool operator()(const CollisionObject* a, const CollisionObject* b) const
-     {
-       if(a->getAABB().min_[1] < b->getAABB().min_[1])
-         return true;
-       return false;
-     }
-   };
-
-  /** \brief Functor sorting objects according to the AABB lower z bound */
-   struct SortByZLow
-   {
-     bool operator()(const CollisionObject* a, const CollisionObject* b) const
-     {
-       if(a->getAABB().min_[2] < b->getAABB().min_[2])
-         return true;
-       return false;
-     }
-   };
-
-   /** \brief Dummy collision object with a point AABB */
-   class DummyCollisionObject : public CollisionObject
-   {
-   public:
-     DummyCollisionObject(const AABB& aabb_)
-     {
-       aabb = aabb_;
-     }
-
-     void computeLocalAABB() {}
-   };
-
    /** \brief check collision between one object and a list of objects */
    void checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end,
                   CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
 
+   void checkDis(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end,
+                    CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
 
    /** \brief Objects sorted according to lower x value */
    std::vector<CollisionObject*> objs_x;
@@ -704,6 +760,9 @@ public:
   /** \brief perform collision test between one object and all the objects belonging to the manager */
   void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
 
+  /** \brief perform distance computation between one object and all the objects belonging to the manager */
+  void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
   /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
   void collide(void* cdata, CollisionCallBack callback) const;
 
@@ -715,10 +774,6 @@ public:
 
 protected:
 
-  /** \brief check collision between one object and a list of objects */
-  void checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end,
-                 CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
-
 
   /** \brief SAP end point */
   struct EndPoint
@@ -756,6 +811,11 @@ protected:
     }
   };
 
+
+  void checkColl(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
+
+  void checkDist(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback) const;
+
   /** \brief vector stores all the end points */
   std::vector<EndPoint> endpoints[3];
 
diff --git a/trunk/fcl/include/fcl/collision_data.h b/trunk/fcl/include/fcl/collision_data.h
index c39e1151..f543be0a 100644
--- a/trunk/fcl/include/fcl/collision_data.h
+++ b/trunk/fcl/include/fcl/collision_data.h
@@ -4,6 +4,7 @@
 #include "fcl/collision_object.h"
 #include "fcl/vec_3f.h"
 #include <vector>
+#include <limits>
 
 
 namespace fcl
@@ -68,6 +69,18 @@ struct CollisionData
   std::vector<Contact> contacts;
 };
 
+struct DistanceData
+{
+  DistanceData()
+  {
+    min_distance = std::numeric_limits<BVH_REAL>::max();
+    done = false;
+  }
+
+  BVH_REAL min_distance;
+  bool done;
+};
+
 
 
 }
diff --git a/trunk/fcl/include/fcl/vec_3f.h b/trunk/fcl/include/fcl/vec_3f.h
index 58a2b284..35adfa02 100644
--- a/trunk/fcl/include/fcl/vec_3f.h
+++ b/trunk/fcl/include/fcl/vec_3f.h
@@ -41,6 +41,7 @@
 #include <cmath>
 #include <cstdlib>
 #include <algorithm>
+#include <cstring>
 
 /** \brief Main namespace */
 namespace fcl
@@ -310,11 +311,14 @@ namespace fcl
 
     Vec3f() { v_[0] = 0; v_[1] = 0; v_[2] = 0; }
 
+    Vec3f(const Vec3f& other)
+    {
+      memcpy(v_, other.v_, sizeof(BVH_REAL) * 3);
+    }
+
     Vec3f(const BVH_REAL* v)
     {
-      v_[0] = v[0];
-      v_[1] = v[1];
-      v_[2] = v[2];
+      memcpy(v_, v, sizeof(BVH_REAL) * 3);
     }
 
     Vec3f(BVH_REAL x, BVH_REAL y, BVH_REAL z)
diff --git a/trunk/fcl/src/AABB.cpp b/trunk/fcl/src/AABB.cpp
index 2cd8ebd2..39ba0c09 100644
--- a/trunk/fcl/src/AABB.cpp
+++ b/trunk/fcl/src/AABB.cpp
@@ -51,8 +51,55 @@ AABB::AABB()
 
 BVH_REAL AABB::distance(const AABB& other, Vec3f* P, Vec3f* Q) const
 {
-  std::cerr << "AABB distance not implemented!" << std::endl;
-  return 0.0;
+  BVH_REAL result = 0;
+  for(unsigned int i = 0; i < 3; ++i)
+  {
+    BVH_REAL amin = min_[i];
+    BVH_REAL amax = max_[i];
+    BVH_REAL bmin = other.min_[i];
+    BVH_REAL bmax = other.max_[i];
+    
+    if(amin > bmax)
+    {
+      BVH_REAL delta = bmax - amin;
+      result += delta * delta;
+      if(P && Q)
+      {
+        (*P)[i] = amin;
+        (*Q)[i] = bmax;
+      }
+    }
+    else if(bmin > amax)
+    {
+      BVH_REAL delta = amax - bmin;
+      result += delta * delta;
+      if(P && Q)
+      {
+        (*P)[i] = amax;
+        (*Q)[i] = bmin;
+      }
+    }
+    else
+    {
+      if(P && Q)
+      {
+        if(bmin >= amin)
+        {
+          BVH_REAL t = 0.5 * (amax + bmin);
+          (*P)[i] = t;
+          (*Q)[i] = t;
+        }
+        else
+        {
+          BVH_REAL t = 0.5 * (amin + bmax);
+          (*P)[i] = t;
+          (*Q)[i] = t;
+        }
+      }
+    }
+  }
+
+  return sqrt(result);
 }
 
 }
diff --git a/trunk/fcl/src/broad_phase_collision.cpp b/trunk/fcl/src/broad_phase_collision.cpp
index bd7b9dd3..dad4ba31 100644
--- a/trunk/fcl/src/broad_phase_collision.cpp
+++ b/trunk/fcl/src/broad_phase_collision.cpp
@@ -37,6 +37,7 @@
 
 #include "fcl/broad_phase_collision.h"
 #include "fcl/collision.h"
+#include "fcl/distance.h"
 #include <algorithm>
 #include <set>
 #include <deque>
@@ -49,7 +50,7 @@ namespace fcl
 
 bool defaultCollisionFunction(CollisionObject* o1, CollisionObject* o2, void* cdata_)
 {
-  CollisionData* cdata = (CollisionData*)cdata_;
+  CollisionData* cdata = static_cast<CollisionData*>(cdata_);
 
   if(cdata->done) return true;
 
@@ -69,9 +70,16 @@ bool defaultCollisionFunction(CollisionObject* o1, CollisionObject* o2, void* cd
   return cdata->done;
 }
 
-BVH_REAL defaultDistanceFunction(CollisionObject* o1, CollisionObject* o2, void* cdata_)
+bool defaultDistanceFunction(CollisionObject* o1, CollisionObject* o2, void* cdata_)
 {
-  return 0.0;
+  DistanceData* cdata = static_cast<DistanceData*>(cdata_);
+  
+  if(cdata->done) return true;
+
+  BVH_REAL d = distance(o1, o2);
+  if(cdata->min_distance > d) cdata->min_distance = d;
+  
+  return cdata->done;
 }
 
 void NaiveCollisionManager::unregisterObject(CollisionObject* obj)
@@ -115,6 +123,16 @@ void NaiveCollisionManager::collide(CollisionObject* obj, void* cdata, Collision
   }
 }
 
+void NaiveCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const
+{
+  std::list<CollisionObject*>::const_iterator it;
+  for(it = objs.begin(); it != objs.end(); ++it)
+  {
+    if(callback(obj, *it, cdata))
+      return;
+  }
+}
+
 void NaiveCollisionManager::collide(void* cdata, CollisionCallBack callback) const
 {
   std::list<CollisionObject*>::const_iterator it1;
@@ -136,6 +154,52 @@ bool NaiveCollisionManager::empty() const
 }
 
 
+/** \brief Functor sorting objects according to the AABB lower x bound */
+struct SortByXLow
+{
+  bool operator()(const CollisionObject* a, const CollisionObject* b) const
+  {
+    if(a->getAABB().min_[0] < b->getAABB().min_[0])
+      return true;
+    return false;
+  }
+};
+
+/** \brief Functor sorting objects according to the AABB lower y bound */
+struct SortByYLow
+{
+  bool operator()(const CollisionObject* a, const CollisionObject* b) const
+  {
+    if(a->getAABB().min_[1] < b->getAABB().min_[1])
+      return true;
+    return false;
+  }
+};
+
+/** \brief Functor sorting objects according to the AABB lower z bound */
+struct SortByZLow
+{
+  bool operator()(const CollisionObject* a, const CollisionObject* b) const
+  {
+    if(a->getAABB().min_[2] < b->getAABB().min_[2])
+      return true;
+    return false;
+  }
+};
+
+/** \brief Dummy collision object with a point AABB */
+class DummyCollisionObject : public CollisionObject
+{
+public:
+  DummyCollisionObject(const AABB& aabb_) : CollisionObject()
+  {
+    aabb = aabb_;
+  }
+
+  void computeLocalAABB() {}
+};
+
+
 void SSaPCollisionManager::unregisterObject(CollisionObject* obj)
 {
   setup();
@@ -246,17 +310,16 @@ void SSaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionC
   std::vector<CollisionObject*>::const_iterator pos_start1 = objs_x.begin();
   std::vector<CollisionObject*>::const_iterator pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow());
   unsigned int d1 = pos_end1 - pos_start1;
+
   if(d1 > CUTOFF)
   {
     std::vector<CollisionObject*>::const_iterator pos_start2 = objs_y.begin();
-
     std::vector<CollisionObject*>::const_iterator pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow());
     unsigned int d2 = pos_end2 - pos_start2;
 
     if(d2 > CUTOFF)
     {
       std::vector<CollisionObject*>::const_iterator pos_start3 = objs_z.begin();
-
       std::vector<CollisionObject*>::const_iterator pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow());
       unsigned int d3 = pos_end3 - pos_start3;
 
@@ -282,6 +345,114 @@ void SSaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionC
     checkColl(pos_start1, pos_end1, obj, cdata, callback);
 }
 
+void SSaPCollisionManager::checkDis(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback) const
+{
+  while(pos_start != pos_end)
+  {
+    if(callback(*pos_start, obj, cdata)) 
+      return;
+
+    pos_start++;
+  }
+}
+
+void SSaPCollisionManager::distance(CollisionObject* obj, void* cdata_, DistanceCallBack callback) const
+{
+  static const unsigned int CUTOFF = 100;
+
+  DistanceData* cdata = static_cast<DistanceData*>(cdata_);
+  Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5;
+  Vec3f dummy_vector = obj->getAABB().max_;
+  if(cdata->min_distance < std::numeric_limits<BVH_REAL>::max())
+    dummy_vector += Vec3f(cdata->min_distance, cdata->min_distance, cdata->min_distance);
+
+  std::vector<CollisionObject*>::const_iterator pos_start1 = objs_x.begin();
+  std::vector<CollisionObject*>::const_iterator pos_start2 = objs_y.begin();
+  std::vector<CollisionObject*>::const_iterator pos_start3 = objs_z.begin();
+  std::vector<CollisionObject*>::const_iterator pos_end1 = objs_x.end();
+  std::vector<CollisionObject*>::const_iterator pos_end2 = objs_y.end();
+  std::vector<CollisionObject*>::const_iterator pos_end3 = objs_z.end();
+
+  int status = 1;
+  BVH_REAL old_min_distance;
+
+  while(1)
+  {
+    old_min_distance = cdata->min_distance;
+    AABB dummy_aabb = AABB(dummy_vector);
+    DummyCollisionObject dummyHigh(dummy_aabb);
+    // DummyCollisionObject dummyHigh(AABB(dummy_vector));
+
+    pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow());
+    unsigned int d1 = pos_end1 - pos_start1;
+
+    if(d1 > CUTOFF)
+    {
+      pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow());
+      unsigned int d2 = pos_end2 - pos_start2;
+
+      if(d2 > CUTOFF)
+      {
+        pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow());
+        unsigned int d3 = pos_end3 - pos_start3;
+
+        if(d3 > CUTOFF)
+        {
+          if(d3 <= d2 && d3 <= d1)
+            checkDis(pos_start3, pos_end3, obj, cdata, callback);
+          else
+          {
+            if(d2 <= d3 && d2 <= d1)
+              checkDis(pos_start2, pos_end2, obj, cdata, callback);
+            else
+              checkDis(pos_start1, pos_end1, obj, cdata, callback);
+          }
+        }
+        else
+          checkDis(pos_start3, pos_end3, obj, cdata, callback);
+      }
+      else
+        checkDis(pos_start2, pos_end2, obj, cdata, callback);
+    }
+    else
+    {
+      checkDis(pos_start1, pos_end1, obj, cdata, callback);
+    }
+
+    if(status == 1)
+    {
+      if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
+      {
+        if(cdata->min_distance < old_min_distance) break;
+        else // the initial min distance estimate is not correct, so turn to use conservative estimate. dummy_vector not changed this time.
+          cdata->min_distance = std::numeric_limits<BVH_REAL>::max();
+      }
+      else
+      {
+        // from infinity to a finite one, only need one additional loop 
+        // to check the possible missed ones to the right of the objs array
+        if(cdata->min_distance < old_min_distance) 
+        {
+          BVH_REAL d = cdata->min_distance;
+          dummy_vector = obj->getAABB().max_ + Vec3f(d, d, d);
+          status = 0;
+        }
+        else // need more loop
+        {
+          if(dummy_vector.equal(obj->getAABB().max_))
+            dummy_vector = dummy_vector + delta;
+          else
+            dummy_vector = dummy_vector * 2 - obj->getAABB().max_;
+        }
+        if(pos_end1 != objs_x.end()) pos_start1 = pos_end1;
+        if(pos_end2 != objs_y.end()) pos_start2 = pos_end2;
+        if(pos_end3 != objs_z.end()) pos_start3 = pos_end3;
+      }
+    }
+    else if(status == 0)
+      break;
+  }
+}
 
 void SSaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const
 {
@@ -691,6 +862,19 @@ void SaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCa
   }
 }
 
+void SaPCollisionManager::distance(CollisionObject* obj, void* cdata_, DistanceCallBack callback) const
+{
+  DistanceData* cdata = static_cast<DistanceData*>(cdata_);
+  for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it)
+  {
+    if((*it)->obj->getAABB().distance(obj->getAABB()) < cdata->min_distance)
+    {
+      if(callback(obj, (*it)->obj, cdata_))
+        return;
+    }
+  }
+}
+
 void SaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const
 {
   for(std::list<SaPPair>::const_iterator it = overlap_pairs.begin(); it != overlap_pairs.end(); ++it)
@@ -907,11 +1091,6 @@ void IntervalTreeCollisionManager::getObjects(std::vector<CollisionObject*>& obj
   }
 }
 
-void IntervalTreeCollisionManager::checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end,
-                                             CollisionObject* obj, void* cdata, CollisionCallBack callback) const
-{
-
-}
 
 void IntervalTreeCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const
 {
@@ -933,66 +1112,117 @@ void IntervalTreeCollisionManager::collide(CollisionObject* obj, void* cdata, Co
         int d3 = results2.size();
 
         if(d1 >= d2 && d1 >= d3)
-        {
-          for(unsigned int i = 0; i < results0.size(); ++i)
-          {
-            SAPInterval* ivl = (SAPInterval*)results0[i];
-            if(callback(ivl->obj, obj, cdata))
-              break;
-          }
-        }
+          checkColl(results0.begin(), results0.end(), obj, cdata, callback);
         else if(d2 >= d1 && d2 >= d3)
-        {
-          for(unsigned int i = 0; i < results1.size(); ++i)
-          {
-            SAPInterval* ivl = (SAPInterval*)results1[i];
-            if(callback(ivl->obj, obj, cdata))
-              break;
-          }
-        }
+          checkColl(results1.begin(), results1.end(), obj, cdata, callback);
         else
-        {
-          for(unsigned int i = 0; i < results2.size(); ++i)
-          {
-            SAPInterval* ivl = (SAPInterval*)results2[i];
-            if(callback(ivl->obj, obj, cdata))
-              break;
-          }
-        }
+          checkColl(results2.begin(), results2.end(), obj, cdata, callback);
       }
       else
+        checkColl(results2.begin(), results2.end(), obj, cdata, callback);
+    }
+    else
+      checkColl(results1.begin(), results1.end(), obj, cdata, callback);
+  }
+  else
+    checkColl(results0.begin(), results0.end(), obj, cdata, callback);
+
+  results0.clear();
+  results1.clear();
+  results2.clear();
+}
+
+void IntervalTreeCollisionManager::distance(CollisionObject* obj, void* cdata_, DistanceCallBack callback) const
+{
+  static const unsigned int CUTOFF = 100;
+
+  DistanceData* cdata = static_cast<DistanceData*>(cdata_);
+  Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5;
+  AABB aabb = obj->getAABB();
+  if(cdata->min_distance < std::numeric_limits<BVH_REAL>::max())
+  {
+    BVH_REAL d = cdata->min_distance;
+    aabb.min_ -= Vec3f(d, d, d);
+    aabb.max_ += Vec3f(d, d, d);
+  }
+
+  int status = 1;
+  BVH_REAL old_min_distance;
+  
+  while(1)
+  {
+    old_min_distance = cdata->min_distance;
+
+    std::deque<SimpleInterval*> results0, results1, results2;
+
+    results0 = interval_trees[0]->query(aabb.min_[0], aabb.max_[0]);
+    if(results0.size() > CUTOFF)
+    {
+      results1 = interval_trees[1]->query(aabb.min_[1], aabb.max_[1]);
+      if(results1.size() > CUTOFF)
       {
-        for(unsigned int i = 0; i < results2.size(); ++i)
+        results2 = interval_trees[2]->query(aabb.min_[2], aabb.max_[2]);
+        if(results2.size() > CUTOFF)
         {
-          SAPInterval* ivl = (SAPInterval*)results2[i];
-          if(callback(ivl->obj, obj, cdata))
-            break;
+          int d1 = results0.size();
+          int d2 = results1.size();
+          int d3 = results2.size();
+
+          if(d1 >= d2 && d1 >= d3)
+            checkDist(results0.begin(), results1.end(), obj, cdata, callback);
+          else if(d2 >= d1 && d2 >= d3)
+            checkDist(results1.begin(), results1.end(), obj, cdata, callback);
+          else
+            checkDist(results2.begin(), results2.end(), obj, cdata, callback);
         }
+        else
+          checkDist(results2.begin(), results2.end(), obj, cdata, callback);
       }
+      else
+        checkDist(results1.begin(), results1.end(), obj, cdata, callback);
     }
     else
+      checkDist(results0.begin(), results0.end(), obj, cdata, callback);
+
+    results0.clear();
+    results1.clear();
+    results2.clear();
+
+    if(status == 1)
     {
-      for(unsigned int i = 0; i < results1.size(); ++i)
+      if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
+      {
+        if(cdata->min_distance < old_min_distance) break;
+        else
+          cdata->min_distance = std::numeric_limits<BVH_REAL>::max();
+      }
+      else
       {
-        SAPInterval* ivl = (SAPInterval*)results1[i];
-        if(callback(ivl->obj, obj, cdata))
-          break;
+        if(cdata->min_distance < old_min_distance)
+        {
+          BVH_REAL d = cdata->min_distance;
+          aabb.min_ = obj->getAABB().min_ - Vec3f(d, d, d);
+          aabb.max_ = obj->getAABB().max_ + Vec3f(d, d, d);
+          status = 0;
+        }
+        else
+        {
+          if(aabb.equal(obj->getAABB()))
+          {
+            aabb.min_ -= delta;
+            aabb.max_ += delta;
+          }
+          else
+          {
+            aabb.min_ = aabb.min_ * 2 - obj->getAABB().min_;
+            aabb.max_ = aabb.max_ * 2 - obj->getAABB().max_;
+          }
+        }
       }
     }
+    else if(status == 0)
+      break;
   }
-  else
-  {
-    for(unsigned int i = 0; i < results0.size(); ++i)
-    {
-      SAPInterval* ivl = (SAPInterval*)results0[i];
-      if(callback(ivl->obj, obj, cdata))
-        break;
-    }
-  }
-
-  results0.clear();
-  results1.clear();
-  results2.clear();
 }
 
 void IntervalTreeCollisionManager::collide(void* cdata, CollisionCallBack callback) const
@@ -1055,6 +1285,35 @@ bool IntervalTreeCollisionManager::empty() const
   return endpoints[0].empty();
 }
 
+void IntervalTreeCollisionManager::checkColl(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, CollisionCallBack callback) const
+{
+  while(pos_start != pos_end)
+  {
+    SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start);
+      
+    if(ivl->obj->getAABB().overlap(obj->getAABB()))
+    {
+      if(callback(ivl->obj, obj, cdata))
+        return;
+    }
+      
+    pos_start++;
+  }
+}
+
+void IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback) const
+{
+  while(pos_start != pos_end)
+  {
+    SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start);
+    if(callback(ivl->obj, obj, cdata))
+      return;
+
+    pos_start++;
+  }
+}
+
+
 
 
 }
-- 
GitLab