From 4201f05a90bcc08fc401f97faa87244b8a4b7826 Mon Sep 17 00:00:00 2001
From: jpan <jpan@253336fb-580f-4252-a368-f3cef5a2a82b>
Date: Thu, 5 Jul 2012 23:01:28 +0000
Subject: [PATCH] Fix memory leak in interval tree

git-svn-id: https://kforge.ros.org/fcl/fcl_ros@117 253336fb-580f-4252-a368-f3cef5a2a82b
---
 trunk/fcl/include/fcl/BV/AABB.h               |   4 +-
 trunk/fcl/include/fcl/broad_phase_collision.h |  80 ++++++++++---
 trunk/fcl/include/fcl/hierarchy_tree.h        | 109 +++++++++++-------
 trunk/fcl/src/BV/AABB.cpp                     |  33 +++++-
 trunk/fcl/src/broad_phase_collision.cpp       |  82 ++++++-------
 5 files changed, 208 insertions(+), 100 deletions(-)

diff --git a/trunk/fcl/include/fcl/BV/AABB.h b/trunk/fcl/include/fcl/BV/AABB.h
index 02066cac..cdd6a303 100644
--- a/trunk/fcl/include/fcl/BV/AABB.h
+++ b/trunk/fcl/include/fcl/BV/AABB.h
@@ -186,7 +186,9 @@ public:
     return (min_ + max_) * 0.5;
   }
 
-  BVH_REAL distance(const AABB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
+  BVH_REAL distance(const AABB& other, Vec3f* P, Vec3f* Q) const;
+
+  BVH_REAL distance(const AABB& other) const;
 
   inline bool equal(const AABB& other) const
   {
diff --git a/trunk/fcl/include/fcl/broad_phase_collision.h b/trunk/fcl/include/fcl/broad_phase_collision.h
index 9eacf4f7..d900bbaa 100644
--- a/trunk/fcl/include/fcl/broad_phase_collision.h
+++ b/trunk/fcl/include/fcl/broad_phase_collision.h
@@ -143,6 +143,18 @@ protected:
   mutable std::set<std::pair<CollisionObject*, CollisionObject*> > tested_set;
   mutable bool enable_tested_set_;
 
+  bool inTestedSet(CollisionObject* a, CollisionObject* b) const
+  {
+    if(a < b) return tested_set.find(std::make_pair(a, b)) != tested_set.end();
+    else return tested_set.find(std::make_pair(b, a)) != tested_set.end();
+  }
+
+  void insertTestedSet(CollisionObject* a, CollisionObject* b) const
+  {
+    if(a < b) tested_set.insert(std::make_pair(a, b));
+    else tested_set.insert(std::make_pair(b, a));
+  }
+
 };
 
 
@@ -504,7 +516,7 @@ bool SpatialHashingCollisionManager<HashTable>::collide_(CollisionObject* obj, v
       for(it = objs_outside_scene_limit.begin(); it != objs_outside_scene_limit.end(); ++it)
       {
         if(obj == *it) continue;
-        if(callback(obj, *it, cdata)) return true;
+        if(callback(obj, *it, cdata)) return true; 
       }
     }
 
@@ -558,8 +570,20 @@ bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj,
         for(it = objs_outside_scene_limit.begin(); it != objs_outside_scene_limit.end(); ++it)
         {
           if(obj == *it) continue;
-          if(obj->getAABB().distance((*it)->getAABB()) < min_dist)
-            if(callback(obj, *it, cdata, min_dist)) return true;
+          if(!enable_tested_set_)
+          {
+            if(obj->getAABB().distance((*it)->getAABB()) < min_dist)
+              if(callback(obj, *it, cdata, min_dist)) return true;
+          }
+          else
+          {
+            if(!inTestedSet(obj, *it))
+            {
+              if(obj->getAABB().distance((*it)->getAABB()) < min_dist)
+                if(callback(obj, *it, cdata, min_dist)) return true;
+              insertTestedSet(obj, *it);
+            }
+          }
         }
       }
       
@@ -567,8 +591,20 @@ bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj,
       for(unsigned int i = 0; i < query_result.size(); ++i)
       {
         if(obj == query_result[i]) continue;
-        if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist)
-          if(callback(obj, query_result[i], cdata, min_dist)) return true;
+        if(!enable_tested_set_)
+        {
+          if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist)
+            if(callback(obj, query_result[i], cdata, min_dist)) return true;
+        }
+        else
+        {
+          if(!inTestedSet(obj, query_result[i]))
+          {
+            if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist)
+              if(callback(obj, query_result[i], cdata, min_dist)) return true;
+            insertTestedSet(obj, query_result[i]);
+          }
+        }
       }
     }
     else
@@ -577,19 +613,27 @@ bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj,
       for(it = objs_outside_scene_limit.begin(); it != objs_outside_scene_limit.end(); ++it)
       {
         if(obj == *it) continue;
-        if(obj->getAABB().distance((*it)->getAABB()) < min_dist)
-          if(callback(obj, *it, cdata, min_dist)) return true;
+        if(!enable_tested_set_)
+        {
+          if(obj->getAABB().distance((*it)->getAABB()) < min_dist)
+            if(callback(obj, *it, cdata, min_dist)) return true;
+        }
+        else
+        {
+          if(!inTestedSet(obj, *it))
+          {
+            if(obj->getAABB().distance((*it)->getAABB()) < min_dist)
+              if(callback(obj, *it, cdata, min_dist)) return true;
+            insertTestedSet(obj, *it);
+          }
+        }
       }
     }
 
     if(status == 1)
     {
       if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
-      {
-        if(min_dist < old_min_distance) break;
-        else
-          min_dist = std::numeric_limits<BVH_REAL>::max();
-      }
+        break;
       else
       {
         if(min_dist < old_min_distance)
@@ -656,10 +700,16 @@ void SpatialHashingCollisionManager<HashTable>::collide(void* cdata, CollisionCa
 template<typename HashTable>
 void SpatialHashingCollisionManager<HashTable>::distance(void* cdata, DistanceCallBack callback) const
 {
+  enable_tested_set_ = true;
+  tested_set.clear();
+  
   BVH_REAL min_dist = std::numeric_limits<BVH_REAL>::max();
 
   for(std::list<CollisionObject*>::const_iterator it = objs.begin(); it != objs.end(); ++it)
-    if(distance_(*it, cdata, callback, min_dist)) return;
+    if(distance_(*it, cdata, callback, min_dist)) break;
+
+  enable_tested_set_ = false;
+  tested_set.clear();
 }
 
 template<typename HashTable>
@@ -1228,9 +1278,9 @@ public:
   
   DynamicAABBTreeCollisionManager()
   {
-    max_tree_nonbalanced_level = 4;
+    max_tree_nonbalanced_level = 10;
     tree_incremental_balance_pass = 10;
-    tree_topdown_balance_threshold = 128;
+    tree_topdown_balance_threshold = 16;
     setup_ = false;
   }
 
diff --git a/trunk/fcl/include/fcl/hierarchy_tree.h b/trunk/fcl/include/fcl/hierarchy_tree.h
index fb52b150..cbd20735 100644
--- a/trunk/fcl/include/fcl/hierarchy_tree.h
+++ b/trunk/fcl/include/fcl/hierarchy_tree.h
@@ -133,7 +133,7 @@ public:
   }
 
   /** \brief update one leaf node's bounding volume */
-  void update(NodeType* leaf, const BV& bv)
+  void update_(NodeType* leaf, const BV& bv)
   {
     NodeType* root = removeLeaf(leaf);
     if(root)
@@ -168,11 +168,18 @@ public:
     insertLeaf(root, leaf);
   }
 
+  bool update(NodeType* leaf, const BV& bv)
+  {
+    if(leaf->bv.contain(bv)) return false;
+    update_(leaf, bv);
+    return true;
+  }
+
   /** \brief update one leaf's bounding volume, with prediction */
   bool update(NodeType* leaf, const BV& bv, const Vec3f& vel, BVH_REAL margin)
   {
     if(leaf->bv.contain(bv)) return false;
-    update(leaf, bv);
+    update_(leaf, bv);
     return true;
   }
 
@@ -180,7 +187,7 @@ public:
   bool update(NodeType* leaf, const BV& bv, const Vec3f& vel)
   {
     if(leaf->bv.contain(bv)) return false;
-    update(leaf, bv);
+    update_(leaf, bv);
     return true;
   }
 
@@ -209,6 +216,27 @@ public:
     }
   }
 
+  /** \brief refit */
+  void refit()
+  {
+    if(root_node)
+    {
+      recurseRefit(root_node);
+    }
+  }
+
+  void recurseRefit(NodeType* node)
+  {
+    if(!node->isLeaf())
+    {
+      recurseRefit(node->childs[0]);
+      recurseRefit(node->childs[1]);
+      node->bv = node->childs[0]->bv + node->childs[1]->bv;
+    }
+    else
+      return;
+  }
+
   size_t getMaxHeight(NodeType* node) const
   {
     if(!node->isLeaf())
@@ -295,9 +323,47 @@ public:
     }
   }
 
+
+  /** \brief construct a tree for a set of leaves from bottom -- very heavy way */
+  void bottomup(std::vector<NodeType*>& leaves)
+  {
+    while(leaves.size() > 1)
+    {
+      BVH_REAL min_size = std::numeric_limits<BVH_REAL>::max();
+      int min_idx[2] = {-1, -1};
+      for(size_t i = 0; i < leaves.size(); ++i)
+      {
+        for(size_t j = i+1; j < leaves.size(); ++j)
+        {
+          BVH_REAL cur_size = (leaves[i]->bv + leaves[j]->bv).size();
+          if(cur_size < min_size)
+          {
+            min_size = cur_size;
+            min_idx[0] = i;
+            min_idx[1] = j;
+          }
+        }
+      }
+
+      NodeType* n[2] = {leaves[min_idx[0]], leaves[min_idx[1]]};
+      NodeType* p = createNode(NULL, n[0]->bv, n[1]->bv, NULL);
+      p->childs[0] = n[0];
+      p->childs[1] = n[1];
+      n[0]->parent = p;
+      n[1]->parent = p;
+      leaves[min_idx[0]] = p;
+      NodeType* tmp = leaves[min_idx[1]];
+      leaves[min_idx[1]] = leaves.back();
+      leaves.back() = tmp;
+      leaves.pop_back();
+    }
+  }
+
+
   /** \brief construct a tree for a set of leaves from top */
   NodeType* topdown(std::vector<NodeType*>& leaves, int bu_threshold)
   {
+    n_leaves = leaves.size();
     static const Vec3f axis[3] = {Vec3f(1, 0, 0), Vec3f(0, 1, 0), Vec3f(0, 0, 1)};
     if(leaves.size() > 1)
     {
@@ -391,43 +457,6 @@ private:
     return n;
   }
   
-
-  /** \brief construct a tree for a set of leaves from bottom */
-  void bottomup(std::vector<NodeType*>& leaves)
-  {
-    while(leaves.size() > 1)
-    {
-      BVH_REAL min_size = std::numeric_limits<BVH_REAL>::max();
-      int min_idx[2] = {-1, -1};
-      for(size_t i = 0; i < leaves.size(); ++i)
-      {
-        for(size_t j = i+1; j < leaves.size(); ++j)
-        {
-          BVH_REAL cur_size = (leaves[i]->bv + leaves[j]->bv).size();
-          if(cur_size < min_size)
-          {
-            min_size = cur_size;
-            min_idx[0] = i;
-            min_idx[1] = j;
-          }
-        }
-      }
-
-      NodeType* n[2] = {leaves[min_idx[0]], leaves[min_idx[1]]};
-      NodeType* p = createNode(NULL, n[0]->bv, n[1]->bv, NULL);
-      p->childs[0] = n[0];
-      p->childs[1] = n[1];
-      n[0]->parent = p;
-      n[1]->parent = p;
-      leaves[min_idx[0]] = p;
-      NodeType* tmp = leaves[min_idx[1]];
-      leaves[min_idx[1]] = leaves.back();
-      leaves.back() = tmp;
-      leaves.pop_back();
-    }
-  }
-
-
   /** \brief Insert a leaf node and also update its ancestors */
   void insertLeaf(NodeType* root, NodeType* leaf)
   {
diff --git a/trunk/fcl/src/BV/AABB.cpp b/trunk/fcl/src/BV/AABB.cpp
index 63099f7b..b645d52f 100644
--- a/trunk/fcl/src/BV/AABB.cpp
+++ b/trunk/fcl/src/BV/AABB.cpp
@@ -54,10 +54,10 @@ BVH_REAL AABB::distance(const AABB& other, Vec3f* P, Vec3f* Q) const
   BVH_REAL result = 0;
   for(size_t 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];
+    const BVH_REAL& amin = min_[i];
+    const BVH_REAL& amax = max_[i];
+    const BVH_REAL& bmin = other.min_[i];
+    const BVH_REAL& bmax = other.max_[i];
     
     if(amin > bmax)
     {
@@ -102,4 +102,29 @@ BVH_REAL AABB::distance(const AABB& other, Vec3f* P, Vec3f* Q) const
   return sqrt(result);
 }
 
+BVH_REAL AABB::distance(const AABB& other) const
+{
+  BVH_REAL result = 0;
+  for(size_t i = 0; i < 3; ++i)
+  {
+    const BVH_REAL& amin = min_[i];
+    const BVH_REAL& amax = max_[i];
+    const BVH_REAL& bmin = other.min_[i];
+    const BVH_REAL& bmax = other.max_[i];
+    
+    if(amin > bmax)
+    {
+      BVH_REAL delta = bmax - amin;
+      result += delta * delta;
+    }
+    else if(bmin > amax)
+    {
+      BVH_REAL delta = amax - bmin;
+      result += delta * delta;
+    }
+  }
+
+  return sqrt(result);
+}
+
 }
diff --git a/trunk/fcl/src/broad_phase_collision.cpp b/trunk/fcl/src/broad_phase_collision.cpp
index ca6560cd..a5c03031 100644
--- a/trunk/fcl/src/broad_phase_collision.cpp
+++ b/trunk/fcl/src/broad_phase_collision.cpp
@@ -159,8 +159,9 @@ void NaiveCollisionManager::collide(void* cdata, CollisionCallBack callback) con
     it2 = it1; it2++;
     for(; it2 != objs.end(); ++it2)
     {
-      if(callback(*it1, *it2, cdata))
-        return;
+      if((*it1)->getAABB().overlap((*it2)->getAABB()))
+        if(callback(*it1, *it2, cdata))
+          return;
     }
   }
 }
@@ -202,8 +203,9 @@ void NaiveCollisionManager::collide(BroadPhaseCollisionManager* other_manager_,
   {
     for(it2 = other_manager->objs.begin(); it2 != other_manager->objs.end(); ++it2)
     {
-      if(callback((*it1), (*it2), cdata))
-        return;
+      if((*it1)->getAABB().overlap((*it2)->getAABB()))
+        if(callback((*it1), (*it2), cdata))
+          return;
     }
   }
 }
@@ -539,11 +541,7 @@ bool SSaPCollisionManager::distance_(CollisionObject* obj, void* cdata, Distance
     if(status == 1)
     {
       if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
-      {
-        if(min_dist < 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.
-          min_dist = std::numeric_limits<BVH_REAL>::max();
-      }
+        break;
       else
       {
         // from infinity to a finite one, only need one additional loop 
@@ -1254,19 +1252,15 @@ bool SaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceC
           }
           else
           {
-            bool not_find;
-            if(curr_obj < obj) not_find = (tested_set.find(std::make_pair(curr_obj, obj)) == tested_set.end());
-            else not_find = (tested_set.find(std::make_pair(obj, curr_obj)) == tested_set.end());
-            if(not_find)
+            if(!inTestedSet(curr_obj, obj))
             {
               if(pos->aabb->cached.distance(obj->getAABB()) < min_dist)
               {
                 if(callback(curr_obj, obj, cdata, min_dist))
                   return true;
               }
-
-              if(curr_obj < obj) tested_set.insert(std::make_pair(curr_obj, obj));
-              else tested_set.insert(std::make_pair(obj, curr_obj));
+              
+              insertTestedSet(curr_obj, obj);
             }
           }
         }
@@ -1278,11 +1272,7 @@ bool SaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceC
     if(status == 1)
     {
       if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
-      {
-        if(min_dist < old_min_distance) break;
-        else
-          min_dist = std::numeric_limits<BVH_REAL>::max();
-      }
+        break;
       else
       {
         if(min_dist < old_min_distance)
@@ -1334,13 +1324,19 @@ void SaPCollisionManager::distance(void* cdata, DistanceCallBack callback) const
 {
   if(size() == 0) return;
 
+  enable_tested_set_ = true;
+  tested_set.clear();
+  
   BVH_REAL min_dist = std::numeric_limits<BVH_REAL>::max();
 
   for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it)
   {
     if(distance_((*it)->obj, cdata, callback, min_dist))
-      return;
+      break;
   }
+
+  enable_tested_set_ = false;
+  tested_set.clear();
 }
 
 void SaPCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const
@@ -1665,9 +1661,6 @@ void IntervalTreeCollisionManager::clear()
   endpoints[1].clear();
   endpoints[2].clear();
 
-  for(int i = 0; i < 3; ++i)
-    obj_interval_maps[i].clear();
-
   delete interval_trees[0]; interval_trees[0] = NULL;
   delete interval_trees[1]; interval_trees[1] = NULL;
   delete interval_trees[2]; interval_trees[2] = NULL;
@@ -1681,6 +1674,9 @@ void IntervalTreeCollisionManager::clear()
     }
   }
 
+  for(int i = 0; i < 3; ++i)
+    obj_interval_maps[i].clear();
+
   setup_ = false;
 }
 
@@ -1809,11 +1805,7 @@ bool IntervalTreeCollisionManager::distance_(CollisionObject* obj, void* cdata,
     if(status == 1)
     {
       if(old_min_distance < std::numeric_limits<BVH_REAL>::max())
-      {
-        if(min_dist < old_min_distance) break;
-        else
-          min_dist = std::numeric_limits<BVH_REAL>::max();
-      }
+        break;
       else
       {
         if(min_dist < old_min_distance)
@@ -1902,7 +1894,7 @@ void IntervalTreeCollisionManager::distance(void* cdata, DistanceCallBack callba
   BVH_REAL min_dist = std::numeric_limits<BVH_REAL>::max();
   
   for(size_t i = 0; i < endpoints[0].size(); ++i)
-    if(distance_(endpoints[0][i].obj, cdata, callback, min_dist)) return;
+    if(distance_(endpoints[0][i].obj, cdata, callback, min_dist)) break;
   
   enable_tested_set_ = false;
   tested_set.clear();
@@ -1994,11 +1986,7 @@ bool IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_
       }
       else
       {
-        bool not_find;
-        if(ivl->obj < obj) not_find = (tested_set.find(std::make_pair(ivl->obj, obj)) == tested_set.end());
-        else not_find = (tested_set.find(std::make_pair(obj, ivl->obj)) == tested_set.end());
-
-        if(not_find)
+        if(!inTestedSet(ivl->obj, obj))
         {
           if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist)
           {
@@ -2006,8 +1994,7 @@ bool IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_
               return true;
           }
 
-          if(ivl->obj < obj) tested_set.insert(std::make_pair(ivl->obj, obj));
-          else tested_set.insert(std::make_pair(obj, ivl->obj));
+          insertTestedSet(ivl->obj, obj);
         }
       }
     }
@@ -2063,12 +2050,14 @@ void DynamicAABBTreeCollisionManager::setup()
 {
   if(!setup_)
   {
-    size_t height = dtree.getMaxHeight(dtree.getRoot());
-    size_t num = dtree.size();
+    int height = dtree.getMaxHeight(dtree.getRoot());
+    int num = dtree.size();
+    
     if(height - std::log((BVH_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level)
       dtree.balanceIncremental(10);
     else
       dtree.balanceTopdown(tree_topdown_balance_threshold);
+
     setup_ = true;
   }
 }
@@ -2076,6 +2065,7 @@ void DynamicAABBTreeCollisionManager::setup()
 
 void DynamicAABBTreeCollisionManager::update()
 {
+  /*
   for(DynamicAABBTable::const_iterator it = table.begin(); it != table.end(); ++it)
   {
     CollisionObject* obj = it->first;
@@ -2083,6 +2073,18 @@ void DynamicAABBTreeCollisionManager::update()
     if(!node->bv.equal(obj->getAABB()))
       dtree.update(node, obj->getAABB());
   }
+  */
+ 
+  
+  for(DynamicAABBTable::const_iterator it = table.begin(); it != table.end(); ++it)
+  {
+    CollisionObject* obj = it->first;
+    DynamicAABBNode* node = it->second;
+    node->bv = obj->getAABB();
+  }
+
+  dtree.refit();
+
   setup_ = false;
 }
 
-- 
GitLab