From 928b1756335451c61edf05903d65d99d9d74f632 Mon Sep 17 00:00:00 2001
From: panjia1983 <panjia1983@gmail.com>
Date: Fri, 9 Aug 2013 17:23:25 -0700
Subject: [PATCH] fix some bug in gjk; add continuous collision, still need
 more test

---
 include/fcl/BVH/BVH_model.h                   |   1 +
 include/fcl/broadphase/hierarchy_tree.hxx     |   2 +-
 include/fcl/ccd/conservative_advancement.h    |  23 +-
 include/fcl/ccd/motion.h                      | 124 ++-
 include/fcl/ccd/motion_base.h                 |  45 +-
 include/fcl/collision.h                       |  22 -
 include/fcl/collision_data.h                  | 138 ++-
 include/fcl/collision_object.h                |   1 +
 include/fcl/continuous_collision.h            |  28 +
 include/fcl/distance.h                        |  10 -
 include/fcl/intersect.h                       |  62 +-
 include/fcl/math/transform.h                  |   1 +
 include/fcl/narrowphase/gjk.h                 |  57 +-
 include/fcl/narrowphase/gjk_libccd.h          |   2 +-
 include/fcl/narrowphase/narrowphase.h         | 257 +++--
 include/fcl/penetration_depth.h               |  24 +
 include/fcl/shape/geometric_shapes.h          |   4 +-
 include/fcl/shape/geometric_shapes_utility.h  |   4 +-
 include/fcl/traversal/traversal_node_base.h   |  14 +
 .../fcl/traversal/traversal_node_bvh_shape.h  | 581 ++++++++++-
 include/fcl/traversal/traversal_node_bvhs.h   |  45 +-
 include/fcl/traversal/traversal_node_octree.h |  13 +-
 include/fcl/traversal/traversal_node_setup.h  | 186 +++-
 include/fcl/traversal/traversal_node_shapes.h |  60 +-
 src/broadphase/broadphase_SSaP.cpp            |   2 +-
 src/ccd/conservative_advancement.cpp          | 875 +++++++++++++++--
 src/ccd/motion.cpp                            |  54 +-
 src/collision.cpp                             |  81 +-
 src/collision_func_matrix.cpp                 |  13 +
 src/continuous_collision.cpp                  | 307 ++++++
 src/distance.cpp                              |  40 +-
 src/intersect.cpp                             | 274 ++++++
 src/narrowphase/gjk.cpp                       | 173 +---
 src/narrowphase/gjk_libccd.cpp                | 360 ++++---
 src/narrowphase/narrowphase.cpp               | 280 +++---
 src/shape/geometric_shapes.cpp                |   2 +-
 src/shape/geometric_shapes_utility.cpp        |   4 +-
 src/traversal/traversal_node_bvhs.cpp         |  22 +-
 test/CMakeLists.txt                           |   1 +
 test/test_fcl_geometric_shapes.cpp            | 185 ++--
 test/test_fcl_shape_mesh_consistency.cpp      | 914 +++++++++---------
 test/test_fcl_utility.cpp                     |   7 +-
 test/test_fcl_utility.h                       |  18 +
 43 files changed, 3993 insertions(+), 1323 deletions(-)
 create mode 100644 include/fcl/continuous_collision.h
 create mode 100644 include/fcl/penetration_depth.h
 create mode 100644 src/continuous_collision.cpp

diff --git a/include/fcl/BVH/BVH_model.h b/include/fcl/BVH/BVH_model.h
index 3560a57f..4c6a0699 100644
--- a/include/fcl/BVH/BVH_model.h
+++ b/include/fcl/BVH/BVH_model.h
@@ -216,6 +216,7 @@ public:
   /// @brief Fitting rule to fit a BV node to a set of geometry primitives
   boost::shared_ptr<BVFitterBase<BV> > bv_fitter;
 
+
 private:
 
   int num_tris_allocated;
diff --git a/include/fcl/broadphase/hierarchy_tree.hxx b/include/fcl/broadphase/hierarchy_tree.hxx
index 07b62912..03bb175e 100644
--- a/include/fcl/broadphase/hierarchy_tree.hxx
+++ b/include/fcl/broadphase/hierarchy_tree.hxx
@@ -1390,7 +1390,7 @@ void HierarchyTree<BV>::bottomup(size_t* lbeg, size_t* lend)
   size_t* lcur_end = lend;
   while(lbeg < lcur_end - 1)
   {
-    size_t* min_it1, *min_it2;
+    size_t* min_it1 = NULL, *min_it2 = NULL;
     FCL_REAL min_size = std::numeric_limits<FCL_REAL>::max();
     for(size_t* it1 = lbeg; it1 < lcur_end; ++it1)
     {
diff --git a/include/fcl/ccd/conservative_advancement.h b/include/fcl/ccd/conservative_advancement.h
index 4129a967..d6d7aeb8 100644
--- a/include/fcl/ccd/conservative_advancement.h
+++ b/include/fcl/ccd/conservative_advancement.h
@@ -46,15 +46,22 @@
 namespace fcl
 {
 
-template<typename BV, typename ConservativeAdvancementNode, typename CollisionNode>
-int conservativeAdvancement(const CollisionGeometry* o1,
-                            const MotionBase* motion1,
-                            const CollisionGeometry* o2,
-                            const MotionBase* motion2,
-                            const CollisionRequest& request,
-                            CollisionResult& result,
-                            FCL_REAL& toc);
+template<typename NarrowPhaseSolver>
+struct ConservativeAdvancementFunctionMatrix
+{
+  typedef FCL_REAL (*ConservativeAdvancementFunc)(const CollisionGeometry* o1, const MotionBase* motion1, const CollisionGeometry* o2, const MotionBase* motion2, const NarrowPhaseSolver* nsolver, const ContinuousCollisionRequest& request, ContinuousCollisionResult& result);
+
+  ConservativeAdvancementFunc conservative_advancement_matrix[NODE_COUNT][NODE_COUNT];
+
+  ConservativeAdvancementFunctionMatrix();
+};
+
+
 
 }
 
 #endif
+
+
+
+
diff --git a/include/fcl/ccd/motion.h b/include/fcl/ccd/motion.h
index 3494cabf..a281a182 100644
--- a/include/fcl/ccd/motion.h
+++ b/include/fcl/ccd/motion.h
@@ -46,6 +46,64 @@
 namespace fcl
 {
 
+class TranslationMotion : public MotionBase
+{
+public:
+  /// @brief Construct motion from intial and goal transform
+  TranslationMotion(const Transform3f& tf1,
+                    const Transform3f& tf2) : MotionBase(),
+                                              rot(tf1.getQuatRotation()),
+                                              trans_start(tf1.getTranslation()),
+                                              trans_range(tf2.getTranslation() - tf1.getTranslation())
+  {
+  }
+
+  TranslationMotion(const Matrix3f& R, const Vec3f& T1, const Vec3f& T2) : MotionBase()
+  {
+    rot.fromRotation(R);
+    trans_start = T1;
+    trans_range = T2 - T1;
+  }
+
+  bool integrate(FCL_REAL dt) const
+  {
+    if(dt > 1) dt = 1;
+    tf = Transform3f(rot, trans_start + trans_range * dt);
+    return true;
+  }
+
+  FCL_REAL computeMotionBound(const BVMotionBoundVisitor& mb_visitor) const
+  {
+    return mb_visitor.visit(*this);
+  }
+
+  FCL_REAL computeMotionBound(const TriangleMotionBoundVisitor& mb_visitor) const
+  {
+    return mb_visitor.visit(*this);
+  }
+
+  void getCurrentTransform(Transform3f& tf_) const
+  {
+    tf_ = tf;
+  }
+
+  void getTaylorModel(TMatrix3& tm, TVector3& tv) const
+  {
+  }
+
+  Vec3f getVelocity() const
+  {
+    return trans_range;
+  }
+
+ private:
+  /// @brief initial and goal transforms
+  Quaternion3f rot;
+  Vec3f trans_start, trans_range;
+
+  mutable Transform3f tf;
+};
+
 class SplineMotion : public MotionBase
 {
 public:
@@ -53,6 +111,19 @@ public:
   SplineMotion(const Vec3f& Td0, const Vec3f& Td1, const Vec3f& Td2, const Vec3f& Td3,
                const Vec3f& Rd0, const Vec3f& Rd1, const Vec3f& Rd2, const Vec3f& Rd3);
 
+  // @brief Construct motion from initial and goal transform
+  SplineMotion(const Matrix3f& R1, const Vec3f& T1,
+               const Matrix3f& R2, const Vec3f& T2) : MotionBase()
+  {
+    // TODO
+  }
+
+  SplineMotion(const Transform3f& tf1,
+               const Transform3f& tf2) : MotionBase()
+  {
+    // TODO
+  }
+
   
   /// @brief Integrate the motion from 0 to dt
   /// We compute the current transformation from zero point instead of from last integrate time, for precision.
@@ -71,22 +142,6 @@ public:
   }
 
   /// @brief Get the rotation and translation in current step
-  void getCurrentTransform(Matrix3f& R, Vec3f& T) const
-  {
-    R = tf.getRotation();
-    T = tf.getTranslation();
-  }
-
-  void getCurrentRotation(Matrix3f& R) const
-  {
-    R = tf.getRotation();
-  }
-
-  void getCurrentTranslation(Vec3f& T) const
-  {
-    T = tf.getTranslation();
-  }
-
   void getCurrentTransform(Transform3f& tf_) const
   {
     tf_ = tf;
@@ -209,7 +264,7 @@ class ScrewMotion : public MotionBase
 {
 public:
   /// @brief Default transformations are all identities
-  ScrewMotion()
+  ScrewMotion() : MotionBase()
   {
     // Default angular velocity is zero
     axis.setValue(1, 0, 0);
@@ -223,7 +278,8 @@ public:
 
   /// @brief Construct motion from the initial rotation/translation and goal rotation/translation
   ScrewMotion(const Matrix3f& R1, const Vec3f& T1,
-              const Matrix3f& R2, const Vec3f& T2) : tf1(R1, T1),
+              const Matrix3f& R2, const Vec3f& T2) : MotionBase(),
+                                                     tf1(R1, T1),
                                                      tf2(R2, T2),
                                                      tf(tf1)
   {
@@ -267,22 +323,6 @@ public:
 
 
   /// @brief Get the rotation and translation in current step
-  void getCurrentTransform(Matrix3f& R, Vec3f& T) const
-  {
-    R = tf.getRotation();
-    T = tf.getTranslation();
-  }
-
-  void getCurrentRotation(Matrix3f& R) const
-  {
-    R = tf.getRotation();
-  }
-
-  void getCurrentTranslation(Vec3f& T) const
-  {
-    T = tf.getTranslation();
-  }
-
   void getCurrentTransform(Transform3f& tf_) const
   {
     tf_ = tf;
@@ -438,22 +478,6 @@ public:
   }
 
   /// @brief Get the rotation and translation in current step
-  void getCurrentTransform(Matrix3f& R, Vec3f& T) const
-  {
-    R = tf.getRotation();
-    T = tf.getTranslation();
-  }
-
-  void getCurrentRotation(Matrix3f& R) const
-  {
-    R = tf.getRotation();
-  }
-
-  void getCurrentTranslation(Vec3f& T) const
-  {
-    T = tf.getTranslation();
-  }
-
   void getCurrentTransform(Transform3f& tf_) const
   {
     tf_ = tf;
diff --git a/include/fcl/ccd/motion_base.h b/include/fcl/ccd/motion_base.h
index edce660f..aba89e3d 100644
--- a/include/fcl/ccd/motion_base.h
+++ b/include/fcl/ccd/motion_base.h
@@ -52,6 +52,7 @@ class MotionBase;
 class SplineMotion;
 class ScrewMotion;
 class InterpMotion;
+class TranslationMotion;
 
 /// @brief Compute the motion bound for a bounding volume, given the closest direction n between two query objects
 class BVMotionBoundVisitor
@@ -61,6 +62,7 @@ public:
   virtual FCL_REAL visit(const SplineMotion& motion) const = 0;
   virtual FCL_REAL visit(const ScrewMotion& motion) const = 0;
   virtual FCL_REAL visit(const InterpMotion& motion) const = 0;
+  virtual FCL_REAL visit(const TranslationMotion& motion) const = 0;
 };
 
 template<typename BV>
@@ -73,6 +75,7 @@ public:
   virtual FCL_REAL visit(const SplineMotion& motion) const { return 0; }
   virtual FCL_REAL visit(const ScrewMotion& motion) const { return 0; }
   virtual FCL_REAL visit(const InterpMotion& motion) const { return 0; }
+  virtual FCL_REAL visit(const TranslationMotion& motion) const { return 0; }
 
 protected:
   BV bv;
@@ -88,6 +91,8 @@ FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const ScrewMotion& motion) const;
 template<>
 FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const InterpMotion& motion) const;
 
+template<>
+FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const TranslationMotion& motion) const;
 
 
 class TriangleMotionBoundVisitor
@@ -100,6 +105,7 @@ public:
   virtual FCL_REAL visit(const SplineMotion& motion) const;
   virtual FCL_REAL visit(const ScrewMotion& motion) const;
   virtual FCL_REAL visit(const InterpMotion& motion) const;
+  virtual FCL_REAL visit(const TranslationMotion& motion) const;
 
 protected:
   Vec3f a, b, c, n;
@@ -120,17 +126,48 @@ public:
   virtual bool integrate(double dt) const = 0;
 
   /** \brief Compute the motion bound for a bounding volume, given the closest direction n between two query objects */
-  virtual FCL_REAL computeMotionBound(const BVMotionBoundVisitor& mb_visitor) const= 0;
+  virtual FCL_REAL computeMotionBound(const BVMotionBoundVisitor& mb_visitor) const = 0;
 
   /** \brief Compute the motion bound for a triangle, given the closest direction n between two query objects */
   virtual FCL_REAL computeMotionBound(const TriangleMotionBoundVisitor& mb_visitor) const = 0;
 
   /** \brief Get the rotation and translation in current step */
-  virtual void getCurrentTransform(Matrix3f& R, Vec3f& T) const = 0;
+  void getCurrentTransform(Matrix3f& R, Vec3f& T) const
+  {
+    Transform3f tf;
+    getCurrentTransform(tf);
+    R = tf.getRotation();
+    T = tf.getTranslation();
+  }
 
-  virtual void getCurrentRotation(Matrix3f& R) const = 0;
+  void getCurrentTransform(Quaternion3f& Q, Vec3f& T) const
+  {
+    Transform3f tf;
+    getCurrentTransform(tf);
+    Q = tf.getQuatRotation();
+    T = tf.getTranslation();
+  }
 
-  virtual void getCurrentTranslation(Vec3f& T) const = 0;
+  void getCurrentRotation(Matrix3f& R) const
+  {
+    Transform3f tf;
+    getCurrentTransform(tf);
+    R = tf.getRotation();
+  }
+
+  void getCurrentRotation(Quaternion3f& Q) const
+  {
+    Transform3f tf;
+    getCurrentTransform(tf);
+    Q = tf.getQuatRotation();
+  }
+
+  void getCurrentTranslation(Vec3f& T) const
+  {
+    Transform3f tf;
+    getCurrentTransform(tf);
+    T = tf.getTranslation();
+  }
 
   virtual void getCurrentTransform(Transform3f& tf) const = 0;
 
diff --git a/include/fcl/collision.h b/include/fcl/collision.h
index 3c70aaac..2288b3a1 100644
--- a/include/fcl/collision.h
+++ b/include/fcl/collision.h
@@ -50,34 +50,12 @@ namespace fcl
 /// performs the collision between them. 
 /// Return value is the number of contacts generated between the two objects.
 
-template<typename NarrowPhaseSolver>
 std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
-                    const NarrowPhaseSolver* nsolver,
                     const CollisionRequest& request,
                     CollisionResult& result);
 
-template<typename NarrowPhaseSolver>
 std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
                     const CollisionGeometry* o2, const Transform3f& tf2,
-                    const NarrowPhaseSolver* nsolver,
-                    const CollisionRequest& request,
-                    CollisionResult& result);
-
-std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
-                    const CollisionRequest& request,
-                    CollisionResult& result);
-
-std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
-                    const CollisionGeometry* o2, const Transform3f& tf2,
-                    const CollisionRequest& request,
-                    CollisionResult& result);
-
-std::size_t collide(const ContinuousCollisionObject* o1, const ContinuousCollisionObject* o2,
-                    const CollisionRequest& request,
-                    CollisionResult& result);
-
-std::size_t collide(const CollisionGeometry* o1, const MotionBase* motion1,
-                    const CollisionGeometry* o2, const MotionBase* motion2,
                     const CollisionRequest& request,
                     CollisionResult& result);
 }
diff --git a/include/fcl/collision_data.h b/include/fcl/collision_data.h
index 7b95e4a9..9621d33d 100644
--- a/include/fcl/collision_data.h
+++ b/include/fcl/collision_data.h
@@ -48,6 +48,9 @@
 namespace fcl
 {
 
+/// @brief Type of narrow phase GJK solver
+enum GJKSolverType {GST_LIBCCD, GST_INDEP};
+
 /// @brief Contact information returned by collision
 struct Contact
 {
@@ -167,7 +170,7 @@ struct CollisionResult;
 
 /// @brief request to the collision algorithm
 struct CollisionRequest
-{
+{  
   /// @brief The maximum number of contacts will return
   size_t num_max_contacts;
 
@@ -183,16 +186,29 @@ struct CollisionRequest
   /// @brief whether the cost computation is approximated
   bool use_approximate_cost;
 
+  /// @brief narrow phase solver
+  GJKSolverType gjk_solver_type;
+
+  /// @brief whether enable gjk intial guess
+  bool enable_cached_gjk_guess;
+  
+  /// @brief the gjk intial guess set by user
+  Vec3f cached_gjk_guess;
+
   CollisionRequest(size_t num_max_contacts_ = 1,
                    bool enable_contact_ = false,
                    size_t num_max_cost_sources_ = 1,
                    bool enable_cost_ = false,
-                   bool use_approximate_cost_ = true) : num_max_contacts(num_max_contacts_),
-                                                        enable_contact(enable_contact_),
-                                                        num_max_cost_sources(num_max_cost_sources_),
-                                                        enable_cost(enable_cost_),
-                                                        use_approximate_cost(use_approximate_cost_)
+                   bool use_approximate_cost_ = true,
+                   GJKSolverType gjk_solver_type_ = GST_LIBCCD) : num_max_contacts(num_max_contacts_),
+                                                                  enable_contact(enable_contact_),
+                                                                  num_max_cost_sources(num_max_cost_sources_),
+                                                                  enable_cost(enable_cost_),
+                                                                  use_approximate_cost(use_approximate_cost_),
+                                                                  gjk_solver_type(gjk_solver_type_)
   {
+    enable_cached_gjk_guess = false;
+    cached_gjk_guess = Vec3f(1, 0, 0);
   }
 
   bool isSatisfied(const CollisionResult& result) const;
@@ -208,6 +224,9 @@ private:
   /// @brief cost sources
   std::set<CostSource> cost_sources;
 
+public:
+  Vec3f cached_gjk_guess;
+
 public:
   CollisionResult()
   {
@@ -277,6 +296,7 @@ public:
   }
 };
 
+
 struct DistanceResult;
 
 /// @brief request to the distance computation
@@ -285,13 +305,29 @@ struct DistanceRequest
   /// @brief whether to return the nearest points
   bool enable_nearest_points;
 
-  DistanceRequest(bool enable_nearest_points_ = false) : enable_nearest_points(enable_nearest_points_)
+  /// @brief error threshold for approximate distance
+  FCL_REAL rel_err; // relative error, between 0 and 1
+  FCL_REAL abs_err; // absoluate error
+
+  /// @brief narrow phase solver type
+  GJKSolverType gjk_solver_type;
+
+
+
+  DistanceRequest(bool enable_nearest_points_ = false,
+                  FCL_REAL rel_err_ = 0.0,
+                  FCL_REAL abs_err_ = 0.0,
+                  GJKSolverType gjk_solver_type_ = GST_LIBCCD) : enable_nearest_points(enable_nearest_points_),
+                                                                rel_err(rel_err_),
+                                                                abs_err(abs_err_),
+                                                                gjk_solver_type(gjk_solver_type_)
   {
   }
 
   bool isSatisfied(const DistanceResult& result) const;
 };
 
+
 /// @brief distance result
 struct DistanceResult
 {
@@ -389,6 +425,94 @@ public:
 };
 
 
+enum CCDMotionType {CCDM_TRANS, CCDM_LINEAR, CCDM_SCREW, CCDM_SPLINE};
+enum CCDSolverType {CCDC_NAIVE, CCDC_CONSERVATIVE_ADVANCEMENT, CCDC_RAY_SHOOTING, CCDC_POLYNOMIAL_SOLVER};
+
+
+struct ContinuousCollisionRequest
+{
+  /// @brief maximum num of iterations
+  std::size_t num_max_iterations;
+
+  /// @brief error in first contact time
+  FCL_REAL toc_err;
+
+  /// @brief ccd motion type
+  CCDMotionType ccd_motion_type;
+
+  /// @brief gjk solver type
+  GJKSolverType gjk_solver_type;
+
+  /// @brief ccd solver type
+  CCDSolverType ccd_solver_type;
+  
+  ContinuousCollisionRequest(std::size_t num_max_iterations_ = 10,
+                             FCL_REAL toc_err_ = 0,
+                             CCDMotionType ccd_motion_type_ = CCDM_TRANS,
+                             GJKSolverType gjk_solver_type_ = GST_LIBCCD,
+                             CCDSolverType ccd_solver_type_ = CCDC_NAIVE) : num_max_iterations(num_max_iterations_),
+                                                                            toc_err(toc_err_),
+                                                                            ccd_motion_type(ccd_motion_type_),
+                                                                            gjk_solver_type(gjk_solver_type_),
+                                                                            ccd_solver_type(ccd_solver_type_)
+  {
+  }
+  
+};
+/// @brief continuous collision result
+struct ContinuousCollisionResult
+{
+  /// @brief collision or not
+  bool is_collide;
+  
+  /// @brief time of contact in [0, 1]
+  FCL_REAL time_of_contact;
+  
+  ContinuousCollisionResult() : is_collide(false), time_of_contact(1.0)
+  {
+  }
+};
+
+
+enum PenetrationDepthType {PDT_LOCAL, PDT_AL};
+
+struct PenetrationDepthMetricBase
+{
+  virtual FCL_REAL operator() (const Transform3f& tf1, const Transform3f& tf2) const = 0;
+};
+
+struct WeightEuclideanPDMetric : public PenetrationDepthMetricBase
+{
+  
+};
+
+struct PenetrationDepthRequest
+{
+  /// @brief PD algorithm type
+  PenetrationDepthType pd_type;
+
+  /// @brief gjk solver type
+  GJKSolverType gjk_solver_type;
+
+  PenetrationDepthRequest(PenetrationDepthType pd_type_ = PDT_LOCAL,
+                          GJKSolverType gjk_solver_type_ = GST_LIBCCD) : pd_type(pd_type_),
+                                                                         gjk_solver_type(gjk_solver_type_)
+  {
+  }
+};
+
+struct PenetrationDepthResult
+{
+  /// @brief penetration depth value
+  FCL_REAL pd_value;
+
+  /// @brief the transform where the collision is resolved
+  Transform3f resolve_trans;
+
+  
+};
+
+
 
 
 }
diff --git a/include/fcl/collision_object.h b/include/fcl/collision_object.h
index 2a4492a1..00716051 100644
--- a/include/fcl/collision_object.h
+++ b/include/fcl/collision_object.h
@@ -115,6 +115,7 @@ public:
 
   /// @brief threshold for free (<= is free)
   FCL_REAL threshold_free;
+
 };
 
 /// @brief the object for collision or distance computation, contains the geometry and the transform information
diff --git a/include/fcl/continuous_collision.h b/include/fcl/continuous_collision.h
new file mode 100644
index 00000000..0a6ab1ab
--- /dev/null
+++ b/include/fcl/continuous_collision.h
@@ -0,0 +1,28 @@
+#ifndef FCL_CONTINUOUS_COLLISION_H
+#define FCL_CONTINUOUS_COLLISION_H
+
+#include "fcl/math/vec_3f.h"
+#include "fcl/collision_object.h"
+#include "fcl/collision_data.h"
+
+namespace fcl
+{
+
+/// @brief continous collision checking between two objects
+FCL_REAL continuous_collide(const CollisionGeometry* o1, const Transform3f& tf1_beg, const Transform3f& tf1_end,
+                            const CollisionGeometry* o2, const Transform3f& tf2_beg, const Transform3f& tf2_end,
+                            const ContinuousCollisionRequest& request,
+                            ContinuousCollisionResult& result);
+
+FCL_REAL continuous_collide(const CollisionObject* o1, const Transform3f& tf1_end,
+                            const CollisionObject* o2, const Transform3f& tf2_end,
+                            const ContinuousCollisionRequest& request,
+                            ContinuousCollisionResult& result);
+
+FCL_REAL collide(const ContinuousCollisionObject* o1, const ContinuousCollisionObject* o2,
+                 const ContinuousCollisionRequest& request,
+                 ContinuousCollisionResult& result);
+          
+}
+
+#endif
diff --git a/include/fcl/distance.h b/include/fcl/distance.h
index 36208ec2..be65f07d 100644
--- a/include/fcl/distance.h
+++ b/include/fcl/distance.h
@@ -46,16 +46,6 @@ namespace fcl
 /// @brief Main distance interface: given two collision objects, and the requirements for contacts, including whether return the nearest points, this function performs the distance between them. 
 /// Return value is the minimum distance generated between the two objects.
 
-template<typename NarrowPhaseSolver>
-FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const NarrowPhaseSolver* nsolver,
-                  const DistanceRequest& request, DistanceResult& result);
-
-template<typename NarrowPhaseSolver>
-FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1,
-                  const CollisionGeometry* o2, const Transform3f& tf2,
-                  const NarrowPhaseSolver* nsolver,
-                  const DistanceRequest& request, DistanceResult& result);
-
 FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2,
                   const DistanceRequest& request, DistanceResult& result);
 
diff --git a/include/fcl/intersect.h b/include/fcl/intersect.h
index d0841de4..047b50a2 100644
--- a/include/fcl/intersect.h
+++ b/include/fcl/intersect.h
@@ -91,13 +91,13 @@ public:
 
   /// @brief CCD intersect between one vertex and one face, using additional filter 
   static bool intersect_VF_filtered(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& p0,
-                           const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& p1,
-                           FCL_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
+                                    const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& p1,
+                                    FCL_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
 
   /// @brief CCD intersect between two edges, using additional filter 
   static bool intersect_EE_filtered(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
-                           const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1,
-                           FCL_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
+                                    const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1,
+                                    FCL_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
 
   /// @brief CCD intersect between one vertex and and one edge 
   static bool intersect_VE(const Vec3f& a0, const Vec3f& b0, const Vec3f& p0,
@@ -204,7 +204,7 @@ private:
 
   /// @brief filter for intersection, works for both VF and EE 
   static bool intersectPreFiltering(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
-                           const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1);
+                                    const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1);
 
   /// @brief distance of point v to a plane n * x - t = 0 
   static FCL_REAL distanceToPlane(const Vec3f& n, FCL_REAL t, const Vec3f& v);
@@ -246,6 +246,46 @@ private:
   static const unsigned int MAX_TRIANGLE_CLIPS = 8;
 };
 
+/// @brief Project functions
+class Project
+{
+public:
+  struct ProjectResult
+  {
+    /// @brief Parameterization of the projected point (based on the simplex to be projected, use 2 or 3 or 4 of the array)
+    FCL_REAL parameterization[4];
+
+    /// @brief square distance from the query point to the projected simplex
+    FCL_REAL sqr_distance;
+
+    /// @brief the code of the projection type
+    unsigned int encode;
+
+    ProjectResult() : sqr_distance(-1), encode(0)
+    {
+    }
+  };
+
+  /// @brief Project point p onto line a-b
+  static ProjectResult projectLine(const Vec3f& a, const Vec3f& b, const Vec3f& p);
+
+  /// @brief Project point p onto triangle a-b-c
+  static ProjectResult projectTriangle(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& p);
+
+  /// @brief Project point p onto tetrahedra a-b-c-d
+  static ProjectResult projectTetrahedra(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d, const Vec3f& p);
+
+  /// @brief Project origin (0) onto line a-b
+  static ProjectResult projectLineOrigin(const Vec3f& a, const Vec3f& b);
+
+  /// @brief Project origin (0) onto triangle a-b-c
+  static ProjectResult projectTriangleOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c);
+
+  /// @brief Project origin (0) onto tetrahedran a-b-c-d
+  static ProjectResult projectTetrahedraOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d);
+};
+
+/// @brief Triangle distance functions
 class TriangleDistance
 {
 public:
@@ -256,7 +296,7 @@ public:
   /// X, Y are the closest points on the two segments
   /// VEC is the vector between X and Y
   static void segPoints(const Vec3f& P, const Vec3f& A, const Vec3f& Q, const Vec3f& B,
-                   Vec3f& VEC, Vec3f& X, Vec3f& Y);
+                        Vec3f& VEC, Vec3f& X, Vec3f& Y);
 
   /// @brief Compute the closest points on two triangles given their absolute coordinate, and returns the distance between them
   /// S and T are two triangles
@@ -279,10 +319,20 @@ public:
                               const Matrix3f& R, const Vec3f& Tl,
                               Vec3f& P, Vec3f& Q);
 
+  static FCL_REAL triDistance(const Vec3f S[3], const Vec3f T[3],
+                              const Transform3f& tf,
+                              Vec3f& P, Vec3f& Q);
+
   static FCL_REAL triDistance(const Vec3f& S1, const Vec3f& S2, const Vec3f& S3,
                               const Vec3f& T1, const Vec3f& T2, const Vec3f& T3,
                               const Matrix3f& R, const Vec3f& Tl,
                               Vec3f& P, Vec3f& Q);
+
+  static FCL_REAL triDistance(const Vec3f& S1, const Vec3f& S2, const Vec3f& S3,
+                              const Vec3f& T1, const Vec3f& T2, const Vec3f& T3,
+                              const Transform3f& tf,
+                              Vec3f& P, Vec3f& Q);
+
 };
 
 
diff --git a/include/fcl/math/transform.h b/include/fcl/math/transform.h
index 5082e74d..e82c1f69 100644
--- a/include/fcl/math/transform.h
+++ b/include/fcl/math/transform.h
@@ -342,6 +342,7 @@ Transform3f inverse(const Transform3f& tf);
 void relativeTransform(const Transform3f& tf1, const Transform3f& tf2,
                        Transform3f& tf);
 
+
 }
 
 #endif
diff --git a/include/fcl/narrowphase/gjk.h b/include/fcl/narrowphase/gjk.h
index 3cebbd84..eba8c926 100644
--- a/include/fcl/narrowphase/gjk.h
+++ b/include/fcl/narrowphase/gjk.h
@@ -68,18 +68,20 @@ struct MinkowskiDiff
   {
     return getSupport(shapes[0], d);
   }
-
+  
   /// @brief support function for shape1
   inline Vec3f support1(const Vec3f& d) const
   {
     return toshape0.transform(getSupport(shapes[1], toshape1 * d));
   }
 
+  /// @brief support function for the pair of shapes
   inline Vec3f support(const Vec3f& d) const
   {
     return support0(d) - support1(-d);
   }
 
+  /// @brief support function for the d-th shape (d = 0 or 1)
   inline Vec3f support(const Vec3f& d, size_t index) const
   {
     if(index)
@@ -88,23 +90,31 @@ struct MinkowskiDiff
       return support0(d);
   }
 
-};
+  /// @brief support function for translating shape0, which is translating at velocity v
+  inline Vec3f support0(const Vec3f& d, const Vec3f& v) const
+  {
+    if(d.dot(v) <= 0)
+      return getSupport(shapes[0], d);
+    else
+      return getSupport(shapes[0], d) + v;
+  }
 
-/// @brief project origin on to a line (a, b). w[0:1] return the (0, 1) parameterization of the projected point. 
-/// m is a encode about the result case: 0x10--> project is larger than b; 0x01--> project is smaller than a;
-/// 0x11-> within the line;
-/// return value is distance between the origin and its projection.
-FCL_REAL projectOrigin(const Vec3f& a, const Vec3f& b, FCL_REAL* w, size_t& m);
+  /// @brief support function for the pair of shapes, where shape0 is translating at velocity v
+  inline Vec3f support(const Vec3f& d, const Vec3f& v) const
+  {
+    return support0(d, v) - support1(-d);
+  }
 
-/// @brief project origin on to a triangle (a, b, c). w[0:2] return the (0, 1) parameterization of the projected point. 
-/// m is a encode about the result case.
-/// return value is distance between the origin and its projection.
-FCL_REAL projectOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c, FCL_REAL* w, size_t& m);
+  /// @brief support function for the d-th shape (d = 0 or 1), where shape0 is translating at velocity v
+  inline Vec3f support(const Vec3f& d, const Vec3f& v, size_t index) const
+  {
+    if(index)
+      return support1(d);
+    else
+      return support0(d, v);
+  }
+};
 
-/// @brief project origin on to a tetrahedra (a, b, c, d). w[0:3] return the (0, 1) parameterization of the projected point. 
-/// m is a encode about the result case.
-/// return value is distance between the origin and its projection.
-FCL_REAL projectOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d, FCL_REAL* w, size_t& m);
 
 /// @brief class for GJK algorithm
 struct GJK
@@ -113,7 +123,7 @@ struct GJK
   {
     /// @brief support direction
     Vec3f d; 
-    /// @brieg support vector
+    /// @brieg support vector (i.e., the furthest point on the shape along the support direction)
     Vec3f w;
   };
 
@@ -124,7 +134,9 @@ struct GJK
     /// @brief weight 
     FCL_REAL p[4];
     /// @brief size of simplex (number of vertices)
-    size_t rank; 
+    size_t rank;
+
+    Simplex() : rank(0) {}
   };
 
   enum Status {Valid, Inside, Failed};
@@ -149,6 +161,9 @@ struct GJK
   /// @brief apply the support function along a direction, the result is return in sv
   void getSupport(const Vec3f& d, SimplexV& sv) const;
 
+  /// @brief apply the support function along a direction, the result is return is sv, here shape0 is translating at velocity v
+  void getSupport(const Vec3f& d, const Vec3f& v, SimplexV& sv) const;
+
   /// @brief discard one vertex from the simplex
   void removeVertex(Simplex& simplex);
 
@@ -158,12 +173,15 @@ struct GJK
   /// @brief whether the simplex enclose the origin
   bool encloseOrigin();
 
-  /// @brief get the underlying simplex using in GJK
+  /// @brief get the underlying simplex using in GJK, can be used for cache in next iteration
   inline Simplex* getSimplex() const
   {
     return simplex;
   }
-  
+
+  /// @brief get the guess from current simplex
+  Vec3f getGuessFromSimplex() const;
+
 private:
   SimplexV store_v[4];
   SimplexV* free_v[4];
@@ -289,7 +307,6 @@ public:
 
 
 
-
 }
 
 
diff --git a/include/fcl/narrowphase/gjk_libccd.h b/include/fcl/narrowphase/gjk_libccd.h
index a222507f..43c27c85 100644
--- a/include/fcl/narrowphase/gjk_libccd.h
+++ b/include/fcl/narrowphase/gjk_libccd.h
@@ -160,7 +160,7 @@ bool GJKCollide(void* obj1, ccd_support_fn supp1, ccd_center_fn cen1,
 bool GJKDistance(void* obj1, ccd_support_fn supp1,
                  void* obj2, ccd_support_fn supp2,
                  unsigned int max_iterations, FCL_REAL tolerance,
-                 FCL_REAL* dist);
+                 FCL_REAL* dist, Vec3f* p1, Vec3f* p2);
 
 
 } // details
diff --git a/include/fcl/narrowphase/narrowphase.h b/include/fcl/narrowphase/narrowphase.h
index 9f3862e9..0ef7245c 100644
--- a/include/fcl/narrowphase/narrowphase.h
+++ b/include/fcl/narrowphase/narrowphase.h
@@ -45,6 +45,8 @@
 namespace fcl
 {
 
+
+
 /// @brief collision and distance solver based on libccd library.
 struct GJKSolver_libccd
 {
@@ -112,7 +114,7 @@ struct GJKSolver_libccd
   template<typename S1, typename S2>
   bool shapeDistance(const S1& s1, const Transform3f& tf1,
                      const S2& s2, const Transform3f& tf2,
-                     FCL_REAL* dist) const
+                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
   {
     void* o1 = details::GJKInitializer<S1>::createGJKObject(s1, tf1);
     void* o2 = details::GJKInitializer<S2>::createGJKObject(s2, tf2);
@@ -120,7 +122,10 @@ struct GJKSolver_libccd
     bool res =  details::GJKDistance(o1, details::GJKInitializer<S1>::getSupportFunction(),
                                      o2, details::GJKInitializer<S2>::getSupportFunction(),
                                      max_distance_iterations, distance_tolerance,
-                                     dist);
+                                     dist, p1, p2);
+
+    if(p1) *p1 = inverse(tf1).transform(*p1);
+    if(p2) *p2 = inverse(tf2).transform(*p2);
 
     details::GJKInitializer<S1>::deleteGJKObject(o1);
     details::GJKInitializer<S2>::deleteGJKObject(o2);
@@ -128,12 +133,20 @@ struct GJKSolver_libccd
     return res;
   }
 
+  template<typename S1, typename S2>
+  bool shapeDistance(const S1& s1, const Transform3f& tf1,
+                     const S2& s2, const Transform3f& tf2,
+                     FCL_REAL* dist) const
+  {
+    return shapeDistance(s1, tf1, s2, tf2, dist, NULL, NULL);
+  }
+
 
   /// @brief distance computation between one shape and a triangle
   template<typename S>
   bool shapeTriangleDistance(const S& s, const Transform3f& tf,
                              const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, 
-                             FCL_REAL* dist) const
+                             FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
   {
     void* o1 = details::GJKInitializer<S>::createGJKObject(s, tf);
     void* o2 = details::triCreateGJKObject(P1, P2, P3);
@@ -141,7 +154,8 @@ struct GJKSolver_libccd
     bool res = details::GJKDistance(o1, details::GJKInitializer<S>::getSupportFunction(), 
                                     o2, details::triGetSupportFunction(),
                                     max_distance_iterations, distance_tolerance,
-                                    dist);
+                                    dist, p1, p2);
+    if(p1) *p1 = inverse(tf).transform(*p1);
   
     details::GJKInitializer<S>::deleteGJKObject(o1);
     details::triDeleteGJKObject(o2);
@@ -149,11 +163,19 @@ struct GJKSolver_libccd
     return res;
   }
 
+  template<typename S>
+  bool shapeTriangleDistance(const S& s, const Transform3f& tf,
+                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, 
+                             FCL_REAL* dist)
+  {
+    return shapeTriangleDistance(s, tf, P1, P2, P3, dist, NULL, NULL);
+  }
+  
   /// @brief distance computation between one shape and a triangle with transformation
   template<typename S>
   bool shapeTriangleDistance(const S& s, const Transform3f& tf1,
                              const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
-                             FCL_REAL* dist) const
+                             FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
   {
     void* o1 = details::GJKInitializer<S>::createGJKObject(s, tf1);
     void* o2 = details::triCreateGJKObject(P1, P2, P3, tf2);
@@ -161,7 +183,9 @@ struct GJKSolver_libccd
     bool res = details::GJKDistance(o1, details::GJKInitializer<S>::getSupportFunction(),
                                     o2, details::triGetSupportFunction(),
                                     max_distance_iterations, distance_tolerance,
-                                    dist);
+                                    dist, p1, p2);
+    if(p1) *p1 = inverse(tf1).transform(*p1);
+    if(p2) *p2 = inverse(tf2).transform(*p2);
   
     details::GJKInitializer<S>::deleteGJKObject(o1);
     details::triDeleteGJKObject(o2);
@@ -169,7 +193,14 @@ struct GJKSolver_libccd
     return res;
   }
 
-
+  template<typename S>
+  bool shapeTriangleDistance(const S& s, const Transform3f& tf1,
+                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
+                             FCL_REAL* dist) const
+  {
+    return shapeTriangleDistance(s, tf1, P1, P2, P3, tf2, dist, NULL, NULL);
+  }
+  
   /// @brief default setting for GJK algorithm
   GJKSolver_libccd()
   {
@@ -179,6 +210,23 @@ struct GJKSolver_libccd
     distance_tolerance = 1e-6;
   }
 
+
+  void enableCachedGuess(bool if_enable) const
+  {
+    // TODO: need change libccd to exploit spatial coherence
+  }
+
+  void setCachedGuess(const Vec3f& guess) const
+  {
+    // TODO: need change libccd to exploit spatial coherence
+  }
+
+  Vec3f getCachedGuess() const
+  {
+    return Vec3f(-1, 0, 0);
+  }
+
+
   /// @brief maximum number of iterations used in GJK algorithm for collision
   unsigned int max_collision_iterations;
 
@@ -198,8 +246,8 @@ struct GJKSolver_libccd
 /// @brief Fast implementation for sphere-capsule collision
 template<>
 bool GJKSolver_libccd::shapeIntersect<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
-                                                      const Capsule& s2, const Transform3f& tf2,
-                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                       const Capsule& s2, const Transform3f& tf2,
+                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 /// @brief Fast implementation for sphere-sphere collision
 template<>
@@ -306,30 +354,30 @@ bool GJKSolver_libccd::shapeTriangleIntersect(const Plane& s, const Transform3f&
 template<>
 bool GJKSolver_libccd::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
                                                       const Capsule& s2, const Transform3f& tf2,
-                                                     FCL_REAL* dist) const;
+                                                      FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 /// @brief Fast implementation for sphere-sphere distance
 template<>
 bool GJKSolver_libccd::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
                                                      const Sphere& s2, const Transform3f& tf2,
-                                                     FCL_REAL* dist) const;
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 /// @brief Fast implementation for sphere-triangle distance
 template<>
 bool GJKSolver_libccd::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf,
                                                      const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, 
-                                                     FCL_REAL* dist) const;
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 /// @brief Fast implementation for sphere-triangle distance
 template<> 
 bool GJKSolver_libccd::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf1, 
                                                      const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
-                                                     FCL_REAL* dist) const;
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 
 /// @brief collision and distance solver based on GJK algorithm implemented in fcl (rewritten the code from the GJK in bullet)
 struct GJKSolver_indep
-{
+{  
   /// @brief intersection checking between two shapes
   template<typename S1, typename S2>
   bool shapeIntersect(const S1& s1, const Transform3f& tf1,
@@ -337,6 +385,8 @@ struct GJKSolver_indep
                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
   {
     Vec3f guess(1, 0, 0);
+    if(enable_cached_guess) guess = cached_guess;
+    
     details::MinkowskiDiff shape;
     shape.shapes[0] = &s1;
     shape.shapes[1] = &s2;
@@ -345,6 +395,8 @@ struct GJKSolver_indep
   
     details::GJK gjk(gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
+    if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
+    
     switch(gjk_status)
     {
     case details::GJK::Inside:
@@ -379,8 +431,11 @@ struct GJKSolver_indep
                               const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
                               Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
   {
-    Triangle2 tri(P1, P2, P3);
+    TriangleP tri(P1, P2, P3);
+    
     Vec3f guess(1, 0, 0);
+    if(enable_cached_guess) guess = cached_guess;
+
     details::MinkowskiDiff shape;
     shape.shapes[0] = &s;
     shape.shapes[1] = &tri;
@@ -389,6 +444,8 @@ struct GJKSolver_indep
   
     details::GJK gjk(gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
+    if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
+
     switch(gjk_status)
     {
     case details::GJK::Inside:
@@ -423,8 +480,11 @@ struct GJKSolver_indep
                               const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
                               Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
   {
-    Triangle2 tri(P1, P2, P3);
+    TriangleP tri(P1, P2, P3);
+
     Vec3f guess(1, 0, 0);
+    if(enable_cached_guess) guess = cached_guess;
+
     details::MinkowskiDiff shape;
     shape.shapes[0] = &s;
     shape.shapes[1] = &tri;
@@ -433,6 +493,8 @@ struct GJKSolver_indep
   
     details::GJK gjk(gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
+    if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
+
     switch(gjk_status)
     {
     case details::GJK::Inside:
@@ -465,9 +527,11 @@ struct GJKSolver_indep
   template<typename S1, typename S2>
   bool shapeDistance(const S1& s1, const Transform3f& tf1,
                      const S2& s2, const Transform3f& tf2,
-                     FCL_REAL* distance) const
+                     FCL_REAL* distance, Vec3f* p1, Vec3f* p2) const
   {
     Vec3f guess(1, 0, 0);
+    if(enable_cached_guess) guess = cached_guess;
+
     details::MinkowskiDiff shape;
     shape.shapes[0] = &s1;
     shape.shapes[1] = &s2;
@@ -476,6 +540,8 @@ struct GJKSolver_indep
 
     details::GJK gjk(gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
+    if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
+
     if(gjk_status == details::GJK::Valid)
     {
       Vec3f w0, w1;
@@ -486,24 +552,38 @@ struct GJKSolver_indep
         w1 += shape.support(-gjk.getSimplex()->c[i]->d, 1) * p;
       }
 
-      *distance = (w0 - w1).length();
+      if(distance) *distance = (w0 - w1).length();
+      
+      if(p1) *p1 = w0;
+      if(p2) *p2 = shape.toshape0.transform(w1);
+      
       return true;
     }
     else
     {
-      *distance = -1;
+      if(distance) *distance = -1;
       return false;
     }
   }
 
+  template<typename S1, typename S2>
+  bool shapeDistance(const S1& s1, const Transform3f& tf1,
+                     const S2& s2, const Transform3f& tf2,
+                     FCL_REAL* distance) const
+  {
+    return shapeDistance(s1, tf1, s2, tf2, distance, NULL, NULL);
+  }
+
   /// @brief distance computation between one shape and a triangle
   template<typename S>
   bool shapeTriangleDistance(const S& s, const Transform3f& tf,
                              const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
-                             FCL_REAL* distance) const
+                             FCL_REAL* distance, Vec3f* p1, Vec3f* p2) const
   {
-    Triangle2 tri(P1, P2, P3);
+    TriangleP tri(P1, P2, P3);
     Vec3f guess(1, 0, 0);
+    if(enable_cached_guess) guess = cached_guess;
+
     details::MinkowskiDiff shape;
     shape.shapes[0] = &s;
     shape.shapes[1] = &tri;
@@ -512,6 +592,8 @@ struct GJKSolver_indep
 
     details::GJK gjk(gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
+    if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
+    
     if(gjk_status == details::GJK::Valid)
     {
       Vec3f w0, w1;
@@ -522,24 +604,36 @@ struct GJKSolver_indep
         w1 += shape.support(-gjk.getSimplex()->c[i]->d, 1) * p;
       }
 
-      *distance = (w0 - w1).length();
+      if(distance) *distance = (w0 - w1).length();
+      if(p1) *p1 = w0;
+      if(p2) *p2 = shape.toshape0.transform(w1);
       return true;
     }
     else
     {
-      *distance = -1;
+      if(distance) *distance = -1;
       return false;
     }
   }
 
+  template<typename S>
+  bool shapeTriangleDistance(const S& s, const Transform3f& tf,
+                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
+                             FCL_REAL* distance) const
+  {
+    return shapeTriangleDistance(s, tf, P1, P2, P3, distance, NULL, NULL);
+  }
+  
   /// @brief distance computation between one shape and a triangle with transformation
   template<typename S>
   bool shapeTriangleDistance(const S& s, const Transform3f& tf1,
                              const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
-                             FCL_REAL* distance) const
+                             FCL_REAL* distance, Vec3f* p1, Vec3f* p2) const
   {
-    Triangle2 tri(P1, P2, P3);
+    TriangleP tri(P1, P2, P3);
     Vec3f guess(1, 0, 0);
+    if(enable_cached_guess) guess = cached_guess;
+    
     details::MinkowskiDiff shape;
     shape.shapes[0] = &s;
     shape.shapes[1] = &tri;
@@ -548,6 +642,8 @@ struct GJKSolver_indep
 
     details::GJK gjk(gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
+    if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
+
     if(gjk_status == details::GJK::Valid)
     {
       Vec3f w0, w1;
@@ -558,16 +654,26 @@ struct GJKSolver_indep
         w1 += shape.support(-gjk.getSimplex()->c[i]->d, 1) * p;
       }
 
-      *distance = (w0 - w1).length();
+      if(distance) *distance = (w0 - w1).length();
+      if(p1) *p1 = w0;
+      if(p2) *p2 = shape.toshape0.transform(w1);
       return true;
     }
     else
     {
-      *distance = -1;
+      if(distance) *distance = -1;
       return false;
     }
   }
 
+  template<typename S>
+  bool shapeTriangleDistance(const S& s, const Transform3f& tf1,
+                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
+                             FCL_REAL* distance) const
+  {
+    return shapeTriangleDistance(s, tf1, P1, P2, P3, tf2, distance, NULL, NULL);
+  }
+  
   /// @brief default setting for GJK algorithm
   GJKSolver_indep()
   {
@@ -577,6 +683,23 @@ struct GJKSolver_indep
     epa_max_vertex_num = 64;
     epa_max_iterations = 255;
     epa_tolerance = 1e-6;
+    enable_cached_guess = false;
+    cached_guess = Vec3f(1, 0, 0);
+  }
+
+  void enableCachedGuess(bool if_enable) const
+  {
+    enable_cached_guess = if_enable;
+  }
+
+  void setCachedGuess(const Vec3f& guess) const
+  {
+    cached_guess = guess;
+  }
+
+  Vec3f getCachedGuess() const
+  {
+    return cached_guess;
   }
 
   /// @brief maximum number of simplex face used in EPA algorithm
@@ -596,12 +719,18 @@ struct GJKSolver_indep
 
   /// @brief maximum number of iterations used for GJK iterations
   FCL_REAL gjk_max_iterations;
+
+  /// @brief Whether smart guess can be provided
+  mutable bool enable_cached_guess;
+
+  /// @brief smart guess
+  mutable Vec3f cached_guess;
 };
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1,
-                                                       const Capsule &s2, const Transform3f& tf2,
-                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                      const Capsule &s2, const Transform3f& tf2,
+                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 /// @brief Fast implementation for sphere-sphere collision                                            
 template<>
@@ -617,73 +746,73 @@ bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f&
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace>(const Sphere& s1, const Transform3f& tf1,
-                                                         const Halfspace& s2, const Transform3f& tf2,
-                                                         Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                        const Halfspace& s2, const Transform3f& tf2,
+                                                        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Box, Halfspace>(const Box& s1, const Transform3f& tf1,
-                                                      const Halfspace& s2, const Transform3f& tf2,
-                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                     const Halfspace& s2, const Transform3f& tf2,
+                                                     Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Capsule, Halfspace>(const Capsule& s1, const Transform3f& tf1,
-                                                          const Halfspace& s2, const Transform3f& tf2,
-                                                          Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                         const Halfspace& s2, const Transform3f& tf2,
+                                                         Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Cylinder, Halfspace>(const Cylinder& s1, const Transform3f& tf1,
-                                                           const Halfspace& s2, const Transform3f& tf2,
-                                                           Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                          const Halfspace& s2, const Transform3f& tf2,
+                                                          Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Cone, Halfspace>(const Cone& s1, const Transform3f& tf1,
-                                                       const Halfspace& s2, const Transform3f& tf2,
-                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                      const Halfspace& s2, const Transform3f& tf2,
+                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, const Transform3f& tf1,
-                                                            const Halfspace& s2, const Transform3f& tf2,
-                                                            Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                           const Halfspace& s2, const Transform3f& tf2,
+                                                           Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1,
-                                                        const Halfspace& s2, const Transform3f& tf2,
-                                                        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                       const Halfspace& s2, const Transform3f& tf2,
+                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Sphere, Plane>(const Sphere& s1, const Transform3f& tf1,
-                                                     const Plane& s2, const Transform3f& tf2,
-                                                     Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                    const Plane& s2, const Transform3f& tf2,
+                                                    Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Box, Plane>(const Box& s1, const Transform3f& tf1,
-                                                  const Plane& s2, const Transform3f& tf2,
-                                                  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                 const Plane& s2, const Transform3f& tf2,
+                                                 Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Capsule, Plane>(const Capsule& s1, const Transform3f& tf1,
-                                                      const Plane& s2, const Transform3f& tf2,
-                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                     const Plane& s2, const Transform3f& tf2,
+                                                     Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Cylinder, Plane>(const Cylinder& s1, const Transform3f& tf1,
-                                                       const Plane& s2, const Transform3f& tf2,
-                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                      const Plane& s2, const Transform3f& tf2,
+                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Cone, Plane>(const Cone& s1, const Transform3f& tf1,
-                                                   const Plane& s2, const Transform3f& tf2,
-                                                   Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                  const Plane& s2, const Transform3f& tf2,
+                                                  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1,
-                                                        const Plane& s2, const Transform3f& tf2,
-                                                        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                       const Plane& s2, const Transform3f& tf2,
+                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Plane, Plane>(const Plane& s1, const Transform3f& tf1,
-                                                    const Plane& s2, const Transform3f& tf2,
-                                                    Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                                   const Plane& s2, const Transform3f& tf2,
+                                                   Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 /// @brief Fast implementation for sphere-triangle collision
 template<> 
@@ -697,35 +826,35 @@ bool GJKSolver_indep::shapeTriangleIntersect(const Sphere& s, const Transform3f&
 
 template<>
 bool GJKSolver_indep::shapeTriangleIntersect(const Halfspace& s, const Transform3f& tf1,
-                                              const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 template<>
 bool GJKSolver_indep::shapeTriangleIntersect(const Plane& s, const Transform3f& tf1,
-                                              const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
+                                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
 
 template<>
 bool GJKSolver_indep::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
-                                                    const Capsule& s2, const Transform3f& tf2,
-                                                    FCL_REAL* dist) const;
+                                                     const Capsule& s2, const Transform3f& tf2,
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 /// @brief Fast implementation for sphere-sphere distance
 template<>
 bool GJKSolver_indep::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
                                                     const Sphere& s2, const Transform3f& tf2,
-                                                    FCL_REAL* dist) const;
+                                                    FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 /// @brief Fast implementation for sphere-triangle distance
 template<>
 bool GJKSolver_indep::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf,
                                                     const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, 
-                                                    FCL_REAL* dist) const;
+                                                    FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 /// @brief Fast implementation for sphere-triangle distance
 template<> 
 bool GJKSolver_indep::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf1, 
                                                     const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
-                                                    FCL_REAL* dist) const;
+                                                    FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const;
 
 
 }
diff --git a/include/fcl/penetration_depth.h b/include/fcl/penetration_depth.h
new file mode 100644
index 00000000..97ccff5c
--- /dev/null
+++ b/include/fcl/penetration_depth.h
@@ -0,0 +1,24 @@
+#ifndef FCL_PENETRATION_DEPTH_H
+#define FCL_PENETRATION_DEPTH_H
+
+#include "fcl/math/vec_3f.h"
+#include "fcl/collision_object.h"
+#include "fcl/collision_data.h"
+
+namespace fcl
+{
+
+/// @brief penetration depth computation between two in-collision objects
+FCL_REAL penetration_depth(const CollisionGeometry* o1, const Transform3f& tf1,
+                           const CollisionGeometry* o2, const Transform3f& tf2,
+                           const PenetrationDepthRequest& request,
+                           PenetrationDepthResult& result);
+
+FCL_REAL penetration_depth(const CollisionObject* o1,
+                           const CollisionObject* o2,
+                           const PenetrationDepthRequest& request,
+                           PenetrationDepthResult& result);
+
+}
+
+#endif
diff --git a/include/fcl/shape/geometric_shapes.h b/include/fcl/shape/geometric_shapes.h
index 5c64ae4c..818833ff 100644
--- a/include/fcl/shape/geometric_shapes.h
+++ b/include/fcl/shape/geometric_shapes.h
@@ -56,10 +56,10 @@ public:
 };
 
 /// @brief Triangle stores the points instead of only indices of points
-class Triangle2 : public ShapeBase
+class TriangleP : public ShapeBase
 {
 public:
-  Triangle2(const Vec3f& a_, const Vec3f& b_, const Vec3f& c_) : ShapeBase(), a(a_), b(b_), c(c_)
+  TriangleP(const Vec3f& a_, const Vec3f& b_, const Vec3f& c_) : ShapeBase(), a(a_), b(b_), c(c_)
   {
   }
 
diff --git a/include/fcl/shape/geometric_shapes_utility.h b/include/fcl/shape/geometric_shapes_utility.h
index 15acae9f..3497239f 100644
--- a/include/fcl/shape/geometric_shapes_utility.h
+++ b/include/fcl/shape/geometric_shapes_utility.h
@@ -55,7 +55,7 @@ std::vector<Vec3f> getBoundVertices(const Capsule& capsule, const Transform3f& t
 std::vector<Vec3f> getBoundVertices(const Cone& cone, const Transform3f& tf);
 std::vector<Vec3f> getBoundVertices(const Cylinder& cylinder, const Transform3f& tf);
 std::vector<Vec3f> getBoundVertices(const Convex& convex, const Transform3f& tf);
-std::vector<Vec3f> getBoundVertices(const Triangle2& triangle, const Transform3f& tf);
+std::vector<Vec3f> getBoundVertices(const TriangleP& triangle, const Transform3f& tf);
 } 
 /// @endcond
 
@@ -87,7 +87,7 @@ template<>
 void computeBV<AABB, Convex>(const Convex& s, const Transform3f& tf, AABB& bv);
 
 template<>
-void computeBV<AABB, Triangle2>(const Triangle2& s, const Transform3f& tf, AABB& bv);
+void computeBV<AABB, TriangleP>(const TriangleP& s, const Transform3f& tf, AABB& bv);
 
 template<>
 void computeBV<AABB, Halfspace>(const Halfspace& s, const Transform3f& tf, AABB& bv);
diff --git a/include/fcl/traversal/traversal_node_base.h b/include/fcl/traversal/traversal_node_base.h
index c61ba68f..a53c2b24 100644
--- a/include/fcl/traversal/traversal_node_base.h
+++ b/include/fcl/traversal/traversal_node_base.h
@@ -145,6 +145,20 @@ public:
   bool enable_statistics;
 };
 
+
+struct ConservativeAdvancementStackData
+{
+  ConservativeAdvancementStackData(const Vec3f& P1_, const Vec3f& P2_, int c1_, int c2_, FCL_REAL d_)
+    : P1(P1_), P2(P2_), c1(c1_), c2(c2_), d(d_) {}
+
+  Vec3f P1;
+  Vec3f P2;
+  int c1;
+  int c2;
+  FCL_REAL d;
+};
+
+
 }
 
 #endif
diff --git a/include/fcl/traversal/traversal_node_bvh_shape.h b/include/fcl/traversal/traversal_node_bvh_shape.h
index 52394030..fe62b289 100644
--- a/include/fcl/traversal/traversal_node_bvh_shape.h
+++ b/include/fcl/traversal/traversal_node_bvh_shape.h
@@ -732,9 +732,10 @@ public:
     const Vec3f& p3 = vertices[tri_id[2]];
     
     FCL_REAL d;
-    nsolver->shapeTriangleDistance(*(this->model2), this->tf2, p1, p2, p3, &d);
+    Vec3f closest_p1, closest_p2;
+    nsolver->shapeTriangleDistance(*(this->model2), this->tf2, p1, p2, p3, &d, &closest_p2, &closest_p1);
 
-    this->result->update(d, this->model1, this->model2, primitive_id, DistanceResult::NONE);
+    this->result->update(d, this->model1, this->model2, primitive_id, DistanceResult::NONE, closest_p1, closest_p2);
   }
 
   /// @brief Whether the traversal process can stop early
@@ -781,9 +782,10 @@ void meshShapeDistanceOrientedNodeLeafTesting(int b1, int /* b2 */,
   const Vec3f& p3 = vertices[tri_id[2]];
     
   FCL_REAL distance;
-  nsolver->shapeTriangleDistance(model2, tf2, p1, p2, p3, tf1, &distance);
+  Vec3f closest_p1, closest_p2;
+  nsolver->shapeTriangleDistance(model2, tf2, p1, p2, p3, tf1, &distance, &closest_p2, &closest_p1);
 
-  result.update(distance, model1, &model2, primitive_id, DistanceResult::NONE);
+  result.update(distance, model1, &model2, primitive_id, DistanceResult::NONE, closest_p1, closest_p2);
 }
 
 
@@ -802,9 +804,10 @@ static inline void distancePreprocessOrientedNode(const BVHModel<BV>* model1,
   const Vec3f& p3 = vertices[init_tri[2]];
   
   FCL_REAL distance;
-  nsolver->shapeTriangleDistance(model2, tf2, p1, p2, p3, tf1, &distance);
+  Vec3f closest_p1, closest_p2;
+  nsolver->shapeTriangleDistance(model2, tf2, p1, p2, p3, tf1, &distance, &closest_p2, &closest_p1);
 
-  result.update(distance, model1, &model2, init_tri_id, DistanceResult::NONE);
+  result.update(distance, model1, &model2, init_tri_id, DistanceResult::NONE, closest_p1, closest_p2);
 }
 
 
@@ -944,9 +947,10 @@ public:
     const Vec3f& p3 = vertices[tri_id[2]];
     
     FCL_REAL distance;
-    nsolver->shapeTriangleDistance(*(this->model1), this->tf1, p1, p2, p3, &distance);
+    Vec3f closest_p1, closest_p2;
+    nsolver->shapeTriangleDistance(*(this->model1), this->tf1, p1, p2, p3, &distance, &closest_p1, &closest_p2);
 
-    this->result->update(distance, this->model1, this->model2, DistanceResult::NONE, primitive_id);
+    this->result->update(distance, this->model1, this->model2, DistanceResult::NONE, primitive_id, closest_p1, closest_p2);
   }
 
   /// @brief Whether the traversal process can stop early
@@ -1061,6 +1065,567 @@ public:
   }
   
 };
+
+
+/// @brief Traversal node for conservative advancement computation between BVH and shape
+template<typename BV, typename S, typename NarrowPhaseSolver>
+class MeshShapeConservativeAdvancementTraversalNode : public MeshShapeDistanceTraversalNode<BV, S, NarrowPhaseSolver>
+{
+public:
+  MeshShapeConservativeAdvancementTraversalNode(FCL_REAL w_ = 1) : MeshShapeDistanceTraversalNode<BV, S, NarrowPhaseSolver>()
+  {
+    delta_t = 1;
+    toc = 0;
+    t_err = (FCL_REAL)0.0001;
+
+    w = w_;
+
+    motion1 = NULL;
+    motion2 = NULL;
+  }
+
+  /// @brief BV culling test in one BVTT node
+  FCL_REAL BVTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_bv_tests++;
+    Vec3f P1, P2;
+    FCL_REAL d = this->model2_bv.distance(this->model1->getBV(b1).bv, &P2, &P1);
+
+    stack.push_back(ConservativeAdvancementStackData(P1, P2, b1, b2, d));
+    
+    return d;
+  }
+
+  /// @brief Conservative advancement testing between leaves (one triangle and one shape)
+  void leafTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_leaf_tests++;
+
+    const BVNode<BV>& node = this->model1->getBV(b1);
+
+    int primitive_id = node.primitiveId();
+
+    const Triangle& tri_id = this->tri_indices[primitive_id];
+
+    const Vec3f& p1 = this->vertices[tri_id[0]];
+    const Vec3f& p2 = this->vertices[tri_id[1]];
+    const Vec3f& p3 = this->vertices[tri_id[2]];
+
+    FCL_REAL d;
+    Vec3f P1, P2;
+    this->nsolver->shapeTriangleDistance(*(this->model2), this->tf2, p1, p2, p3, &d, &P2, &P1);
+
+    if(d < this->min_distance)
+    {
+      this->min_distance = d;
+
+      closest_p1 = P1;
+      closest_p2 = P2;
+      
+      last_tri_id = primitive_id;
+    }
+
+    Vec3f n = this->tf2.transform(P2) - P1; n.normalize();
+    // here n should be in global frame
+    TriangleMotionBoundVisitor mb_visitor1(p1, p2, p3, n);
+    TBVMotionBoundVisitor<BV> mb_visitor2(this->model2_bv, -n);
+    FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+    FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+    FCL_REAL bound = bound1 + bound2;
+
+    FCL_REAL cur_delta_t;
+    if(bound <= d) cur_delta_t = 1;
+    else cur_delta_t = d / bound;
+
+    if(cur_delta_t < delta_t)
+      delta_t = cur_delta_t;
+  }
+
+  /// @brief Whether the traversal process can stop early
+  bool canStop(FCL_REAL c) const
+  {
+    if((c >= w * (this->min_distance - this->abs_err)) && (c * (1 + this->rel_err) >= w * this->min_distance))
+    {
+      const ConservativeAdvancementStackData& data = stack.back();
+
+      Vec3f n = this->tf2.transform(data.P2) - data.P1; n.normalize();
+      int c1 = data.c1;
+
+      TBVMotionBoundVisitor<BV> mb_visitor1(this->model1->getBV(c1).bv, n);
+      TBVMotionBoundVisitor<BV> mb_visitor2(this->model2_bv, -n);
+      FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+      FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+      FCL_REAL bound = bound1 + bound2;
+
+      FCL_REAL cur_delta_t;
+      if(bound < c) cur_delta_t = 1;
+      else cur_delta_t = c / bound;
+
+      if(cur_delta_t < delta_t)
+        delta_t = cur_delta_t;
+
+      stack.pop_back();
+
+      return true;
+    }
+    else
+    {
+      stack.pop_back();
+
+      return false;
+    }
+  }
+
+  mutable FCL_REAL min_distance;
+
+  mutable Vec3f closest_p1, closest_p2;
+
+  mutable int last_tri_id;
+  
+  /// @brief CA controlling variable: early stop for the early iterations of CA
+  FCL_REAL w;
+
+  /// @brief The time from beginning point
+  FCL_REAL toc;
+  FCL_REAL t_err;
+
+  /// @brief The delta_t each step
+  mutable FCL_REAL delta_t;
+
+  /// @brief Motions for the two objects in query
+  const MotionBase* motion1;
+  const MotionBase* motion2;
+
+  mutable std::vector<ConservativeAdvancementStackData> stack;
+};
+
+
+template<typename S, typename BV, typename NarrowPhaseSolver>
+class ShapeMeshConservativeAdvancementTraversalNode : public ShapeMeshDistanceTraversalNode<S, BV, NarrowPhaseSolver>
+{
+public:
+  ShapeMeshConservativeAdvancementTraversalNode(FCL_REAL w_ = 1) : ShapeMeshDistanceTraversalNode<S, BV, NarrowPhaseSolver>()
+  {
+    delta_t = 1;
+    toc = 0;
+    t_err = (FCL_REAL)0.0001;
+
+    w = w_;
+
+    motion1 = NULL;
+    motion2 = NULL;
+  }
+
+  /// @brief BV culling test in one BVTT node
+  FCL_REAL BVTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_bv_tests++;
+    Vec3f P1, P2;
+    FCL_REAL d = this->model1_bv.distance(this->model2->getBV(b2).bv, &P1, &P2);
+
+    stack.push_back(ConservativeAdvancementStackData(P1, P2, b1, b2, d));
+
+    return d;
+  }
+
+  /// @brief Conservative advancement testing between leaves (one triangle and one shape)
+  void leafTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_leaf_tests++;
+
+    const BVNode<BV>& node = this->model2->getBV(b2);
+
+    int primitive_id = node.primitiveId();
+
+    const Triangle& tri_id = this->tri_indices[primitive_id];
+ 
+    const Vec3f& p1 = this->vertices[tri_id[0]];
+    const Vec3f& p2 = this->vertices[tri_id[1]];
+    const Vec3f& p3 = this->vertices[tri_id[2]];
+
+    FCL_REAL d;
+    Vec3f P1, P2;
+    this->nsolver->shapeTriangleDistance(*(this->model1), this->tf1, p1, p2, p3, &d, &P1, &P2);
+
+    if(d < this->min_distance)
+    {
+      this->min_distance = d;
+
+      closest_p1 = P1;
+      closest_p2 = P2;
+
+      last_tri_id = primitive_id;
+    }
+
+    Vec3f n = P2 - this->tf1.transform(P1); n.normalize();
+    // here n should be in global frame
+    TBVMotionBoundVisitor<BV> mb_visitor1(this->model1_bv, n);
+    TriangleMotionBoundVisitor mb_visitor2(p1, p2, p3, -n);
+    FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+    FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+    FCL_REAL bound = bound1 + bound2;
+
+    FCL_REAL cur_delta_t;
+    if(bound <= d) cur_delta_t = 1;
+    else cur_delta_t = d / bound;
+
+    if(cur_delta_t < delta_t)
+      delta_t = cur_delta_t;
+  }
+
+  /// @brief Whether the traversal process can stop early
+  bool canStop(FCL_REAL c) const
+  {
+    if((c >= w * (this->min_distance - this->abs_err)) && (c * (1 + this->rel_err) >= w * this->min_distance))
+    {
+      const ConservativeAdvancementStackData& data = stack.back();
+
+      Vec3f n = data.P2 - this->tf1.transform(data.P1); n.normalize();
+      int c2 = data.c2;
+
+      TBVMotionBoundVisitor<BV> mb_visitor1(this->model1_bv, n);
+      TBVMotionBoundVisitor<BV> mb_visitor2(this->model2->getBV(c2).bv, -n);
+      FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+      FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+      FCL_REAL bound = bound1 + bound2;
+
+      FCL_REAL cur_delta_t;
+      if(bound < c) cur_delta_t = 1;
+      else cur_delta_t = c / bound;
+
+      if(cur_delta_t < delta_t)
+        delta_t = cur_delta_t;
+
+      stack.pop_back();
+
+      return true;
+    }
+    else
+    {
+      stack.pop_back();
+
+      return false;
+    }
+  }
+
+  mutable FCL_REAL min_distance;
+
+  mutable Vec3f closest_p1, closest_p2;
+
+  mutable int last_tri_id;
+  
+   /// @brief CA controlling variable: early stop for the early iterations of CA
+  FCL_REAL w;
+
+  /// @brief The time from beginning point
+  FCL_REAL toc;
+  FCL_REAL t_err;
+
+  /// @brief The delta_t each step
+  mutable FCL_REAL delta_t;
+
+  /// @brief Motions for the two objects in query
+  const MotionBase* motion1;
+  const MotionBase* motion2;
+
+  mutable std::vector<ConservativeAdvancementStackData> stack;  
+};
+
+namespace details
+{
+template<typename BV, typename S, typename NarrowPhaseSolver>
+void meshShapeConservativeAdvancementOrientedNodeLeafTesting(int b1, int /* b2 */,
+                                                             const BVHModel<BV>* model1, const S& model2,
+                                                             const BV& model2_bv,
+                                                             Vec3f* vertices, Triangle* tri_indices,
+                                                             const Transform3f& tf1,
+                                                             const Transform3f& tf2,
+                                                             const MotionBase* motion1, const MotionBase* motion2,
+                                                             const NarrowPhaseSolver* nsolver,
+                                                             bool enable_statistics,
+                                                             FCL_REAL& min_distance,
+                                                             Vec3f& p1, Vec3f& p2,
+                                                             int& last_tri_id,
+                                                             FCL_REAL& delta_t,
+                                                             int& num_leaf_tests)
+{
+  if(enable_statistics) num_leaf_tests++;
+
+  const BVNode<BV>& node = model1->getBV(b1);
+  int primitive_id = node.primitiveId();
+
+  const Triangle& tri_id = tri_indices[primitive_id];
+  const Vec3f& t1 = vertices[tri_id[0]];
+  const Vec3f& t2 = vertices[tri_id[1]];
+  const Vec3f& t3 = vertices[tri_id[2]];
+    
+  FCL_REAL distance;
+  Vec3f P1, P2;
+  nsolver->shapeTriangleDistance(model2, tf2, t1, t2, t3, tf1, &distance, &P2, &P1);
+
+  if(distance < min_distance)
+  {
+    min_distance = distance;
+    
+    p1 = P1;
+    p2 = P2;
+
+    last_tri_id = primitive_id;
+  }
+
+  // n is in global frame
+  Vec3f n = P2 - P1; n.normalize();
+
+  TriangleMotionBoundVisitor mb_visitor1(t1, t2, t3, n);
+  TBVMotionBoundVisitor<BV> mb_visitor2(model2_bv, -n);
+  FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+  FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+  FCL_REAL bound = bound1 + bound2;
+  
+  FCL_REAL cur_delta_t;
+  if(bound <= distance) cur_delta_t = 1;
+  else cur_delta_t = distance / bound;
+
+  if(cur_delta_t < delta_t)
+    delta_t = cur_delta_t;  
+}
+
+
+template<typename BV, typename S>
+bool meshShapeConservativeAdvancementOrientedNodeCanStop(FCL_REAL c,
+                                                         FCL_REAL min_distance,
+                                                         FCL_REAL abs_err, FCL_REAL rel_err, FCL_REAL w,
+                                                         const BVHModel<BV>* model1, const S& model2,
+                                                         const BV& model2_bv,
+                                                         const MotionBase* motion1, const MotionBase* motion2,
+                                                         std::vector<ConservativeAdvancementStackData>& stack,
+                                                         FCL_REAL& delta_t)
+{
+  if((c >= w * (min_distance - abs_err)) && (c * (1 + rel_err) >= w * min_distance))
+  {
+    const ConservativeAdvancementStackData& data = stack.back();
+    Vec3f n = data.P2 - data.P1; n.normalize();
+    int c1 = data.c1;
+
+    TBVMotionBoundVisitor<BV> mb_visitor1(model1->getBV(c1).bv, n);
+    TBVMotionBoundVisitor<BV> mb_visitor2(model2_bv, -n);
+
+    FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+    FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+    FCL_REAL bound = bound1 + bound2;
+
+    FCL_REAL cur_delta_t;
+    if(bound <= c) cur_delta_t = 1;
+    else cur_delta_t = c / bound;
+
+    if(cur_delta_t < delta_t)
+      delta_t = cur_delta_t;
+
+    stack.pop_back();
+
+    return true;
+  }
+  else
+  {
+    stack.pop_back();
+    return false;
+  }
+}
+
+
+}
+
+template<typename S, typename NarrowPhaseSolver>
+class MeshShapeConservativeAdvancementTraversalNodeRSS : public MeshShapeConservativeAdvancementTraversalNode<RSS, S, NarrowPhaseSolver>
+{
+public:
+  MeshShapeConservativeAdvancementTraversalNodeRSS(FCL_REAL w_ = 1) : MeshShapeConservativeAdvancementTraversalNode<RSS, S, NarrowPhaseSolver>(w_)
+  {
+  }
+
+  FCL_REAL BVTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_bv_tests++;
+    Vec3f P1, P2;
+    FCL_REAL d = distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model1->getBV(b1).bv, this->model2_bv, &P1, &P2);
+
+    this->stack.push_back(ConservativeAdvancementStackData(P1, P2, b1, b2, d));
+
+    return d;
+  }
+
+  void leafTesting(int b1, int b2) const
+  {
+    details::meshShapeConservativeAdvancementOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2),
+                                                                     this->model2_bv,
+                                                                     this->vertices, this->tri_indices,
+                                                                     this->tf1, this->tf2,
+                                                                     this->motion1, this->motion2,
+                                                                     this->nsolver,
+                                                                     this->enable_statistics,
+                                                                     this->min_distance,
+                                                                     this->closest_p1, this->closest_p2,
+                                                                     this->last_tri_id,
+                                                                     this->delta_t,
+                                                                     this->num_leaf_tests);
+  }
+
+  bool canStop(FCL_REAL c) const
+  {
+    return details::meshShapeConservativeAdvancementOrientedNodeCanStop(c, this->min_distance,
+                                                                        this->abs_err, this->rel_err, this->w,
+                                                                        this->model1, *(this->model2), this->model2_bv,
+                                                                        this->motion1, this->motion2,
+                                                                        this->stack, this->delta_t);
+  }
+};
+
+
+template<typename S, typename NarrowPhaseSolver>
+class MeshShapeConservativeAdvancementTraversalNodeOBBRSS : public MeshShapeConservativeAdvancementTraversalNode<OBBRSS, S, NarrowPhaseSolver>
+{
+public:
+  MeshShapeConservativeAdvancementTraversalNodeOBBRSS(FCL_REAL w_ = 1) : MeshShapeConservativeAdvancementTraversalNode<OBBRSS, S, NarrowPhaseSolver>(w_)
+  {
+  }
+
+  FCL_REAL BVTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_bv_tests++;
+    Vec3f P1, P2;
+    FCL_REAL d = distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model1->getBV(b1).bv, this->model2_bv, &P1, &P2);
+
+    this->stack.push_back(ConservativeAdvancementStackData(P1, P2, b1, b2, d));
+
+    return d;
+  }
+
+  void leafTesting(int b1, int b2) const
+  {
+    details::meshShapeConservativeAdvancementOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2),
+                                                                     this->model2_bv,
+                                                                     this->vertices, this->tri_indices,
+                                                                     this->tf1, this->tf2,
+                                                                     this->motion1, this->motion2,
+                                                                     this->nsolver,
+                                                                     this->enable_statistics,
+                                                                     this->min_distance,
+                                                                     this->closest_p1, this->closest_p2,
+                                                                     this->last_tri_id,
+                                                                     this->delta_t,
+                                                                     this->num_leaf_tests);
+  }
+
+  bool canStop(FCL_REAL c) const
+  {
+    return details::meshShapeConservativeAdvancementOrientedNodeCanStop(c, this->min_distance,
+                                                                        this->abs_err, this->rel_err, this->w,
+                                                                        this->model1, *(this->model2), this->model2_bv,
+                                                                        this->motion1, this->motion2,
+                                                                        this->stack, this->delta_t);
+  }
+};
+
+
+
+template<typename S, typename NarrowPhaseSolver>
+class ShapeMeshConservativeAdvancementTraversalNodeRSS : public ShapeMeshConservativeAdvancementTraversalNode<S, RSS, NarrowPhaseSolver>
+{
+public:
+  ShapeMeshConservativeAdvancementTraversalNodeRSS(FCL_REAL w_ = 1) : ShapeMeshConservativeAdvancementTraversalNode<S, RSS, NarrowPhaseSolver>(w_)
+  {
+  }
+
+  FCL_REAL BVTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_bv_tests++;
+    Vec3f P1, P2;
+    FCL_REAL d = distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model2->getBV(b2).bv, this->model1_bv, &P2, &P1);
+
+    this->stack.push_back(ConservativeAdvancementStackData(P1, P2, b1, b2, d));
+
+    return d;
+  }
+
+  void leafTesting(int b1, int b2) const
+  {
+    details::meshShapeConservativeAdvancementOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1),
+                                                                     this->model1_bv,
+                                                                     this->vertices, this->tri_indices,
+                                                                     this->tf2, this->tf1,
+                                                                     this->motion2, this->motion1,
+                                                                     this->nsolver,
+                                                                     this->enable_statistics,
+                                                                     this->min_distance,
+                                                                     this->closest_p2, this->closest_p1,
+                                                                     this->last_tri_id,
+                                                                     this->delta_t,
+                                                                     this->num_leaf_tests);
+  }
+
+  bool canStop(FCL_REAL c) const
+  {
+    return details::meshShapeConservativeAdvancementOrientedNodeCanStop(c, this->min_distance,
+                                                                        this->abs_err, this->rel_err, this->w,
+                                                                        this->model2, *(this->model1), this->model1_bv,
+                                                                        this->motion2, this->motion1,
+                                                                        this->stack, this->delta_t);
+  }
+};
+
+
+template<typename S, typename NarrowPhaseSolver>
+class ShapeMeshConservativeAdvancementTraversalNodeOBBRSS : public ShapeMeshConservativeAdvancementTraversalNode<S, OBBRSS, NarrowPhaseSolver>
+{
+public:
+  ShapeMeshConservativeAdvancementTraversalNodeOBBRSS(FCL_REAL w_ = 1) : ShapeMeshConservativeAdvancementTraversalNode<S, OBBRSS, NarrowPhaseSolver>(w_)
+  {
+  }
+
+  FCL_REAL BVTesting(int b1, int b2) const
+  {
+    if(this->enable_statistics) this->num_bv_tests++;
+    Vec3f P1, P2;
+    FCL_REAL d = distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model2->getBV(b2).bv, this->model1_bv, &P2, &P1);
+
+    this->stack.push_back(ConservativeAdvancementStackData(P1, P2, b1, b2, d));
+
+    return d;
+  }
+
+  void leafTesting(int b1, int b2) const
+  {
+    details::meshShapeConservativeAdvancementOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1),
+                                                                     this->model1_bv,
+                                                                     this->vertices, this->tri_indices,
+                                                                     this->tf2, this->tf1,
+                                                                     this->motion2, this->motion1,
+                                                                     this->nsolver,
+                                                                     this->enable_statistics,
+                                                                     this->min_distance,
+                                                                     this->closest_p2, this->closest_p1,
+                                                                     this->last_tri_id,
+                                                                     this->delta_t,
+                                                                     this->num_leaf_tests);
+  }
+
+  bool canStop(FCL_REAL c) const
+  {
+    return details::meshShapeConservativeAdvancementOrientedNodeCanStop(c, this->min_distance,
+                                                                        this->abs_err, this->rel_err, this->w,
+                                                                        this->model2, *(this->model1), this->model1_bv,
+                                                                        this->motion2, this->motion1,
+                                                                        this->stack, this->delta_t);
+  }
+};
+
+
 }
 
 #endif
diff --git a/include/fcl/traversal/traversal_node_bvhs.h b/include/fcl/traversal/traversal_node_bvhs.h
index 9ddd8b54..3ceb22e7 100644
--- a/include/fcl/traversal/traversal_node_bvhs.h
+++ b/include/fcl/traversal/traversal_node_bvhs.h
@@ -340,6 +340,7 @@ public:
 
     num_vf_tests = 0;
     num_ee_tests = 0;
+    time_of_contact = 1;
   }
 
   /// @brief Intersection testing between leaves (two triangles)
@@ -422,7 +423,10 @@ public:
     }
 
     if(!(collision_time > 1)) // collision happens
+    {
       pairs.push_back(BVHContinuousCollisionPair(primitive_id1, primitive_id2, collision_time));
+      time_of_contact = std::min(time_of_contact, collision_time);
+    }
   }
 
   /// @brief Whether the traversal process can stop early
@@ -444,6 +448,8 @@ public:
   mutable int num_ee_tests;
 
   mutable std::vector<BVHContinuousCollisionPair> pairs;
+
+  mutable FCL_REAL time_of_contact;
 };
 
 
@@ -544,8 +550,8 @@ public:
     tri_indices1 = NULL;
     tri_indices2 = NULL;
 
-    rel_err = 0;
-    abs_err = 0;
+    rel_err = this->request.rel_err;
+    abs_err = this->request.abs_err;
   }
 
   /// @brief Distance testing between leaves (two triangles)
@@ -659,17 +665,6 @@ public:
 };
 
 
-struct ConservativeAdvancementStackData
-{
-  ConservativeAdvancementStackData(const Vec3f& P1_, const Vec3f& P2_, int c1_, int c2_, FCL_REAL d_)
-    : P1(P1_), P2(P2_), c1(c1_), c2(c2_), d(d_) {}
-
-  Vec3f P1;
-  Vec3f P2;
-  int c1;
-  int c2;
-  FCL_REAL d;
-};
 
 /// @brief continuous collision node using conservative advancement. when using this default version, must refit the BVH in current configuration (R_t, T_t) into default configuration
 template<typename BV>
@@ -732,16 +727,16 @@ public:
     {
       this->min_distance = d;
 
-      this->p1 = P1;
-      this->p2 = P2;
-
-      this->last_tri_id1 = primitive_id1;
-      this->last_tri_id2 = primitive_id2;
+      closest_p1 = P1;
+      closest_p2 = P2;
+      
+      last_tri_id1 = primitive_id1;
+      last_tri_id2 = primitive_id2;
     }
 
 
-    // n is the local frame of object 1
     Vec3f n = P2 - P1;
+    n.normalize();
     // here n is already in global frame as we assume the body is in original configuration (I, 0) for general BVH
     TriangleMotionBoundVisitor mb_visitor1(p1, p2, p3, n), mb_visitor2(q1, q2, q3, n);
     FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
@@ -771,21 +766,21 @@ public:
       {
         const ConservativeAdvancementStackData& data2 = stack[stack.size() - 2];
         d = data2.d;
-        n = data2.P2 - data2.P1;
+        n = data2.P2 - data2.P1; n.normalize();
         c1 = data2.c1;
         c2 = data2.c2;
         stack[stack.size() - 2] = stack[stack.size() - 1];
       }
       else
       {
-        n = data.P2 - data.P1;
+        n = data.P2 - data.P1; n.normalize();
         c1 = data.c1;
         c2 = data.c2;
       }
 
       assert(c == d);
 
-      TBVMotionBoundVisitor<BV> mb_visitor1((this->tree1 + c1)->bv, n), mb_visitor2((this->tree2 + c2)->bv, n);
+      TBVMotionBoundVisitor<BV> mb_visitor1(this->model1->getBV(c1).bv, n), mb_visitor2(this->model2->getBV(c2).bv, n);
       FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
       FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
 
@@ -817,9 +812,9 @@ public:
   }
 
   mutable FCL_REAL min_distance;
-
-  mutable Vec3f p1, p2;
-
+ 
+  mutable Vec3f closest_p1, closest_p2;
+  
   mutable int last_tri_id1, last_tri_id2;
 
 
diff --git a/include/fcl/traversal/traversal_node_octree.h b/include/fcl/traversal/traversal_node_octree.h
index 9cc1d50d..3ef5da22 100644
--- a/include/fcl/traversal/traversal_node_octree.h
+++ b/include/fcl/traversal/traversal_node_octree.h
@@ -247,9 +247,10 @@ private:
         constructBox(bv1, tf1, box, box_tf);
  
         FCL_REAL dist;
-        solver->shapeDistance(box, box_tf, s, tf2, &dist);
+        Vec3f closest_p1, closest_p2;
+        solver->shapeDistance(box, box_tf, s, tf2, &dist, &closest_p1, &closest_p2);
         
-        dresult->update(dist, tree1, &s, root1 - tree1->getRoot(), DistanceResult::NONE);
+        dresult->update(dist, tree1, &s, root1 - tree1->getRoot(), DistanceResult::NONE, closest_p1, closest_p2);
         
         return drequest->isSatisfied(*dresult);
       }
@@ -440,7 +441,8 @@ private:
         const Vec3f& p3 = tree2->vertices[tri_id[2]];
         
         FCL_REAL dist;
-        solver->shapeTriangleDistance(box, box_tf, p1, p2, p3, tf2, &dist);
+        Vec3f closest_p1, closest_p2;
+        solver->shapeTriangleDistance(box, box_tf, p1, p2, p3, tf2, &dist, &closest_p1, &closest_p2);
 
         dresult->update(dist, tree1, tree2, root1 - tree1->getRoot(), primitive_id);
 
@@ -709,9 +711,10 @@ private:
         constructBox(bv2, tf2, box2, box2_tf);
 
         FCL_REAL dist;
-        solver->shapeDistance(box1, box1_tf, box2, box2_tf, &dist);
+        Vec3f closest_p1, closest_p2;
+        solver->shapeDistance(box1, box1_tf, box2, box2_tf, &dist, &closest_p1, &closest_p2);
 
-        dresult->update(dist, tree1, tree2, root1 - tree1->getRoot(), root2 - tree2->getRoot());
+        dresult->update(dist, tree1, tree2, root1 - tree1->getRoot(), root2 - tree2->getRoot(), closest_p1, closest_p2);
         
         return drequest->isSatisfied(*dresult);
       }
diff --git a/include/fcl/traversal/traversal_node_setup.h b/include/fcl/traversal/traversal_node_setup.h
index fd73e34b..5f01167c 100644
--- a/include/fcl/traversal/traversal_node_setup.h
+++ b/include/fcl/traversal/traversal_node_setup.h
@@ -1023,9 +1023,6 @@ bool initialize(MeshContinuousCollisionTraversalNode<BV>& node,
                 const BVHModel<BV>& model2, const Transform3f& tf2,
                 const CollisionRequest& request)
 {
-  if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
-    return false;
-
   node.model1 = &model1;
   node.tf1 = tf1;
   node.model2 = &model2;
@@ -1053,9 +1050,6 @@ bool initialize(MeshConservativeAdvancementTraversalNode<BV>& node,
                 FCL_REAL w = 1,
                 bool use_refit = false, bool refit_bottomup = false)
 {
-  if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
-    return false;
-
   std::vector<Vec3f> vertices_transformed1(model1.num_vertices);
   for(int i = 0; i < model1.num_vertices; ++i)
   {
@@ -1107,6 +1101,186 @@ bool initialize(MeshConservativeAdvancementTraversalNodeOBBRSS& node,
                 const BVHModel<OBBRSS>& model2, const Transform3f& tf2,
                 FCL_REAL w = 1);
 
+template<typename S1, typename S2, typename NarrowPhaseSolver>
+bool initialize(ShapeConservativeAdvancementTraversalNode<S1, S2, NarrowPhaseSolver>& node,
+                const S1& shape1, const Transform3f& tf1,
+                const S2& shape2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver)
+{ 
+  node.model1 = &shape1;
+  node.tf1 = tf1;
+  node.model2 = &shape2;
+  node.tf2 = tf2;
+  node.nsolver = nsolver;
+
+  computeBV<RSS, S1>(shape1, Transform3f(), node.model1_bv);
+  computeBV<RSS, S2>(shape2, Transform3f(), node.model2_bv);
+  
+  return true;
+}
+
+template<typename BV, typename S, typename NarrowPhaseSolver>
+bool initialize(MeshShapeConservativeAdvancementTraversalNode<BV, S, NarrowPhaseSolver>& node,
+                BVHModel<BV>& model1, const Transform3f& tf1,
+                const S& model2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver,
+                FCL_REAL w = 1,
+                bool use_refit = false, bool refit_bottomup = false)
+{
+  std::vector<Vec3f> vertices_transformed(model1.num_vertices);
+  for(int i = 0; i < model1.num_vertices; ++i)
+  {
+    Vec3f& p = model1.vertices[i];
+    Vec3f new_v = tf1.transform(p);
+    vertices_transformed[i] = new_v;
+  }
+
+  model1.beginReplaceModel();
+  model1.replaceSubModel(vertices_transformed);
+  model1.endReplaceModel(use_refit, refit_bottomup);
+  
+  node.model1 = &model1;
+  node.model2 = &model2;
+
+  node.vertices = model1.vertices;
+  node.tri_indices = model1.tri_indices;
+  
+  node.tf1 = tf1;
+  node.tf2 = tf2;
+  
+  node.nsolver = nsolver;
+  node.w = w;
+
+  computeBV<BV, S>(model2, Transform3f(), node.model2_bv);
+
+  return true;
+}
+
+
+template<typename S, typename NarrowPhaseSolver>
+bool initialize(MeshShapeConservativeAdvancementTraversalNodeRSS<S, NarrowPhaseSolver>& node,
+                const BVHModel<RSS>& model1, const Transform3f& tf1,
+                const S& model2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver,
+                FCL_REAL w = 1)
+{
+  node.model1 = &model1;
+  node.tf1 = tf1;
+  node.model2 = &model2;
+  node.tf2 = tf2;
+  node.nsolver = nsolver;
+
+  node.w = w;
+
+  computeBV<RSS, S>(model2, Transform3f(), node.model2_bv);
+
+  return true;
+}
+
+
+template<typename S, typename NarrowPhaseSolver>
+bool initialize(MeshShapeConservativeAdvancementTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node,
+                const BVHModel<OBBRSS>& model1, const Transform3f& tf1,
+                const S& model2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver,
+                FCL_REAL w = 1)
+{
+  node.model1 = &model1;
+  node.tf1 = tf1;
+  node.model2 = &model2;
+  node.tf2 = tf2;
+  node.nsolver = nsolver;
+
+  node.w = w;
+
+  computeBV<OBBRSS, S>(model2, Transform3f(), node.model2_bv);
+
+  return true;
+}
+
+
+template<typename S, typename BV, typename NarrowPhaseSolver>
+bool initialize(ShapeMeshConservativeAdvancementTraversalNode<S, BV, NarrowPhaseSolver>& node,
+                const S& model1, const Transform3f& tf1,
+                BVHModel<BV>& model2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver,
+                FCL_REAL w = 1,
+                bool use_refit = false, bool refit_bottomup = false)
+{
+  std::vector<Vec3f> vertices_transformed(model2.num_vertices);
+  for(int i = 0; i < model2.num_vertices; ++i)
+  {
+    Vec3f& p = model2.vertices[i];
+    Vec3f new_v = tf2.transform(p);
+    vertices_transformed[i] = new_v;
+  }
+
+  model2.beginReplaceModel();
+  model2.replaceSubModel(vertices_transformed);
+  model2.endReplaceModel(use_refit, refit_bottomup);
+  
+  node.model1 = &model1;
+  node.model2 = &model2;
+
+  node.vertices = model2.vertices;
+  node.tri_indices = model2.tri_indices;
+  
+  node.tf1 = tf1;
+  node.tf2 = tf2;
+  
+  node.nsolver = nsolver;
+  node.w = w;
+
+  computeBV<BV, S>(model1, Transform3f(), node.model1_bv);
+
+  return true;
+}
+
+
+template<typename S, typename NarrowPhaseSolver>
+bool initialize(ShapeMeshConservativeAdvancementTraversalNodeRSS<S, NarrowPhaseSolver>& node,
+                const S& model1, const Transform3f& tf1,
+                const BVHModel<RSS>& model2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver,
+                FCL_REAL w = 1)
+{
+  node.model1 = &model1;
+  node.tf1 = tf1;
+  node.model2 = &model2;
+  node.tf2 = tf2;
+  node.nsolver = nsolver;
+
+  node.w = w;
+
+  computeBV<RSS, S>(model1, Transform3f(), node.model1_bv);
+
+  return true;
+}
+
+
+template<typename S, typename NarrowPhaseSolver>
+bool initialize(ShapeMeshConservativeAdvancementTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node,
+                const S& model1, const Transform3f& tf1,
+                const BVHModel<OBBRSS>& model2, const Transform3f& tf2,
+                const NarrowPhaseSolver* nsolver,
+                FCL_REAL w = 1)
+{
+  node.model1 = &model1;
+  node.tf1 = tf1;
+  node.model2 = &model2;
+  node.tf2 = tf2;
+  node.nsolver = nsolver;
+
+  node.w = w;
+
+  computeBV<OBBRSS, S>(model1, Transform3f(), node.model1_bv);
+
+  return true;
+}
+
+
+                
+
 }
 
 #endif
diff --git a/include/fcl/traversal/traversal_node_shapes.h b/include/fcl/traversal/traversal_node_shapes.h
index 3bb3cc3d..fb2c4062 100644
--- a/include/fcl/traversal/traversal_node_shapes.h
+++ b/include/fcl/traversal/traversal_node_shapes.h
@@ -42,6 +42,9 @@
 #include "fcl/traversal/traversal_node_base.h"
 #include "fcl/narrowphase/narrowphase.h"
 #include "fcl/shape/geometric_shapes_utility.h"
+#include "fcl/BV/BV.h"
+#include "fcl/shape/geometric_shapes_utility.h"
+#include "fcl/ccd/motion.h"
 
 namespace fcl
 {
@@ -148,8 +151,9 @@ public:
   void leafTesting(int, int) const
   {
     FCL_REAL distance;
-    nsolver->shapeDistance(*model1, tf1, *model2, tf2, &distance);
-    result->update(distance, model1, model2, DistanceResult::NONE, DistanceResult::NONE);
+    Vec3f closest_p1, closest_p2;
+    nsolver->shapeDistance(*model1, tf1, *model2, tf2, &distance, &closest_p1, &closest_p2);
+    result->update(distance, model1, model2, DistanceResult::NONE, DistanceResult::NONE, closest_p1, closest_p2);
   }
 
   const S1* model1;
@@ -158,6 +162,58 @@ public:
   const NarrowPhaseSolver* nsolver;
 };
 
+template<typename S1, typename S2, typename NarrowPhaseSolver>
+class ShapeConservativeAdvancementTraversalNode : public ShapeDistanceTraversalNode<S1, S2, NarrowPhaseSolver>
+{
+public:
+  ShapeConservativeAdvancementTraversalNode() : ShapeDistanceTraversalNode<S1, S2, NarrowPhaseSolver>()
+  {
+    delta_t = 1;
+    toc = 0;
+    t_err = (FCL_REAL)0.0001;
+
+    motion1 = NULL;
+    motion2 = NULL;
+  }
+
+  void leafTesting(int, int) const
+  {
+    FCL_REAL distance;
+    Vec3f closest_p1, closest_p2;
+    this->nsolver->shapeDistance(*(this->model1), this->tf1, *(this->model2), this->tf2, &distance, &closest_p1, &closest_p2);
+
+    Vec3f n = this->tf2.transform(closest_p2) - this->tf1.transform(closest_p1); n.normalize();
+    TBVMotionBoundVisitor<RSS> mb_visitor1(model1_bv, n);
+    TBVMotionBoundVisitor<RSS> mb_visitor2(model2_bv, -n);
+    FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
+    FCL_REAL bound2 = motion2->computeMotionBound(mb_visitor2);
+
+    FCL_REAL bound = bound1 + bound2;
+
+    FCL_REAL cur_delta_t;
+    if(bound <= distance) cur_delta_t = 1;
+    else cur_delta_t = distance / bound;
+
+    if(cur_delta_t < delta_t)
+      delta_t  = cur_delta_t;
+  }
+
+  mutable FCL_REAL min_distance;
+
+  /// @brief The time from beginning point
+  FCL_REAL toc;
+  FCL_REAL t_err;
+
+  /// @brief The delta_t each step
+  mutable FCL_REAL delta_t;
+
+  /// @brief Motions for the two objects in query
+  const MotionBase* motion1;
+  const MotionBase* motion2;
+
+  RSS model1_bv, model2_bv; // local bv for the two shapes
+};
+
 
 }
 
diff --git a/src/broadphase/broadphase_SSaP.cpp b/src/broadphase/broadphase_SSaP.cpp
index c47160f8..ea23055e 100644
--- a/src/broadphase/broadphase_SSaP.cpp
+++ b/src/broadphase/broadphase_SSaP.cpp
@@ -432,7 +432,7 @@ void SSaPCollisionManager::distance(void* cdata, DistanceCallBack callback) cons
   if(size() == 0) return;
 
   std::vector<CollisionObject*>::const_iterator it, it_end;
-  size_t axis = selectOptimalAxis(objs_x, objs_y, objs_z, it, it_end);
+  // size_t axis = selectOptimalAxis(objs_x, objs_y, objs_z, it, it_end);
 
   FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max();
   for(; it != it_end; ++it)
diff --git a/src/ccd/conservative_advancement.cpp b/src/ccd/conservative_advancement.cpp
index 9447c932..4cf9e39e 100644
--- a/src/ccd/conservative_advancement.cpp
+++ b/src/ccd/conservative_advancement.cpp
@@ -44,83 +44,513 @@
 
 
 namespace fcl
+{
+
+
 
+
+template<typename BV>
+bool conservativeAdvancement(const BVHModel<BV>& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<BV>& o2,
+                             const MotionBase* motion2,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
 {
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
+
+  // whether the first start configuration is in collision
+  if(collide(&o1, tf1, &o2, tf2, request, result))
+  {
+    toc = 0;
+    return true;
+  }
+
+
+  BVHModel<BV>* o1_tmp = new BVHModel<BV>(o1);
+  BVHModel<BV>* o2_tmp = new BVHModel<BV>(o2);
+  
+  
+  MeshConservativeAdvancementTraversalNode<BV> node;
+
+  node.motion1 = motion1;
+  node.motion2 = motion2;
+
+  do
+  {
+    // repeatedly update mesh to global coordinate, so time consuming
+    initialize(node, *o1_tmp, tf1, *o2_tmp, tf2);
+    
+    node.delta_t = 1;
+    node.min_distance = std::numeric_limits<FCL_REAL>::max();
+
+    distanceRecurse(&node, 0, 0, NULL);
+
+    if(node.delta_t <= node.t_err)
+    {
+      // std::cout << node.delta_t << " " << node.t_err << std::endl;
+      break;
+    }
+
+    node.toc += node.delta_t;
+    if(node.toc > 1)
+    {
+      node.toc = 1;
+      break;
+    }
+
+    node.motion1->integrate(node.toc);
+    node.motion2->integrate(node.toc);
+
+    motion1->getCurrentTransform(tf1);
+    motion2->getCurrentTransform(tf2);
+  }
+  while(1);
 
-template<typename BV, typename ConservativeAdvancementNode, typename CollisionNode>
-int conservativeAdvancement(const CollisionGeometry* o1,
-                            const MotionBase* motion1,
-                            const CollisionGeometry* o2,
-                            const MotionBase* motion2,
-                            const CollisionRequest& request,
-                            CollisionResult& result,
-                            FCL_REAL& toc)
+  delete o1_tmp;
+  delete o2_tmp;
+
+  toc = node.toc;
+
+  if(node.toc < 1)
+    return true;
+
+  return false;
+}
+
+namespace details
+{
+
+template<typename BV, typename ConservativeAdvancementOrientedNode>
+bool conservativeAdvancementMeshOriented(const BVHModel<BV>& o1,
+                                         const MotionBase* motion1,
+                                         const BVHModel<BV>& o2,
+                                         const MotionBase* motion2,
+                                         const CollisionRequest& request,
+                                         CollisionResult& result,
+                                         FCL_REAL& toc)
 {
-  if(request.num_max_contacts == 0)
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
+
+  // whether the first start configuration is in collision
+  if(collide(&o1, tf1, &o2, tf2, request, result))
   {
-    std::cerr << "Warning: should stop early as num_max_contact is " << request.num_max_contacts << " !" << std::endl;
-    return 0;
+    toc = 0;
+    return true;
   }
+  
+  
+  ConservativeAdvancementOrientedNode node;
+
+  initialize(node, o1, tf1, o2, tf2);
+
+  node.motion1 = motion1;
+  node.motion2 = motion2;
+
+  do
+  {
+    node.motion1->getCurrentTransform(tf1);
+    node.motion2->getCurrentTransform(tf2);
 
-  const OBJECT_TYPE object_type1 = o1->getObjectType();
-  const NODE_TYPE node_type1 = o1->getNodeType();
+    // compute the transformation from 1 to 2
+    Transform3f tf;
+    relativeTransform(tf1, tf2, tf);
+    node.R = tf.getRotation();
+    node.T = tf.getTranslation();
+    
+    node.delta_t = 1;
+    node.min_distance = std::numeric_limits<FCL_REAL>::max();
 
-  const OBJECT_TYPE object_type2 = o2->getObjectType();
-  const NODE_TYPE node_type2 = o2->getNodeType();
+    distanceRecurse(&node, 0, 0, NULL);
 
-  if(object_type1 != OT_BVH || object_type2 != OT_BVH)
-    return 0;
+    if(node.delta_t <= node.t_err)
+    {
+      // std::cout << node.delta_t << " " << node.t_err << std::endl;
+      break;
+    }
 
-  if(node_type1 != BV_RSS || node_type2 != BV_RSS)
-    return 0;
+    node.toc += node.delta_t;
+    if(node.toc > 1)
+    {
+      node.toc = 1;
+      break;
+    }
 
+    node.motion1->integrate(node.toc);
+    node.motion2->integrate(node.toc);
+  }
+  while(1);
 
-  const BVHModel<BV>* model1 = static_cast<const BVHModel<BV>*>(o1);
-  const BVHModel<BV>* model2 = static_cast<const BVHModel<BV>*>(o2);
+  toc = node.toc;
 
+  if(node.toc < 1)
+    return true;
+
+  return false;
+}
+
+
+}
+
+template<>
+bool conservativeAdvancement(const BVHModel<RSS>& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<RSS>& o2,
+                             const MotionBase* motion2,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc);
+
+
+template<>
+bool conservativeAdvancement(const BVHModel<OBBRSS>& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<OBBRSS>& o2,
+                             const MotionBase* motion2,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc);
+
+template<typename S1, typename S2, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const S1& o1,
+                             const MotionBase* motion1,
+                             const S2& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* solver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
   Transform3f tf1, tf2;
   motion1->getCurrentTransform(tf1);
   motion2->getCurrentTransform(tf2);
 
   // whether the first start configuration is in collision
-  CollisionNode cnode;
-  if(!initialize(cnode, *model1, tf1, *model2, tf2, request, result))
-    std::cout << "initialize error" << std::endl;
+  if(collide(&o1, tf1, &o2, tf2, request, result))
+  {
+    toc = 0;
+    return true;
+  }
+
+  ShapeConservativeAdvancementTraversalNode<S1, S2, NarrowPhaseSolver> node;
+
+  initialize(node, o1, tf1, o2, tf2, solver);
+
+  node.motion1 = motion1;
+  node.motion2 = motion2;
+
+  do
+  {
+    motion1->getCurrentTransform(tf1);
+    motion2->getCurrentTransform(tf2);
+    node.tf1 = tf1;
+    node.tf2 = tf2;
+    
+    node.delta_t = 1;
+    node.min_distance = std::numeric_limits<FCL_REAL>::max();
+
+    distanceRecurse(&node, 0, 0, NULL);
+
+    if(node.delta_t <= node.t_err)
+    {
+      // std::cout << node.delta_t << " " << node.t_err << std::endl;
+      break;
+    }
+
+    node.toc += node.delta_t;
+    if(node.toc > 1)
+    {
+      node.toc = 1;
+      break;
+    }
 
-  relativeTransform(tf1.getRotation(), tf1.getTranslation(), tf2.getRotation(), tf2.getTranslation(), cnode.R, cnode.T);
+    node.motion1->integrate(node.toc);
+    node.motion2->integrate(node.toc);
+  }
+  while(1);
 
-  cnode.enable_statistics = false;
-  cnode.request = request;
+  toc = node.toc;
 
-  collide(&cnode);
+  if(node.toc < 1)
+    return true;
+
+  return false;
+}
 
-  int b = result.numContacts();
+template<typename BV, typename S, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const BVHModel<BV>& o1,
+                             const MotionBase* motion1,
+                             const S& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* nsolver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
 
-  if(b > 0)
+  if(collide(&o1, tf1, &o2, tf2, request, result))
   {
     toc = 0;
-    // std::cout << "zero collide" << std::endl;
-    return b;
+    return true;
   }
-  
-  ConservativeAdvancementNode node;
 
-  initialize(node, *model1, tf1, *model2, tf2);
+  BVHModel<BV>* o1_tmp = new BVHModel<BV>(o1);
+
+  MeshShapeConservativeAdvancementTraversalNode<BV, S, NarrowPhaseSolver> node;
 
   node.motion1 = motion1;
   node.motion2 = motion2;
 
   do
   {
-    Matrix3f R1_t, R2_t;
-    Vec3f T1_t, T2_t;
+    // initialize update mesh to global coordinate, so time consuming
+    initialize(node, *o1_tmp, tf1, o2, tf2, nsolver);
 
-    node.motion1->getCurrentTransform(R1_t, T1_t);
-    node.motion2->getCurrentTransform(R2_t, T2_t);
+    node.delta_t = 1;
+    node.min_distance = std::numeric_limits<FCL_REAL>::max();
 
-    // compute the transformation from 1 to 2
-    relativeTransform(R1_t, T1_t, R2_t, T2_t, node.R, node.T);
+    distanceRecurse(&node, 0, 0, NULL);
+
+    if(node.delta_t <= node.t_err)
+    {
+      break;
+    }
+
+    node.toc += node.delta_t;
+    if(node.toc > 1)
+    {
+      node.toc = 1;
+      break;
+    }
 
+    node.motion1->integrate(node.toc);
+    node.motion2->integrate(node.toc);
+
+    motion1->getCurrentTransform(tf1);
+    motion2->getCurrentTransform(tf2);
+  }
+  while(1);
+
+  delete o1_tmp;
+
+  toc = node.toc;
+
+  if(node.toc < 1)
+    return true;
+
+  return false;
+}
+
+namespace details
+{
+
+template<typename BV, typename S, typename NarrowPhaseSolver, typename ConservativeAdvancementOrientedNode>
+bool conservativeAdvancementMeshShapeOriented(const BVHModel<BV>& o1,
+                                              const MotionBase* motion1,
+                                              const S& o2,
+                                              const MotionBase* motion2,
+                                              const NarrowPhaseSolver* nsolver,
+                                              const CollisionRequest& request,
+                                              CollisionResult& result,
+                                              FCL_REAL& toc)
+{
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
+
+  if(collide(&o1, tf1, &o2, tf2, request, result))
+  {
+    toc = 0;
+    return true;
+  }
+
+  ConservativeAdvancementOrientedNode node;
+
+  initialize(node, o1, tf1, o2, tf2, nsolver);
+
+  node.motion1 = motion1;
+  node.motion2 = motion2;
+
+  do
+  {
+    node.motion1->getCurrentTransform(tf1);
+    node.motion2->getCurrentTransform(tf2);
+
+    node.tf1 = tf1;
+    node.tf2 = tf2;
+    
+    node.delta_t = 1;
+    node.min_distance = std::numeric_limits<FCL_REAL>::max();
+
+    distanceRecurse(&node, 0, 0, NULL);
+
+    if(node.delta_t <= node.t_err)
+    {
+      break;
+    }
+
+    node.toc += node.delta_t;
+    if(node.toc > 1)
+    {
+      node.toc = 1;
+      break;
+    }
+
+    node.motion1->integrate(node.toc);
+    node.motion2->integrate(node.toc);
+  }
+  while(1);
+
+  toc = node.toc;
+
+  if(node.toc < 1)
+    return true;
+
+  return false;
+}
+
+}
+
+
+template<typename S, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const BVHModel<RSS>& o1,
+                             const MotionBase* motion1,
+                             const S& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* nsolver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  return details::conservativeAdvancementMeshShapeOriented<RSS, S, NarrowPhaseSolver, MeshShapeConservativeAdvancementTraversalNodeRSS<S, NarrowPhaseSolver> >(o1, motion1, o2, motion2, nsolver, request, result, toc);
+}
+
+template<typename S, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const BVHModel<OBBRSS>& o1,
+                             const MotionBase* motion1,
+                             const S& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* nsolver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  return details::conservativeAdvancementMeshShapeOriented<OBBRSS, S, NarrowPhaseSolver, MeshShapeConservativeAdvancementTraversalNodeOBBRSS<S, NarrowPhaseSolver> >(o1, motion1, o2, motion2, nsolver, request, result, toc);  
+}
+                            
+template<typename S, typename BV, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const S& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<BV>& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* nsolver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
+
+  if(collide(&o1, tf1, &o2, tf2, request, result))
+  {
+    toc = 0;
+    return true;
+  }
+
+  BVHModel<BV>* o2_tmp = new BVHModel<BV>(o2);
+
+  ShapeMeshConservativeAdvancementTraversalNode<S, BV, NarrowPhaseSolver> node;
+
+  node.motion1 = motion1;
+  node.motion2 = motion2;
+
+  do
+  {
+    // initialize update mesh to global coordinate, so time consuming
+    initialize(node, o1, tf1, *o2_tmp, tf2, nsolver);
+
+    node.delta_t = 1;
+    node.min_distance = std::numeric_limits<FCL_REAL>::max();
+
+    distanceRecurse(&node, 0, 0, NULL);
+
+    if(node.delta_t <= node.t_err)
+    {
+      break;
+    }
+
+    node.toc += node.delta_t;
+    if(node.toc > 1)
+    {
+      node.toc = 1;
+      break;
+    }
+
+    node.motion1->integrate(node.toc);
+    node.motion2->integrate(node.toc);
+
+    motion1->getCurrentTransform(tf1);
+    motion2->getCurrentTransform(tf2);
+  }
+  while(1);
+
+  delete o2_tmp;
+
+  toc = node.toc;
+
+  if(node.toc < 1)
+    return true;
+
+  return false;  
+}
+
+namespace details
+{
+
+template<typename S, typename BV, typename NarrowPhaseSolver, typename ConservativeAdvancementOrientedNode>
+bool conservativeAdvancementShapeMeshOriented(const S& o1,
+                                              const MotionBase* motion1,
+                                              const BVHModel<BV>& o2,
+                                              const MotionBase* motion2,
+                                              const NarrowPhaseSolver* nsolver,
+                                              const CollisionRequest& request,
+                                              CollisionResult& result,
+                                              FCL_REAL& toc)
+{
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
+
+  if(collide(&o1, tf1, &o2, tf2, request, result))
+  {
+    toc = 0;
+    return true;
+  }
+
+  ConservativeAdvancementOrientedNode node;
+
+  initialize(node, o1, tf1, o2, tf2, nsolver);
+
+  node.motion1 = motion1;
+  node.motion2 = motion2;
+
+  do
+  {
+    node.motion1->getCurrentTransform(tf1);
+    node.motion2->getCurrentTransform(tf2);
+
+    node.tf1 = tf1;
+    node.tf2 = tf2;
+    
     node.delta_t = 1;
     node.min_distance = std::numeric_limits<FCL_REAL>::max();
 
@@ -128,7 +558,6 @@ int conservativeAdvancement(const CollisionGeometry* o1,
 
     if(node.delta_t <= node.t_err)
     {
-      // std::cout << node.delta_t << " " << node.t_err << std::endl;
       break;
     }
 
@@ -147,27 +576,355 @@ int conservativeAdvancement(const CollisionGeometry* o1,
   toc = node.toc;
 
   if(node.toc < 1)
-    return 1;
+    return true;
+
+  return false;
+}
+
+}
+
+template<typename S, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const S& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<RSS>& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* nsolver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  return details::conservativeAdvancementShapeMeshOriented<S, RSS, NarrowPhaseSolver, ShapeMeshConservativeAdvancementTraversalNodeRSS<S, NarrowPhaseSolver> >(o1, motion1, o2, motion2, nsolver, request, result, toc);
+}
+
+
+template<typename S, typename NarrowPhaseSolver>
+bool conservativeAdvancement(const S& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<OBBRSS>& o2,
+                             const MotionBase* motion2,
+                             const NarrowPhaseSolver* nsolver,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  return details::conservativeAdvancementShapeMeshOriented<S, OBBRSS, NarrowPhaseSolver, ShapeMeshConservativeAdvancementTraversalNodeOBBRSS<S, NarrowPhaseSolver> >(o1, motion1, o2, motion2, nsolver, request, result, toc);
+}
+
+
+
+template<>
+bool conservativeAdvancement(const BVHModel<RSS>& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<RSS>& o2,
+                             const MotionBase* motion2,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  return details::conservativeAdvancementMeshOriented<RSS, MeshConservativeAdvancementTraversalNodeRSS>(o1, motion1, o2, motion2, request, result, toc);
+}
+
+template<>
+bool conservativeAdvancement(const BVHModel<OBBRSS>& o1,
+                             const MotionBase* motion1,
+                             const BVHModel<OBBRSS>& o2,
+                             const MotionBase* motion2,
+                             const CollisionRequest& request,
+                             CollisionResult& result,
+                             FCL_REAL& toc)
+{
+  return details::conservativeAdvancementMeshOriented<OBBRSS, MeshConservativeAdvancementTraversalNodeOBBRSS>(o1, motion1, o2, motion2, request, result, toc);
+}
 
-  return 0;
+
+template<typename BV, typename NarrowPhaseSolver>
+FCL_REAL BVHConservativeAdvancement(const CollisionGeometry* o1, const MotionBase* motion1, const CollisionGeometry* o2, const MotionBase* motion2, const NarrowPhaseSolver* nsolver, const ContinuousCollisionRequest& request, ContinuousCollisionResult& result)
+{
+  const BVHModel<BV>* obj1 = static_cast<const BVHModel<BV>*>(o1);
+  const BVHModel<BV>* obj2 = static_cast<const BVHModel<BV>*>(o2);
+
+  CollisionRequest c_request;
+  CollisionResult c_result;
+  FCL_REAL toc;
+  bool is_collide = conservativeAdvancement(*obj1, motion1, *obj2, motion2, c_request, c_result, toc);
+
+  result.is_collide = is_collide;
+  result.time_of_contact = toc;
+  
+  return toc;
+}
+
+template<typename S1, typename S2, typename NarrowPhaseSolver>
+FCL_REAL ShapeConservativeAdvancement(const CollisionGeometry* o1, const MotionBase* motion1, const CollisionGeometry* o2, const MotionBase* motion2, const NarrowPhaseSolver* nsolver, const ContinuousCollisionRequest& request, ContinuousCollisionResult& result)
+{
+  const S1* obj1 = static_cast<const S1*>(o1);
+  const S2* obj2 = static_cast<const S2*>(o2);
+
+  CollisionRequest c_request;
+  CollisionResult c_result;
+  FCL_REAL toc;
+  bool is_collide = conservativeAdvancement(*obj1, motion1, *obj2, motion2, nsolver, c_request, c_result, toc);
+
+  result.is_collide = is_collide;
+  result.time_of_contact = toc;
+
+  return toc;
+}
+
+template<typename S, typename BV, typename NarrowPhaseSolver>
+FCL_REAL ShapeBVHConservativeAdvancement(const CollisionGeometry* o1, const MotionBase* motion1, const CollisionGeometry* o2, const MotionBase* motion2, const NarrowPhaseSolver* nsolver, const ContinuousCollisionRequest& request, ContinuousCollisionResult& result)
+{
+  const S* obj1 = static_cast<const S*>(o1);
+  const BVHModel<BV>* obj2 = static_cast<const BVHModel<BV>*>(o2);
+
+  CollisionRequest c_request;
+  CollisionResult c_result;
+  FCL_REAL toc;
+
+  bool is_collide = conservativeAdvancement(*obj1, motion1, *obj2, motion2, nsolver, c_request, c_result, toc);
+
+  result.is_collide = is_collide;
+  result.time_of_contact = toc;
+
+  return toc;
+}
+
+template<typename BV, typename S, typename NarrowPhaseSolver>
+FCL_REAL BVHShapeConservativeAdvancement(const CollisionGeometry* o1, const MotionBase* motion1, const CollisionGeometry* o2, const MotionBase* motion2, const NarrowPhaseSolver* nsolver, const ContinuousCollisionRequest& request, ContinuousCollisionResult& result)
+{
+  const BVHModel<BV>* obj1 = static_cast<const BVHModel<BV>*>(o1);
+  const S* obj2 = static_cast<const S*>(o2);
+
+  CollisionRequest c_request;
+  CollisionResult c_result;
+  FCL_REAL toc;
+
+  bool is_collide = conservativeAdvancement(*obj1, motion1, *obj2, motion2, nsolver, c_request, c_result, toc);
+
+  result.is_collide = is_collide;
+  result.time_of_contact = toc;
+
+  return toc;
+}
+
+template<typename NarrowPhaseSolver>
+ConservativeAdvancementFunctionMatrix<NarrowPhaseSolver>::ConservativeAdvancementFunctionMatrix()
+{
+  for(int i = 0; i < NODE_COUNT; ++i)
+  {
+    for(int j = 0; j < NODE_COUNT; ++j)
+      conservative_advancement_matrix[i][j] = NULL;
+  }
+
+
+  conservative_advancement_matrix[GEOM_BOX][GEOM_BOX] = &ShapeConservativeAdvancement<Box, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeConservativeAdvancement<Box, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Box, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_BOX][GEOM_CONE] = &ShapeConservativeAdvancement<Box, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Box, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeConservativeAdvancement<Box, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeConservativeAdvancement<Box, Plane, NarrowPhaseSolver>;
+    
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeConservativeAdvancement<Sphere, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeConservativeAdvancement<Sphere, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Sphere, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeConservativeAdvancement<Sphere, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Sphere, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeConservativeAdvancement<Sphere, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeConservativeAdvancement<Sphere, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeConservativeAdvancement<Capsule, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeConservativeAdvancement<Capsule, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Capsule, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeConservativeAdvancement<Capsule, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Capsule, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeConservativeAdvancement<Capsule, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeConservativeAdvancement<Capsule, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_CONE][GEOM_BOX] = &ShapeConservativeAdvancement<Cone, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeConservativeAdvancement<Cone, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Cone, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][GEOM_CONE] = &ShapeConservativeAdvancement<Cone, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Cone, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeConservativeAdvancement<Cone, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeConservativeAdvancement<Cone, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeConservativeAdvancement<Cylinder, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeConservativeAdvancement<Cylinder, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Cylinder, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeConservativeAdvancement<Cylinder, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Cylinder, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeConservativeAdvancement<Cylinder, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeConservativeAdvancement<Cylinder, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeConservativeAdvancement<Convex, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeConservativeAdvancement<Convex, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Convex, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeConservativeAdvancement<Convex, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Convex, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeConservativeAdvancement<Convex, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeConservativeAdvancement<Convex, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeConservativeAdvancement<Plane, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeConservativeAdvancement<Plane, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeConservativeAdvancement<Plane, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeConservativeAdvancement<Plane, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeConservativeAdvancement<Plane, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeConservativeAdvancement<Plane, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeConservativeAdvancement<Plane, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_AABB][GEOM_BOX] = &BVHShapeConservativeAdvancement<AABB, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<AABB, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<AABB, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_AABB][GEOM_CONE] = &BVHShapeConservativeAdvancement<AABB, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<AABB, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<AABB, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeConservativeAdvancement<AABB, Plane, NarrowPhaseSolver>;
+  
+  conservative_advancement_matrix[BV_OBB][GEOM_BOX] = &BVHShapeConservativeAdvancement<OBB, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<OBB, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<OBB, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][GEOM_CONE] = &BVHShapeConservativeAdvancement<OBB, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<OBB, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<OBB, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeConservativeAdvancement<OBB, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeConservativeAdvancement<OBBRSS, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<OBBRSS, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<OBBRSS, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeConservativeAdvancement<OBBRSS, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<OBBRSS, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<OBBRSS, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeConservativeAdvancement<OBBRSS, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_RSS][GEOM_BOX] = &BVHShapeConservativeAdvancement<RSS, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<RSS, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<RSS, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][GEOM_CONE] = &BVHShapeConservativeAdvancement<RSS, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<RSS, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<RSS, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeConservativeAdvancement<RSS, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeConservativeAdvancement<KDOP<16>, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<KDOP<16>, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<KDOP<16>, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeConservativeAdvancement<KDOP<16>, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<KDOP<16>, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<KDOP<16>, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeConservativeAdvancement<KDOP<16>, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeConservativeAdvancement<KDOP<18>, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<KDOP<18>, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<KDOP<18>, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeConservativeAdvancement<KDOP<18>, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<KDOP<18>, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<KDOP<18>, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeConservativeAdvancement<KDOP<18>, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeConservativeAdvancement<KDOP<24>, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<KDOP<24>, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<KDOP<24>, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeConservativeAdvancement<KDOP<24>, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<KDOP<24>, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<KDOP<24>, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeConservativeAdvancement<KDOP<24>, Plane, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeConservativeAdvancement<kIOS, Box, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeConservativeAdvancement<kIOS, Sphere, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeConservativeAdvancement<kIOS, Capsule, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeConservativeAdvancement<kIOS, Cone, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeConservativeAdvancement<kIOS, Cylinder, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeConservativeAdvancement<kIOS, Convex, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeConservativeAdvancement<kIOS, Plane, NarrowPhaseSolver>;
+
+
+  conservative_advancement_matrix[GEOM_BOX][BV_AABB] = &ShapeBVHConservativeAdvancement<Box, AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_AABB] = &ShapeBVHConservativeAdvancement<Sphere, AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_AABB] = &ShapeBVHConservativeAdvancement<Capsule, AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_AABB] = &ShapeBVHConservativeAdvancement<Cone, AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_AABB] = &ShapeBVHConservativeAdvancement<Cylinder, AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_AABB] = &ShapeBVHConservativeAdvancement<Convex, AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_AABB] = &ShapeBVHConservativeAdvancement<Plane, AABB, NarrowPhaseSolver>;
+  
+  conservative_advancement_matrix[GEOM_BOX][BV_OBB] = &ShapeBVHConservativeAdvancement<Box, OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_OBB] = &ShapeBVHConservativeAdvancement<Sphere, OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_OBB] = &ShapeBVHConservativeAdvancement<Capsule, OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_OBB] = &ShapeBVHConservativeAdvancement<Cone, OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_OBB] = &ShapeBVHConservativeAdvancement<Cylinder, OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_OBB] = &ShapeBVHConservativeAdvancement<Convex, OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_OBB] = &ShapeBVHConservativeAdvancement<Plane, OBB, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_BOX][BV_RSS] = &ShapeBVHConservativeAdvancement<Box, RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_RSS] = &ShapeBVHConservativeAdvancement<Sphere, RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_RSS] = &ShapeBVHConservativeAdvancement<Capsule, RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_RSS] = &ShapeBVHConservativeAdvancement<Cone, RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_RSS] = &ShapeBVHConservativeAdvancement<Cylinder, RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_RSS] = &ShapeBVHConservativeAdvancement<Convex, RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_RSS] = &ShapeBVHConservativeAdvancement<Plane, RSS, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_BOX][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Box, OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Sphere, OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Capsule, OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Cone, OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Cylinder, OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Convex, OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_OBBRSS] = &ShapeBVHConservativeAdvancement<Plane, OBBRSS, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_BOX][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Box, KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Sphere, KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Capsule, KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Cone, KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Cylinder, KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Convex, KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_KDOP16] = &ShapeBVHConservativeAdvancement<Plane, KDOP<16>, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_BOX][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Box, KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Sphere, KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Capsule, KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Cone, KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Cylinder, KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Convex, KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_KDOP18] = &ShapeBVHConservativeAdvancement<Plane, KDOP<18>, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_BOX][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Box, KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Sphere, KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Capsule, KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Cone, KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Cylinder, KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Convex, KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_KDOP24] = &ShapeBVHConservativeAdvancement<Plane, KDOP<24>, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[GEOM_BOX][BV_kIOS] = &ShapeBVHConservativeAdvancement<Box, kIOS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_SPHERE][BV_kIOS] = &ShapeBVHConservativeAdvancement<Sphere, kIOS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CAPSULE][BV_kIOS] = &ShapeBVHConservativeAdvancement<Capsule, kIOS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONE][BV_kIOS] = &ShapeBVHConservativeAdvancement<Cone, kIOS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CYLINDER][BV_kIOS] = &ShapeBVHConservativeAdvancement<Cylinder, kIOS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_CONVEX][BV_kIOS] = &ShapeBVHConservativeAdvancement<Convex, kIOS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[GEOM_PLANE][BV_kIOS] = &ShapeBVHConservativeAdvancement<Plane, kIOS, NarrowPhaseSolver>;
+
+  conservative_advancement_matrix[BV_AABB][BV_AABB] = &BVHConservativeAdvancement<AABB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBB][BV_OBB] = &BVHConservativeAdvancement<OBB, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_RSS][BV_RSS] = &BVHConservativeAdvancement<RSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHConservativeAdvancement<OBBRSS, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP16][BV_KDOP16] = &BVHConservativeAdvancement<KDOP<16>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP18][BV_KDOP18] = &BVHConservativeAdvancement<KDOP<18>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_KDOP24][BV_KDOP24] = &BVHConservativeAdvancement<KDOP<24>, NarrowPhaseSolver>;
+  conservative_advancement_matrix[BV_kIOS][BV_kIOS] = &BVHConservativeAdvancement<kIOS, NarrowPhaseSolver>;
+  
 }
 
 
-template
-int conservativeAdvancement<RSS, MeshConservativeAdvancementTraversalNodeRSS, MeshCollisionTraversalNodeRSS>(const CollisionGeometry* o1,
-                                                                                                             const MotionBase* motion1,
-                                                                                                             const CollisionGeometry* o2,
-                                                                                                             const MotionBase* motion2,
-                                                                                                             const CollisionRequest& request,
-                                                                                                             CollisionResult& result,
-                                                                                                             FCL_REAL& toc);
+template struct ConservativeAdvancementFunctionMatrix<GJKSolver_libccd>;
+template struct ConservativeAdvancementFunctionMatrix<GJKSolver_indep>;
+
+
+
+
+
+
+
 
-template int conservativeAdvancement<OBBRSS, MeshConservativeAdvancementTraversalNodeOBBRSS, MeshCollisionTraversalNodeOBBRSS>(const CollisionGeometry* o1,
-                                                                                                                               const MotionBase* motion1,
-                                                                                                                               const CollisionGeometry* o2,
-                                                                                                                               const MotionBase* motion2,
-                                                                                                                               const CollisionRequest& request,
-                                                                                                                               CollisionResult& result,
-                                                                                                                               FCL_REAL& toc);
 
 }
+
+
diff --git a/src/ccd/motion.cpp b/src/ccd/motion.cpp
index 93124161..016c19b6 100644
--- a/src/ccd/motion.cpp
+++ b/src/ccd/motion.cpp
@@ -115,7 +115,7 @@ FCL_REAL TriangleMotionBoundVisitor::visit(const SplineMotion& motion) const
 }
 
 SplineMotion::SplineMotion(const Vec3f& Td0, const Vec3f& Td1, const Vec3f& Td2, const Vec3f& Td3,
-                           const Vec3f& Rd0, const Vec3f& Rd1, const Vec3f& Rd2, const Vec3f& Rd3)
+                           const Vec3f& Rd0, const Vec3f& Rd1, const Vec3f& Rd2, const Vec3f& Rd3) : MotionBase()
 {
   Td[0] = Td0;
   Td[1] = Td1;
@@ -437,7 +437,7 @@ FCL_REAL TriangleMotionBoundVisitor::visit(const InterpMotion& motion) const
   return mu;  
 }
 
-InterpMotion::InterpMotion()
+InterpMotion::InterpMotion() : MotionBase()
 {
   // Default angular velocity is zero
   angular_axis.setValue(1, 0, 0);
@@ -449,20 +449,20 @@ InterpMotion::InterpMotion()
 }
 
 InterpMotion::InterpMotion(const Matrix3f& R1, const Vec3f& T1,
-                           const Matrix3f& R2, const Vec3f& T2) :
-  tf1(R1, T1),
-  tf2(R2, T2),
-  tf(tf1)
+                           const Matrix3f& R2, const Vec3f& T2) : MotionBase(),
+                                                                  tf1(R1, T1),
+                                                                  tf2(R2, T2),
+                                                                  tf(tf1)
 {
   // Compute the velocities for the motion
   computeVelocity();
 }
 
 
-InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_) :
-  tf1(tf1_),
-  tf2(tf2_),
-  tf(tf1)
+InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_) : MotionBase(),
+                                                                               tf1(tf1_),
+                                                                               tf2(tf2_),
+                                                                               tf(tf1)
 {
   // Compute the velocities for the motion
   computeVelocity();
@@ -470,21 +470,21 @@ InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_) :
 
 InterpMotion::InterpMotion(const Matrix3f& R1, const Vec3f& T1,
                            const Matrix3f& R2, const Vec3f& T2,
-                           const Vec3f& O) :
-  tf1(R1, T1),
-  tf2(R2, T2),
-  tf(tf1),
-  reference_p(O)
+                           const Vec3f& O) : MotionBase(),
+                                             tf1(R1, T1),
+                                             tf2(R2, T2),
+                                             tf(tf1),
+                                             reference_p(O)
 {
   // Compute the velocities for the motion
   computeVelocity();
 }
 
-InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_, const Vec3f& O) :
-  tf1(tf1_),
-  tf2(tf2_),
-  tf(tf1),
-  reference_p(O)
+InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_, const Vec3f& O) : MotionBase(),
+                                                                                               tf1(tf1_),
+                                                                                               tf2(tf2_),
+                                                                                               tf(tf1),
+                                                                                               reference_p(O)
 {
 }
 
@@ -525,6 +525,20 @@ Quaternion3f InterpMotion::absoluteRotation(FCL_REAL dt) const
   return delta_t * tf1.getQuatRotation();
 }
 
+
+/// @brief Compute the motion bound for a bounding volume along a given direction n
+template<>
+FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const TranslationMotion& motion) const
+{
+  return motion.getVelocity().dot(n);
+}
+
+/// @brief Compute the motion bound for a triangle along a given direction n
+FCL_REAL TriangleMotionBoundVisitor::visit(const TranslationMotion& motion) const
+{
+  return motion.getVelocity().dot(n);
+}
+
 template class TBVMotionBoundVisitor<RSS>;
 
 }
diff --git a/src/collision.cpp b/src/collision.cpp
index 68f51f6b..b481e2d4 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -70,7 +70,7 @@ std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
 {
   const NarrowPhaseSolver* nsolver = nsolver_;
   if(!nsolver_)
-    nsolver = new NarrowPhaseSolver();
+    nsolver = new NarrowPhaseSolver();  
 
   const CollisionFunctionMatrix<NarrowPhaseSolver>& looktable = getCollisionFunctionLookTable<NarrowPhaseSolver>();
 
@@ -115,64 +115,47 @@ std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
   return res;
 }
 
-template std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, const GJKSolver_libccd* nsolver, const CollisionRequest& request, CollisionResult& result);
-template std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, const GJKSolver_indep* nsolver, const CollisionRequest& request, CollisionResult& result);
-template std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver_libccd* nsolver, const CollisionRequest& request, CollisionResult& result);
-template std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver_indep* nsolver, const CollisionRequest& request, CollisionResult& result);
-
-
 std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
                     const CollisionRequest& request, CollisionResult& result)
 {
-  GJKSolver_libccd solver;
-  return collide<GJKSolver_libccd>(o1, o2, &solver, request, result);
+  switch(request.gjk_solver_type)
+  {
+  case GST_LIBCCD:
+    {
+      GJKSolver_libccd solver;
+      return collide<GJKSolver_libccd>(o1, o2, &solver, request, result);
+    }
+  case GST_INDEP:
+    {
+      GJKSolver_indep solver;
+      return collide<GJKSolver_indep>(o1, o2, &solver, request, result);
+    }
+  default:
+    return -1; // error
+  }
 }
 
 std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
                     const CollisionGeometry* o2, const Transform3f& tf2,
                     const CollisionRequest& request, CollisionResult& result)
 {
-  GJKSolver_libccd solver;
-  return collide<GJKSolver_libccd>(o1, tf1, o2, tf2, &solver, request, result);
-  // GJKSolver_indep solver;
-  // return collide<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result);
-}
-
-}
-
-#include "fcl/ccd/conservative_advancement.h"
-#include "fcl/traversal/traversal_node_bvhs.h"
-namespace fcl
-{
-std::size_t collide(const ContinuousCollisionObject* o1, const ContinuousCollisionObject* o2,
-                    const CollisionRequest& request,
-                    CollisionResult& result)
-{
-  FCL_REAL toc;
-  return conservativeAdvancement<RSS, MeshConservativeAdvancementTraversalNodeRSS, MeshCollisionTraversalNodeRSS>(
-                                                                                                                  o1->getCollisionGeometry(),
-                                                                                                                  o1->getMotion(),
-                                                                                                                  o2->getCollisionGeometry(),
-                                                                                                                  o2->getMotion(),
-                                                                                                                  request,
-                                                                                                                  result,
-                                                                                                                  toc);
+  switch(request.gjk_solver_type)
+  {
+  case GST_LIBCCD:
+    {
+      GJKSolver_libccd solver;
+      return collide<GJKSolver_libccd>(o1, tf1, o2, tf2, &solver, request, result);
+    }
+  case GST_INDEP:
+    {
+      GJKSolver_indep solver;
+      return collide<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result);
+    }
+  default:
+    std::cerr << "Warning! Invalid GJK solver" << std::endl;
+    return -1; // error
+  }
 }
 
-std::size_t collide(const CollisionGeometry* o1, const MotionBase* motion1,
-                    const CollisionGeometry* o2, const MotionBase* motion2,
-                    const CollisionRequest& request,
-                    CollisionResult& result)
-{
-  FCL_REAL toc;
-  return conservativeAdvancement<RSS, MeshConservativeAdvancementTraversalNodeRSS, MeshCollisionTraversalNodeRSS>(
-                                                                                                                  o1, motion1,
-                                                                                                                  o2, motion2,
-                                                                                                                  request,
-                                                                                                                  result,
-                                                                                                                  toc);  
 }
 
-
-
-}
diff --git a/src/collision_func_matrix.cpp b/src/collision_func_matrix.cpp
index 62f1f45d..0b3c2db9 100644
--- a/src/collision_func_matrix.cpp
+++ b/src/collision_func_matrix.cpp
@@ -203,9 +203,22 @@ std::size_t ShapeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf
   const T_SH1* obj1 = static_cast<const T_SH1*>(o1);
   const T_SH2* obj2 = static_cast<const T_SH2*>(o2);
 
+  if(request.enable_cached_gjk_guess)
+  {
+    nsolver->enableCachedGuess(true);
+    nsolver->setCachedGuess(request.cached_gjk_guess);
+  }
+  else
+  {
+    nsolver->enableCachedGuess(true);
+  }
+
   initialize(node, *obj1, tf1, *obj2, tf2, nsolver, request, result);
   collide(&node);
 
+  if(request.enable_cached_gjk_guess)
+    result.cached_gjk_guess = nsolver->getCachedGuess();
+
   return result.numContacts();
 }
 
diff --git a/src/continuous_collision.cpp b/src/continuous_collision.cpp
new file mode 100644
index 00000000..260145fa
--- /dev/null
+++ b/src/continuous_collision.cpp
@@ -0,0 +1,307 @@
+#include "fcl/collision.h"
+#include "fcl/continuous_collision.h"
+#include "fcl/ccd/motion.h"
+#include "fcl/BVH/BVH_model.h"
+#include "fcl/traversal/traversal_node_bvhs.h"
+#include "fcl/traversal/traversal_node_setup.h"
+#include "fcl/collision_node.h"
+#include "fcl/ccd/conservative_advancement.h"
+#include <iostream>
+
+namespace fcl
+{
+
+template<typename GJKSolver>
+ConservativeAdvancementFunctionMatrix<GJKSolver>& getConservativeAdvancementFunctionLookTable()
+{
+  static ConservativeAdvancementFunctionMatrix<GJKSolver> table;
+  return table;
+}
+
+MotionBase* getMotionBase(const Transform3f& tf_beg, const Transform3f& tf_end, CCDMotionType motion_type)
+{
+  switch(motion_type)
+  {
+  case CCDM_TRANS:
+    return new TranslationMotion(tf_beg, tf_end);
+    break;
+  case CCDM_LINEAR:
+    return new InterpMotion(tf_beg, tf_end);
+    break;
+  case CCDM_SCREW:
+    return new ScrewMotion(tf_beg, tf_end);
+    break;
+  case CCDM_SPLINE:
+    return new SplineMotion(tf_beg, tf_end);
+    break;
+  default:
+    return NULL;
+  }
+}
+
+
+FCL_REAL continuousCollideNaive(const CollisionGeometry* o1, const MotionBase* motion1,
+                                const CollisionGeometry* o2, const MotionBase* motion2,
+                                const ContinuousCollisionRequest& request,
+                                ContinuousCollisionResult& result)
+{
+  std::size_t n_iter = std::min(request.num_max_iterations, (std::size_t)ceil(1 / request.toc_err));
+  Transform3f cur_tf1, cur_tf2;
+  for(std::size_t i = 0; i < n_iter; ++i)
+  {
+    FCL_REAL t = i / (FCL_REAL) (n_iter - 1);
+    motion1->getCurrentTransform(cur_tf1);
+    motion2->getCurrentTransform(cur_tf2);
+
+    CollisionRequest c_request;
+    CollisionResult c_result;
+
+    if(collide(o1, cur_tf1, o2, cur_tf2, c_request, c_result))
+    {
+      result.is_collide = true;
+      result.time_of_contact = t;
+      return t;
+    }
+  }
+
+  return 1.0;
+}
+
+namespace details
+{
+template<typename BV>
+FCL_REAL continuousCollideBVHPolynomial(const CollisionGeometry* o1_, const TranslationMotion* motion1,
+                                        const CollisionGeometry* o2_, const TranslationMotion* motion2,
+                                        const ContinuousCollisionRequest& request,
+                                        ContinuousCollisionResult& result)
+{
+  const BVHModel<BV>* o1__ = static_cast<const BVHModel<BV>*>(o1_);
+  const BVHModel<BV>* o2__ = static_cast<const BVHModel<BV>*>(o2_);
+
+  // ugly, but lets do it now.
+  BVHModel<BV>* o1 = const_cast<BVHModel<BV>*>(o1__);
+  BVHModel<BV>* o2 = const_cast<BVHModel<BV>*>(o2__);
+  std::vector<Vec3f> new_v1(o1->num_vertices);
+  std::vector<Vec3f> new_v2(o2->num_vertices);
+
+  for(std::size_t i = 0; i < new_v1.size(); ++i)
+    new_v1[i] = o1->vertices[i] + motion1->getVelocity();
+  for(std::size_t i = 0; i < new_v2.size(); ++i)
+    new_v2[i] = o2->vertices[i] + motion2->getVelocity();
+
+  o1->beginUpdateModel();
+  o1->updateSubModel(new_v1);
+  o1->endUpdateModel(true, true);
+
+  o2->beginUpdateModel();
+  o2->updateSubModel(new_v2);
+  o2->endUpdateModel(true, true);
+
+  MeshContinuousCollisionTraversalNode<BV> node;
+  CollisionRequest c_request;
+
+  motion1->integrate(0);
+  motion2->integrate(0);
+  Transform3f tf1, tf2;
+  motion1->getCurrentTransform(tf1);
+  motion2->getCurrentTransform(tf2);
+  if(!initialize<BV>(node, *o1, tf1, *o2, tf2, c_request))
+    return -1.0;
+
+  collide(&node);
+
+  result.is_collide = (node.pairs.size() > 0);
+  result.time_of_contact = node.time_of_contact;
+
+  return result.time_of_contact;
+}
+
+}
+
+FCL_REAL continuousCollideBVHPolynomial(const CollisionGeometry* o1, const TranslationMotion* motion1,
+                                        const CollisionGeometry* o2, const TranslationMotion* motion2,
+                                        const ContinuousCollisionRequest& request,
+                                        ContinuousCollisionResult& result)
+{
+  switch(o1->getNodeType())
+  {
+  case BV_AABB:
+    if(o2->getNodeType() == BV_AABB)
+      return details::continuousCollideBVHPolynomial<AABB>(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_OBB:
+    if(o2->getNodeType() == BV_OBB)
+      return details::continuousCollideBVHPolynomial<OBB>(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_RSS:
+    if(o2->getNodeType() == BV_RSS)
+      return details::continuousCollideBVHPolynomial<RSS>(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_kIOS:
+    if(o2->getNodeType() == BV_kIOS)
+      return details::continuousCollideBVHPolynomial<kIOS>(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_OBBRSS:
+    if(o2->getNodeType() == BV_OBBRSS)
+      return details::continuousCollideBVHPolynomial<OBBRSS>(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_KDOP16:
+    if(o2->getNodeType() == BV_KDOP16)
+      return details::continuousCollideBVHPolynomial<KDOP<16> >(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_KDOP18:
+    if(o2->getNodeType() == BV_KDOP18)
+      return details::continuousCollideBVHPolynomial<KDOP<18> >(o1, motion1, o2, motion2, request, result);
+    break;
+  case BV_KDOP24:
+    if(o2->getNodeType() == BV_KDOP24)
+      return details::continuousCollideBVHPolynomial<KDOP<24> >(o1, motion1, o2, motion2, request, result);
+    break;
+  default:
+    ;
+  }
+
+  std::cerr << "Warning: BV type not supported by polynomial solver CCD" << std::endl;
+
+  return -1;
+}
+
+namespace details
+{
+
+template<typename NarrowPhaseSolver>
+FCL_REAL continuousCollideConservativeAdvancement(const CollisionGeometry* o1, const MotionBase* motion1,
+                                                  const CollisionGeometry* o2, const MotionBase* motion2,
+                                                  const NarrowPhaseSolver* nsolver_,
+                                                  const ContinuousCollisionRequest& request,
+                                                  ContinuousCollisionResult& result)
+{
+  const NarrowPhaseSolver* nsolver = nsolver_;
+  if(!nsolver_)
+    nsolver = new NarrowPhaseSolver();
+
+  const ConservativeAdvancementFunctionMatrix<NarrowPhaseSolver>& looktable = getConservativeAdvancementFunctionLookTable<NarrowPhaseSolver>();
+
+  NODE_TYPE node_type1 = o1->getNodeType();
+  NODE_TYPE node_type2 = o2->getNodeType();
+
+  FCL_REAL res = -1;
+  
+  if(!looktable.conservative_advancement_matrix[node_type1][node_type2])
+  {
+    std::cerr << "Warning: collision function between node type " << node_type1 << " and node type " << node_type2 << " is not supported"<< std::endl;
+  }
+  else
+  {
+    res = looktable.conservative_advancement_matrix[node_type1][node_type2](o1, motion1, o2, motion2, nsolver, request, result);
+  }
+
+  if(!nsolver_)
+    delete nsolver;
+
+  return res;
+}
+
+}
+
+
+FCL_REAL continuousCollideConservativeAdvancement(const CollisionGeometry* o1, const MotionBase* motion1,
+                                                  const CollisionGeometry* o2, const MotionBase* motion2,
+                                                  const ContinuousCollisionRequest& request,
+                                                  ContinuousCollisionResult& result)
+{
+  switch(request.gjk_solver_type)
+  {
+  case GST_LIBCCD:
+    {
+      GJKSolver_libccd solver;
+      return details::continuousCollideConservativeAdvancement(o1, motion1, o2, motion2, &solver, request, result);
+    }
+  case GST_INDEP:
+    {
+      GJKSolver_indep solver;
+      return details::continuousCollideConservativeAdvancement(o1, motion1, o2, motion2, &solver, request, result);
+    }
+  default:
+    return -1;
+  }
+}
+
+  
+FCL_REAL continuousCollide(const CollisionGeometry* o1, const MotionBase* motion1,
+                           const CollisionGeometry* o2, const MotionBase* motion2,
+                           const ContinuousCollisionRequest& request,
+                           ContinuousCollisionResult& result)
+{
+  switch(request.ccd_solver_type)
+  {
+  case CCDC_NAIVE:
+    return continuousCollideNaive(o1, motion1,
+                                  o2, motion2,
+                                  request,
+                                  result);
+    break;
+  case CCDC_CONSERVATIVE_ADVANCEMENT:
+    return continuousCollideConservativeAdvancement(o1, motion1,
+                                                    o2, motion2,
+                                                    request,
+                                                    result);
+    break;
+  case CCDC_RAY_SHOOTING:
+    if(o1->getObjectType() == OT_GEOM && o2->getObjectType() == OT_GEOM && request.ccd_motion_type == CCDM_TRANS)
+    {
+      
+    }
+    else
+      std::cerr << "Warning! Invalid continuous collision setting" << std::endl;
+    break;
+  case CCDC_POLYNOMIAL_SOLVER:
+    if(o1->getObjectType() == OT_BVH && o2->getObjectType() == OT_BVH && request.ccd_motion_type == CCDM_TRANS)
+    {
+      return continuousCollideBVHPolynomial(o1, (const TranslationMotion*)motion1,
+                                            o2, (const TranslationMotion*)motion2,
+                                            request, result);
+    }
+    else
+      std::cerr << "Warning! Invalid continuous collision checking" << std::endl;
+    break;
+  default:
+    std::cerr << "Warning! Invalid continuous collision setting" << std::endl;
+  }
+
+  return -1;
+}
+
+FCL_REAL continuousCollide(const CollisionGeometry* o1, const Transform3f& tf1_beg, const Transform3f& tf1_end,
+                           const CollisionGeometry* o2, const Transform3f& tf2_beg, const Transform3f& tf2_end,
+                           const ContinuousCollisionRequest& request,
+                           ContinuousCollisionResult& result)
+{
+  MotionBase* motion1 = getMotionBase(tf1_beg, tf1_end, request.ccd_motion_type);
+  MotionBase* motion2 = getMotionBase(tf2_beg, tf2_end, request.ccd_motion_type);
+
+  return continuousCollide(o1, motion1, o2, motion2, request, result);
+}
+
+
+FCL_REAL continuousCollide(const CollisionObject* o1, const Transform3f& tf1_end,
+                           const CollisionObject* o2, const Transform3f& tf2_end,
+                           const ContinuousCollisionRequest& request,
+                           ContinuousCollisionResult& result)
+{
+  return continuousCollide(o1->getCollisionGeometry(), o1->getTransform(), tf1_end,
+                           o2->getCollisionGeometry(), o2->getTransform(), tf2_end,
+                           request, result);
+}
+
+
+FCL_REAL collide(const ContinuousCollisionObject* o1, const ContinuousCollisionObject* o2,
+                 const ContinuousCollisionRequest& request,
+                 ContinuousCollisionResult& result)
+{
+  return continuousCollide(o1->getCollisionGeometry(), o1->getMotion(),
+                           o2->getCollisionGeometry(), o2->getMotion(),
+                           request, result);
+}
+
+}
diff --git a/src/distance.cpp b/src/distance.cpp
index fde2650f..d20da2f5 100644
--- a/src/distance.cpp
+++ b/src/distance.cpp
@@ -106,25 +106,45 @@ FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1,
   return res;
 }
 
-template FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const GJKSolver_libccd* nsolver, const DistanceRequest& request, DistanceResult& result);
-template FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const GJKSolver_indep* nsolver, const DistanceRequest& request, DistanceResult& result);
-template FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver_libccd* nsolver, const DistanceRequest& request, DistanceResult& result);
-template FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver_indep* nsolver, const DistanceRequest& request, DistanceResult& result);
 
 FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const DistanceRequest& request, DistanceResult& result)
 {
-  GJKSolver_libccd solver;
-  return distance<GJKSolver_libccd>(o1, o2, &solver, request, result);
+  switch(request.gjk_solver_type)
+  {
+  case GST_LIBCCD:
+    {
+      GJKSolver_libccd solver;
+      return distance<GJKSolver_libccd>(o1, o2, &solver, request, result);
+    }
+  case GST_INDEP:
+    {
+      GJKSolver_indep solver;
+      return distance<GJKSolver_indep>(o1, o2, &solver, request, result);
+    }
+  default:
+    return -1; // error
+  }
 }
 
 FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1,
                   const CollisionGeometry* o2, const Transform3f& tf2,
                   const DistanceRequest& request, DistanceResult& result)
 {
-  GJKSolver_libccd solver;
-  return distance<GJKSolver_libccd>(o1, tf1, o2, tf2, &solver, request, result);
-  // GJKSolver_indep solver;
-  // return distance<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result);
+  switch(request.gjk_solver_type)
+  {
+  case GST_LIBCCD:
+    {
+      GJKSolver_libccd solver;
+      return distance<GJKSolver_libccd>(o1, tf1, o2, tf2, &solver, request, result);
+    }
+  case GST_INDEP:
+    {
+      GJKSolver_indep solver;
+      return distance<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result);
+    }
+  default:
+    return -1;
+  }
 }
 
 
diff --git a/src/intersect.cpp b/src/intersect.cpp
index efce14ba..791d0209 100644
--- a/src/intersect.cpp
+++ b/src/intersect.cpp
@@ -1533,6 +1533,20 @@ FCL_REAL TriangleDistance::triDistance(const Vec3f S[3], const Vec3f T[3],
   return triDistance(S, T_transformed, P, Q);
 }
 
+
+FCL_REAL TriangleDistance::triDistance(const Vec3f S[3], const Vec3f T[3],
+                                       const Transform3f& tf,
+                                       Vec3f& P, Vec3f& Q)
+{
+  Vec3f T_transformed[3];
+  T_transformed[0] = tf.transform(T[0]);
+  T_transformed[1] = tf.transform(T[1]);
+  T_transformed[2] = tf.transform(T[2]);
+
+  return triDistance(S, T_transformed, P, Q);
+}
+
+
 FCL_REAL TriangleDistance::triDistance(const Vec3f& S1, const Vec3f& S2, const Vec3f& S3,
                                        const Vec3f& T1, const Vec3f& T2, const Vec3f& T3,
                                        const Matrix3f& R, const Vec3f& Tl,
@@ -1544,4 +1558,264 @@ FCL_REAL TriangleDistance::triDistance(const Vec3f& S1, const Vec3f& S2, const V
   return triDistance(S1, S2, S3, T1_transformed, T2_transformed, T3_transformed, P, Q);
 }
 
+FCL_REAL TriangleDistance::triDistance(const Vec3f& S1, const Vec3f& S2, const Vec3f& S3,
+                                       const Vec3f& T1, const Vec3f& T2, const Vec3f& T3,
+                                       const Transform3f& tf,
+                                       Vec3f& P, Vec3f& Q)
+{
+  Vec3f T1_transformed = tf.transform(T1);
+  Vec3f T2_transformed = tf.transform(T2);
+  Vec3f T3_transformed = tf.transform(T3);
+  return triDistance(S1, S2, S3, T1_transformed, T2_transformed, T3_transformed, P, Q);
+}
+
+
+
+
+
+Project::ProjectResult Project::projectLine(const Vec3f& a, const Vec3f& b, const Vec3f& p)
+{
+  ProjectResult res;
+
+  const Vec3f d = b - a;
+  const FCL_REAL l = d.sqrLength();
+
+  if(l > 0)
+  {
+    const FCL_REAL t = (p - a).dot(d);
+    res.parameterization[1] = (t >= l) ? 1 : ((t <= 0) ? 0 : (t / l));
+    res.parameterization[0] = 1 - res.parameterization[1];
+    if(t >= l) { res.sqr_distance = (p - b).sqrLength(); res.encode = 2; /* 0x10 */ }
+    else if(t <= 0) { res.sqr_distance = (p - a).sqrLength(); res.encode = 1; /* 0x01 */ }
+    else { res.sqr_distance = (a + d * res.parameterization[1] - p).sqrLength(); res.encode = 3; /* 0x00 */ }
+  }
+
+  return res;
+}
+
+Project::ProjectResult Project::projectTriangle(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& p)
+{
+  ProjectResult res;
+	
+  static const size_t nexti[3] = {1, 2, 0};
+  const Vec3f* vt[] = {&a, &b, &c};
+  const Vec3f dl[] = {a - b, b - c, c - a};
+  const Vec3f& n = dl[0].cross(dl[1]);
+  const FCL_REAL l = n.sqrLength();
+	
+  if(l > 0)
+  {
+    FCL_REAL mindist = -1;
+    for(size_t i = 0; i < 3; ++i)
+    {
+      if((*vt[i] - p).dot(dl[i].cross(n)) > 0) // origin is to the outside part of the triangle edge, then the optimal can only be on the edge
+      {
+        size_t j = nexti[i];
+        ProjectResult res_line = projectLine(*vt[i], *vt[j], p);
+
+        if(mindist < 0 || res_line.sqr_distance < mindist)
+        {
+          mindist = res_line.sqr_distance;
+          res.encode = static_cast<size_t>(((res_line.encode&1)?1<<i:0) + ((res_line.encode&2)?1<<j:0));
+          res.parameterization[i] = res_line.parameterization[0];
+          res.parameterization[j] = res_line.parameterization[1];
+          res.parameterization[nexti[j]] = 0;
+        }
+      }
+    }
+    
+    if(mindist < 0) // the origin project is within the triangle
+    {
+      FCL_REAL d = (a - p).dot(n);
+      FCL_REAL s = sqrt(l);
+      Vec3f p_to_project = n * (d / l);
+      mindist = p_to_project.sqrLength();
+      res.encode = 7; // m = 0x111
+      res.parameterization[0] = dl[1].cross(b - p -p_to_project).length() / s;
+      res.parameterization[1] = dl[2].cross(c - p -p_to_project).length() / s;
+      res.parameterization[2] = 1 - res.parameterization[0] - res.parameterization[1];
+    }
+
+    res.sqr_distance = mindist;
+  }
+
+  return  res;
+
+}
+
+Project::ProjectResult Project::projectTetrahedra(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d, const Vec3f& p)
+{
+  ProjectResult res;
+
+  static const size_t nexti[] = {1, 2, 0};
+  const Vec3f* vt[] = {&a, &b, &c, &d};
+  const Vec3f dl[3] = {a-d, b-d, c-d};
+  FCL_REAL vl = triple(dl[0], dl[1], dl[2]); 
+  bool ng = (vl * (a-p).dot((b-c).cross(a-b))) <= 0;
+  if(ng && std::abs(vl) > 0) // abs(vl) == 0, the tetrahedron is degenerated; if ng is false, then the last vertex in the tetrahedron does not grow toward the origin (in fact origin is on the other side of the abc face)
+  {
+    FCL_REAL mindist = -1;
+
+    for(size_t i = 0; i < 3; ++i)
+    {
+      size_t j = nexti[i];
+      FCL_REAL s = vl * (d-p).dot(dl[i].cross(dl[j]));
+      if(s > 0) // the origin is to the outside part of a triangle face, then the optimal can only be on the triangle face
+      {
+        ProjectResult res_triangle = projectTriangle(*vt[i], *vt[j], d, p);
+        if(mindist < 0 || res_triangle.sqr_distance < mindist)
+        {
+          mindist = res_triangle.sqr_distance;
+          res.encode = static_cast<size_t>( (res_triangle.encode&1?1<<i:0) + (res_triangle.encode&2?1<<j:0) + (res_triangle.encode&4?8:0) );
+          res.parameterization[i] = res_triangle.parameterization[0];
+          res.parameterization[j] = res_triangle.parameterization[1];
+          res.parameterization[nexti[j]] = 0;
+          res.parameterization[3] = res_triangle.parameterization[2];
+        }
+      }
+    }
+
+    if(mindist < 0)
+    {
+      mindist = 0;
+      res.encode = 15;
+      res.parameterization[0] = triple(c - p, b - p, d - p) / vl;
+      res.parameterization[1] = triple(a - p, c - p, d - p) / vl;
+      res.parameterization[2] = triple(b - p, a - p, d - p) / vl;
+      res.parameterization[3] = 1 - (res.parameterization[0] + res.parameterization[1] + res.parameterization[2]);
+    }
+
+    res.sqr_distance = mindist;
+  }
+  else if(!ng)
+  {
+    res = projectTriangle(a, b, c, p);
+    res.parameterization[3] = 0;
+  }
+  return res;
+}
+
+Project::ProjectResult Project::projectLineOrigin(const Vec3f& a, const Vec3f& b)
+{
+  ProjectResult res;
+
+  const Vec3f d = b - a;
+  const FCL_REAL l = d.sqrLength();
+
+  if(l > 0)
+  {
+    const FCL_REAL t = - a.dot(d);
+    res.parameterization[1] = (t >= l) ? 1 : ((t <= 0) ? 0 : (t / l));
+    res.parameterization[0] = 1 - res.parameterization[1];
+    if(t >= l) { res.sqr_distance = b.sqrLength(); res.encode = 2; /* 0x10 */ }
+    else if(t <= 0) { res.sqr_distance = a.sqrLength(); res.encode = 1; /* 0x01 */ }
+    else { res.sqr_distance = (a + d * res.parameterization[1]).sqrLength(); res.encode = 3; /* 0x00 */ }
+  }
+
+  return res;
+}
+
+Project::ProjectResult Project::projectTriangleOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c)
+{
+  ProjectResult res;
+	
+  static const size_t nexti[3] = {1, 2, 0};
+  const Vec3f* vt[] = {&a, &b, &c};
+  const Vec3f dl[] = {a - b, b - c, c - a};
+  const Vec3f& n = dl[0].cross(dl[1]);
+  const FCL_REAL l = n.sqrLength();
+	
+  if(l > 0)
+  {
+    FCL_REAL mindist = -1;
+    for(size_t i = 0; i < 3; ++i)
+    {
+      if(vt[i]->dot(dl[i].cross(n)) > 0) // origin is to the outside part of the triangle edge, then the optimal can only be on the edge
+      {
+        size_t j = nexti[i];
+        ProjectResult res_line = projectLineOrigin(*vt[i], *vt[j]);
+
+        if(mindist < 0 || res_line.sqr_distance < mindist)
+        {
+          mindist = res_line.sqr_distance;
+          res.encode = static_cast<size_t>(((res_line.encode&1)?1<<i:0) + ((res_line.encode&2)?1<<j:0));
+          res.parameterization[i] = res_line.parameterization[0];
+          res.parameterization[j] = res_line.parameterization[1];
+          res.parameterization[nexti[j]] = 0;
+        }
+      }
+    }
+    
+    if(mindist < 0) // the origin project is within the triangle
+    {
+      FCL_REAL d = a.dot(n);
+      FCL_REAL s = sqrt(l);
+      Vec3f o_to_project = n * (d / l);
+      mindist = o_to_project.sqrLength();
+      res.encode = 7; // m = 0x111
+      res.parameterization[0] = dl[1].cross(b - o_to_project).length() / s;
+      res.parameterization[1] = dl[2].cross(c - o_to_project).length() / s;
+      res.parameterization[2] = 1 - res.parameterization[0] - res.parameterization[1];
+    }
+
+    res.sqr_distance = mindist;
+  }
+
+  return  res;
+
+}
+
+Project::ProjectResult Project::projectTetrahedraOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d)
+{
+  ProjectResult res;
+
+  static const size_t nexti[] = {1, 2, 0};
+  const Vec3f* vt[] = {&a, &b, &c, &d};
+  const Vec3f dl[3] = {a-d, b-d, c-d};
+  FCL_REAL vl = triple(dl[0], dl[1], dl[2]); 
+  bool ng = (vl * a.dot((b-c).cross(a-b))) <= 0;
+  if(ng && std::abs(vl) > 0) // abs(vl) == 0, the tetrahedron is degenerated; if ng is false, then the last vertex in the tetrahedron does not grow toward the origin (in fact origin is on the other side of the abc face)
+  {
+    FCL_REAL mindist = -1;
+
+    for(size_t i = 0; i < 3; ++i)
+    {
+      size_t j = nexti[i];
+      FCL_REAL s = vl * d.dot(dl[i].cross(dl[j]));
+      if(s > 0) // the origin is to the outside part of a triangle face, then the optimal can only be on the triangle face
+      {
+        ProjectResult res_triangle = projectTriangleOrigin(*vt[i], *vt[j], d);
+        if(mindist < 0 || res_triangle.sqr_distance < mindist)
+        {
+          mindist = res_triangle.sqr_distance;
+          res.encode = static_cast<size_t>( (res_triangle.encode&1?1<<i:0) + (res_triangle.encode&2?1<<j:0) + (res_triangle.encode&4?8:0) );
+          res.parameterization[i] = res_triangle.parameterization[0];
+          res.parameterization[j] = res_triangle.parameterization[1];
+          res.parameterization[nexti[j]] = 0;
+          res.parameterization[3] = res_triangle.parameterization[2];
+        }
+      }
+    }
+
+    if(mindist < 0)
+    {
+      mindist = 0;
+      res.encode = 15;
+      res.parameterization[0] = triple(c, b, d) / vl;
+      res.parameterization[1] = triple(a, c, d) / vl;
+      res.parameterization[2] = triple(b, a, d) / vl;
+      res.parameterization[3] = 1 - (res.parameterization[0] + res.parameterization[1] + res.parameterization[2]);
+    }
+
+    res.sqr_distance = mindist;
+  }
+  else if(!ng)
+  {
+    res = projectTriangleOrigin(a, b, c);
+    res.parameterization[3] = 0;
+  }
+  return res;
+}
+
+
 }
diff --git a/src/narrowphase/gjk.cpp b/src/narrowphase/gjk.cpp
index 1df32317..8be837f1 100644
--- a/src/narrowphase/gjk.cpp
+++ b/src/narrowphase/gjk.cpp
@@ -35,6 +35,7 @@
 /** \author Jia Pan */
 
 #include "fcl/narrowphase/gjk.h"
+#include "fcl/intersect.h"
 
 namespace fcl
 {
@@ -48,7 +49,7 @@ Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir)
   {
   case GEOM_TRIANGLE:
     {
-      const Triangle2* triangle = static_cast<const Triangle2*>(shape);
+      const TriangleP* triangle = static_cast<const TriangleP*>(shape);
       FCL_REAL dota = dir.dot(triangle->a);
       FCL_REAL dotb = dir.dot(triangle->b);
       FCL_REAL dotc = dir.dot(triangle->c);
@@ -154,10 +155,7 @@ Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir)
     }
     break;
   case GEOM_PLANE:
-    {
-      return Vec3f(0, 0, 0);
-    }
-    break;
+	break;
   default:
     ; // nothing
   }
@@ -165,116 +163,6 @@ Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir)
   return Vec3f(0, 0, 0);
 }
 
-
-FCL_REAL projectOrigin(const Vec3f& a, const Vec3f& b, FCL_REAL* w, size_t& m)
-{
-  const Vec3f d = b - a;
-  const FCL_REAL l = d.sqrLength();
-  if(l > 0)
-  {
-    const FCL_REAL t(l > 0 ? - a.dot(d) / l : 0);
-    if(t >= 1) { w[0] = 0; w[1] = 1; m = 2; return b.sqrLength(); } // m = 0x10 
-    else if(t <= 0) { w[0] = 1; w[1] = 0; m = 1; return a.sqrLength(); } // m = 0x01
-    else { w[0] = 1 - (w[1] = t); m = 3; return (a + d * t).sqrLength(); } // m = 0x11
-  }
-
-  return -1;
-}
-
-FCL_REAL projectOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c, FCL_REAL* w, size_t& m)
-{
-  static const size_t nexti[3] = {1, 2, 0};
-  const Vec3f* vt[] = {&a, &b, &c};
-  const Vec3f dl[] = {a - b, b - c, c - a};
-  const Vec3f& n = dl[0].cross(dl[1]);
-  const FCL_REAL l = n.sqrLength();
-
-  if(l > 0)
-  {
-    FCL_REAL mindist = -1;
-    FCL_REAL subw[2] = {0, 0};
-    size_t subm = 0;
-    for(size_t i = 0; i < 3; ++i)
-    {
-      if(vt[i]->dot(dl[i].cross(n)) > 0) // origin is to the outside part of the triangle edge, then the optimal can only be on the edge
-      {
-        size_t j = nexti[i];
-        FCL_REAL subd = projectOrigin(*vt[i], *vt[j], subw, subm);
-        if(mindist < 0 || subd < mindist)
-        {
-          mindist = subd;
-          m = static_cast<size_t>(((subm&1)?1<<i:0) + ((subm&2)?1<<j:0));
-          w[i] = subw[0];
-          w[j] = subw[1];
-          w[nexti[j]] = 0;
-        }
-      }
-    }
-    
-    if(mindist < 0) // the origin project is within the triangle
-    {
-      FCL_REAL d = a.dot(n);
-      FCL_REAL s = sqrt(l);
-      Vec3f p = n * (d / l);
-      mindist = p.sqrLength();
-      m = 7; // m = 0x111
-      w[0] = dl[1].cross(b-p).length() / s;
-      w[1] = dl[2].cross(c-p).length() / s;
-      w[2] = 1 - (w[0] + w[1]);
-    }
-
-    return mindist;
-  }
-  return -1;
-}
-
-FCL_REAL projectOrigin(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d, FCL_REAL* w, size_t& m)
-{
-  static const size_t nexti[] = {1, 2, 0};
-  const Vec3f* vt[] = {&a, &b, &c, &d};
-  const Vec3f dl[3] = {a-d, b-d, c-d};
-  FCL_REAL vl = triple(dl[0], dl[1], dl[2]); 
-  bool ng = (vl * a.dot((b-c).cross(a-b))) <= 0;
-  if(ng && std::abs(vl) > 0) // abs(vl) == 0, the tetrahedron is degenerated; if ng is false, then the last vertex in the tetrahedron does not grow toward the origin (in fact origin is on the other side of the abc face)
-  {
-    FCL_REAL mindist = -1;
-    FCL_REAL subw[3] = {0, 0, 0};
-    size_t subm = 0;
-    for(size_t i = 0; i < 3; ++i)
-    {
-      size_t j = nexti[i];
-      FCL_REAL s = vl * d.dot(dl[i].cross(dl[j]));
-      if(s > 0) // the origin is to the outside part of a triangle face, then the optimal can only be on the triangle face
-      {
-        FCL_REAL subd = projectOrigin(*vt[i], *vt[j], d, subw, subm);
-        if(mindist < 0 || subd < mindist)
-        {
-          mindist = subd;
-          m = static_cast<size_t>( (subm&1?1<<i:0) + (subm&2?1<<j:0) + (subm&4?8:0) );
-          w[i] = subw[0];
-          w[j] = subw[1];
-          w[nexti[j]] = 0;
-          w[3] = subw[2];
-        }
-      }
-    }
-
-    if(mindist < 0)
-    {
-      mindist = 0;
-      m = 15;
-      w[0] = triple(c, b, d) / vl;
-      w[1] = triple(a, c, d) / vl;
-      w[2] = triple(b, a, d) / vl;
-      w[3] = 1 - (w[0] + w[1] + w[2]);
-    }
-    
-    return mindist;
-  }
-  return -1;
-}
-
-
 void GJK::initialize()
 {
   ray = Vec3f();
@@ -282,12 +170,19 @@ void GJK::initialize()
   status = Failed;
   current = 0;
   distance = 0.0;
+  simplex = NULL;
 }
 
+
+Vec3f GJK::getGuessFromSimplex() const
+{
+  return ray;
+}
+
+
 GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
 {
   size_t iterations = 0;
-  FCL_REAL sqdist = 0;
   FCL_REAL alpha = 0;
   Vec3f lastw[4];
   size_t clastw = 0;
@@ -304,29 +199,29 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
   distance = 0.0;
   simplices[0].rank = 0;
   ray = guess;
-    
-  FCL_REAL sqrl = ray.sqrLength();
-  appendVertex(simplices[0], (sqrl>0) ? -ray : Vec3f(1, 0, 0));
+
+  appendVertex(simplices[0], (ray.sqrLength() > 0) ? -ray : Vec3f(1, 0, 0));
   simplices[0].p[0] = 1;
   ray = simplices[0].c[0]->w;
-  sqdist = sqrl;
-  lastw[0] = lastw[1] = lastw[2] = lastw[3] = ray;
+  lastw[0] = lastw[1] = lastw[2] = lastw[3] = ray; // cache previous support points, the new support point will compare with it to avoid too close support points
 
   do
   {
     size_t next = 1 - current;
     Simplex& curr_simplex = simplices[current];
     Simplex& next_simplex = simplices[next];
-      
-    FCL_REAL rl = ray.sqrLength();
-    if(rl < tolerance) // means origin is near the face of original simplex, return touch
+
+    // check A: when origin is near the existing simplex, stop
+    FCL_REAL rl = ray.length();
+    if(rl < tolerance) // mean origin is near the face of original simplex, return touch
     {
       status = Inside;
       break;
     }
 
     appendVertex(curr_simplex, -ray); // see below, ray points away from origin
-      
+
+    // check B: when the new support point is close to previous support points, stop (as the new simplex is degenerated)
     Vec3f& w = curr_simplex.c[curr_simplex.rank - 1]->w;
     bool found = false;
     for(size_t i = 0; i < 4; ++i)
@@ -347,7 +242,7 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
       lastw[clastw = (clastw+1)&3] = w;
     }
 
-    // check for termination, from bullet
+    // check C: when the new support point is close to the sub-simplex where the ray point lies, stop (as the new simplex again is degenerated)
     FCL_REAL omega = ray.dot(w) / rl;
     alpha = std::max(alpha, omega);
     if((rl - alpha) - tolerance * rl <= 0)
@@ -356,36 +251,34 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
       break;
     }
 
-    // reduce simplex and decide the extend direction
-    FCL_REAL weights[4];
-    size_t mask = 0; // decide the simplex vertices that compose the minimal distance
+    Project::ProjectResult project_res;
     switch(curr_simplex.rank)
     {
     case 2:
-      sqdist = projectOrigin(curr_simplex.c[0]->w, curr_simplex.c[1]->w, weights, mask); break;
+      project_res = Project::projectLineOrigin(curr_simplex.c[0]->w, curr_simplex.c[1]->w); break;
     case 3:
-      sqdist = projectOrigin(curr_simplex.c[0]->w, curr_simplex.c[1]->w, curr_simplex.c[2]->w, weights, mask); break;
+      project_res = Project::projectTriangleOrigin(curr_simplex.c[0]->w, curr_simplex.c[1]->w, curr_simplex.c[2]->w); break;
     case 4:
-      sqdist = projectOrigin(curr_simplex.c[0]->w, curr_simplex.c[1]->w, curr_simplex.c[2]->w, curr_simplex.c[3]->w, weights, mask); break;
+      project_res = Project::projectTetrahedraOrigin(curr_simplex.c[0]->w, curr_simplex.c[1]->w, curr_simplex.c[2]->w, curr_simplex.c[3]->w); break;
     }
       
-    if(sqdist >= 0)
+    if(project_res.sqr_distance >= 0)
     {
       next_simplex.rank = 0;
       ray = Vec3f();
       current = next;
       for(size_t i = 0; i < curr_simplex.rank; ++i)
       {
-        if(mask & (1 << i))
+        if(project_res.encode & (1 << i))
         {
           next_simplex.c[next_simplex.rank] = curr_simplex.c[i];
-          next_simplex.p[next_simplex.rank++] = weights[i];
-          ray += curr_simplex.c[i]->w * weights[i];
+          next_simplex.p[next_simplex.rank++] = project_res.parameterization[i]; // weights[i];
+          ray += curr_simplex.c[i]->w * project_res.parameterization[i]; // weights[i];
         }
         else
           free_v[nfree++] = curr_simplex.c[i];
       }
-      if(mask == 15) status = Inside; // the origin is within the 4-simplex, collision
+      if(project_res.encode == 15) status = Inside; // the origin is within the 4-simplex, collision
     }
     else
     {
@@ -413,6 +306,12 @@ void GJK::getSupport(const Vec3f& d, SimplexV& sv) const
   sv.w = shape.support(sv.d);
 }
 
+void GJK::getSupport(const Vec3f& d, const Vec3f& v, SimplexV& sv) const
+{
+  sv.d = normalize(d);
+  sv.w = shape.support(sv.d, v);
+}
+
 void GJK::removeVertex(Simplex& simplex)
 {
   free_v[nfree++] = simplex.c[--simplex.rank];
diff --git a/src/narrowphase/gjk_libccd.cpp b/src/narrowphase/gjk_libccd.cpp
index 2b18391c..d46689aa 100644
--- a/src/narrowphase/gjk_libccd.cpp
+++ b/src/narrowphase/gjk_libccd.cpp
@@ -38,6 +38,7 @@
 #include "fcl/narrowphase/gjk_libccd.h"
 #include <ccd/simplex.h>
 #include <ccd/vec3.h>
+#include <ccd/ccd.h>
 
 namespace fcl
 {
@@ -87,16 +88,53 @@ struct ccd_triangle_t : public ccd_obj_t
   ccd_vec3_t c;
 };
 
-/*
-static void tripleCross(const ccd_vec3_t* a, const ccd_vec3_t* b, 
-                        const ccd_vec3_t* c, ccd_vec3_t* d)
+namespace libccd_extension
+{
+
+
+static ccd_real_t simplexReduceToTriangle(ccd_simplex_t *simplex,
+                                          ccd_real_t dist,
+                                          ccd_vec3_t *best_witness)
+{
+  ccd_real_t newdist;
+  ccd_vec3_t witness;
+  int best = -1;
+  int i;
+
+  // try the fourth point in all three positions
+  for (i = 0; i < 3; i++){
+    newdist = ccdVec3PointTriDist2(ccd_vec3_origin,
+                                   &ccdSimplexPoint(simplex, (i == 0 ? 3 : 0))->v,
+                                   &ccdSimplexPoint(simplex, (i == 1 ? 3 : 1))->v,
+                                   &ccdSimplexPoint(simplex, (i == 2 ? 3 : 2))->v,
+                                   &witness);
+    newdist = CCD_SQRT(newdist);
+
+    // record the best triangle
+    if (newdist < dist){
+      dist = newdist;
+      best = i;
+      ccdVec3Copy(best_witness, &witness);
+    }
+  }
+
+  if (best >= 0){
+    ccdSimplexSet(simplex, best, ccdSimplexPoint(simplex, 3));
+  }
+  ccdSimplexSetSize(simplex, 3);
+
+  return dist;
+}
+
+_ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b,
+                             const ccd_vec3_t *c, ccd_vec3_t *d)
 {
   ccd_vec3_t e;
   ccdVec3Cross(&e, a, b);
   ccdVec3Cross(d, &e, c);
 }
 
-static int doSimplex2Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* dist)
+static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir)
 {
   const ccd_support_t *A, *B;
   ccd_vec3_t AB, AO, tmp;
@@ -112,28 +150,22 @@ static int doSimplex2Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
   ccdVec3Copy(&AO, &A->v);
   ccdVec3Scale(&AO, -CCD_ONE);
 
-  // dot product AB . -AO
+  // dot product AB . AO
   dot = ccdVec3Dot(&AB, &AO);
 
   // check if origin doesn't lie on AB segment
   ccdVec3Cross(&tmp, &AB, &AO);
-  if(ccdIsZero(ccdVec3Len2(&tmp)) && dot > CCD_ZERO)
-  {
+  if (ccdIsZero(ccdVec3Len2(&tmp)) && dot > CCD_ZERO){
     return 1;
   }
 
-  *dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, &A->v, &B->v, NULL);
-
   // check if origin is in area where AB segment is
-  if(ccdIsZero(dot) || dot < CCD_ZERO)
-  {
+  if (ccdIsZero(dot) || dot < CCD_ZERO){
     // origin is in outside are of A
     ccdSimplexSet(simplex, 0, A);
     ccdSimplexSetSize(simplex, 1);
     ccdVec3Copy(dir, &AO);
-  }
-  else
-  {
+  }else{
     // origin is in area where AB segment is
 
     // keep simplex untouched and set direction to
@@ -144,11 +176,11 @@ static int doSimplex2Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
   return 0;
 }
 
-static int doSimplex3Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* dist)
+static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir)
 {
   const ccd_support_t *A, *B, *C;
   ccd_vec3_t AO, AB, AC, ABC, tmp;
-  ccd_real_t dot;
+  ccd_real_t dot, dist;
 
   // get last added as A
   A = ccdSimplexLast(simplex);
@@ -157,16 +189,14 @@ static int doSimplex3Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
   C = ccdSimplexPoint(simplex, 0);
 
   // check touching contact
-  *dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL);
-  if(ccdIsZero(*dist))
-  {
+  dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL);
+  if (ccdIsZero(dist)){
     return 1;
   }
 
   // check if triangle is really triangle (has area > 0)
   // if not simplex can't be expanded and thus no itersection is found
-  if(ccdVec3Eq(&A->v, &B->v) || ccdVec3Eq(&A->v, &C->v))
-  {
+  if (ccdVec3Eq(&A->v, &B->v) || ccdVec3Eq(&A->v, &C->v)){
     return -1;
   }
 
@@ -181,52 +211,37 @@ static int doSimplex3Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
 
   ccdVec3Cross(&tmp, &ABC, &AC);
   dot = ccdVec3Dot(&tmp, &AO);
-  if(ccdIsZero(dot) || dot > CCD_ZERO)
-  {
+  if (ccdIsZero(dot) || dot > CCD_ZERO){
     dot = ccdVec3Dot(&AC, &AO);
-    if(ccdIsZero(dot) || dot > CCD_ZERO)
-    {
+    if (ccdIsZero(dot) || dot > CCD_ZERO){
       // C is already in place
       ccdSimplexSet(simplex, 1, A);
       ccdSimplexSetSize(simplex, 2);
       tripleCross(&AC, &AO, &AC, dir);
-    }
-    else
-    {
+    }else{
     ccd_do_simplex3_45:
       dot = ccdVec3Dot(&AB, &AO);
-      if(ccdIsZero(dot) || dot > CCD_ZERO)
-      {
+      if (ccdIsZero(dot) || dot > CCD_ZERO){
         ccdSimplexSet(simplex, 0, B);
         ccdSimplexSet(simplex, 1, A);
         ccdSimplexSetSize(simplex, 2);
         tripleCross(&AB, &AO, &AB, dir);
-      }
-      else
-      {
+      }else{
         ccdSimplexSet(simplex, 0, A);
         ccdSimplexSetSize(simplex, 1);
         ccdVec3Copy(dir, &AO);
       }
     }
-  }
-  else
-  {
+  }else{
     ccdVec3Cross(&tmp, &AB, &ABC);
     dot = ccdVec3Dot(&tmp, &AO);
-    if(ccdIsZero(dot) || dot > CCD_ZERO)
-    {
+    if (ccdIsZero(dot) || dot > CCD_ZERO){
       goto ccd_do_simplex3_45;
-    }
-    else
-    {
+    }else{
       dot = ccdVec3Dot(&ABC, &AO);
-      if (ccdIsZero(dot) || dot > CCD_ZERO)
-      {
+      if (ccdIsZero(dot) || dot > CCD_ZERO){
         ccdVec3Copy(dir, &ABC);
-      }
-      else
-      {
+      }else{
         ccd_support_t Ctmp;
         ccdSupportCopy(&Ctmp, C);
         ccdSimplexSet(simplex, 0, B);
@@ -238,16 +253,16 @@ static int doSimplex3Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
     }
   }
 
-
   return 0;
 }
 
-static int doSimplex4Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* dist)
+static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir)
 {
   const ccd_support_t *A, *B, *C, *D;
   ccd_vec3_t AO, AB, AC, AD, ABC, ACD, ADB;
   int B_on_ACD, C_on_ADB, D_on_ABC;
   int AB_O, AC_O, AD_O;
+  ccd_real_t dist;
 
   // get last added as A
   A = ccdSimplexLast(simplex);
@@ -259,25 +274,24 @@ static int doSimplex4Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
   // check if tetrahedron is really tetrahedron (has volume > 0)
   // if it is not simplex can't be expanded and thus no intersection is
   // found
-  ccd_real_t volume = ccdVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, NULL);
-  if(ccdIsZero(volume))
-  {
+  dist = ccdVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, NULL);
+  if (ccdIsZero(dist)){
     return -1;
   }
 
   // check if origin lies on some of tetrahedron's face - if so objects
   // intersect
-  volume = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL);
-  if(ccdIsZero(volume))
+  dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL);
+  if (ccdIsZero(dist))
     return 1;
-  volume = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &C->v, &D->v, NULL);
-  if(ccdIsZero(volume))
+  dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &C->v, &D->v, NULL);
+  if (ccdIsZero(dist))
     return 1;
-  volume = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &D->v, NULL);
-  if(ccdIsZero(volume))
+  dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &D->v, NULL);
+  if (ccdIsZero(dist))
     return 1;
-  volume = ccdVec3PointTriDist2(ccd_vec3_origin, &B->v, &C->v, &D->v, NULL);
-  if(ccdIsZero(volume))
+  dist = ccdVec3PointTriDist2(ccd_vec3_origin, &B->v, &C->v, &D->v, NULL);
+  if (ccdIsZero(dist))
     return 1;
 
   // compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors
@@ -302,15 +316,12 @@ static int doSimplex4Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
   AC_O = ccdSign(ccdVec3Dot(&ADB, &AO)) == C_on_ADB;
   AD_O = ccdSign(ccdVec3Dot(&ABC, &AO)) == D_on_ABC;
 
-  if(AB_O && AC_O && AD_O)
-  {
+  if (AB_O && AC_O && AD_O){
     // origin is in tetrahedron
     return 1;
 
-    // rearrange simplex to triangle and call doSimplex3Dist()
-  }
-  else if(!AB_O)
-  {
+    // rearrange simplex to triangle and call doSimplex3()
+  }else if (!AB_O){
     // B is farthest from the origin among all of the tetrahedron's
     // points, so remove it from the list and go on with the triangle
     // case
@@ -318,60 +329,44 @@ static int doSimplex4Dist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* d
     // D and C are in place
     ccdSimplexSet(simplex, 2, A);
     ccdSimplexSetSize(simplex, 3);
-  }
-  else if(!AC_O)
-  {
+  }else if (!AC_O){
     // C is farthest
     ccdSimplexSet(simplex, 1, D);
     ccdSimplexSet(simplex, 0, B);
     ccdSimplexSet(simplex, 2, A);
     ccdSimplexSetSize(simplex, 3);
-  }
-  else
-  { 
-    // (!AD_O)
+  }else{ // (!AD_O)
     ccdSimplexSet(simplex, 0, C);
     ccdSimplexSet(simplex, 1, B);
     ccdSimplexSet(simplex, 2, A);
     ccdSimplexSetSize(simplex, 3);
   }
 
-  return doSimplex3Dist(simplex, dir, dist);
+  return doSimplex3(simplex, dir);
 }
 
-
-static int doSimplexDist(ccd_simplex_t *simplex, ccd_vec3_t *dir, ccd_real_t* dist)
+static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir)
 {
-  if(ccdSimplexSize(simplex) == 2)
-  {
+  if (ccdSimplexSize(simplex) == 2){
     // simplex contains segment only one segment
-    return doSimplex2Dist(simplex, dir, dist);
-  }
-  else if(ccdSimplexSize(simplex) == 3)
-  {
+    return doSimplex2(simplex, dir);
+  }else if (ccdSimplexSize(simplex) == 3){
     // simplex contains triangle
-    return doSimplex3Dist(simplex, dir, dist);
-  }
-  else
-  { 
-    // ccdSimplexSize(simplex) == 4
+    return doSimplex3(simplex, dir);
+  }else{ // ccdSimplexSize(simplex) == 4
     // tetrahedron - this is the only shape which can encapsule origin
     // so doSimplex4() also contains test on it
-    return doSimplex4Dist(simplex, dir, dist);
+    return doSimplex4(simplex, dir);
   }
 }
 
-
-
-static ccd_real_t __ccdGJKDist(const void *obj1, const void *obj2,
-                               const ccd_t *ccd, ccd_simplex_t *simplex,
-                               ccd_real_t tolerance)
+static int __ccdGJK(const void *obj1, const void *obj2,
+                    const ccd_t *ccd, ccd_simplex_t *simplex)
 {
   unsigned long iterations;
   ccd_vec3_t dir; // direction vector
   ccd_support_t last; // last support point
   int do_simplex_res;
-  ccd_real_t min_dist = -1;
 
   // initialize simplex struct
   ccdSimplexInit(simplex);
@@ -387,23 +382,16 @@ static ccd_real_t __ccdGJKDist(const void *obj1, const void *obj2,
   ccdVec3Copy(&dir, &last.v);
   ccdVec3Scale(&dir, -CCD_ONE);
 
-  bool collision_free = false;
-
   // start iterations
-  for(iterations = 0UL; iterations < ccd->max_iterations; ++iterations)
-  {
+  for (iterations = 0UL; iterations < ccd->max_iterations; ++iterations) {
     // obtain support point
     __ccdSupport(obj1, obj2, &dir, ccd, &last);
 
     // check if farthest point in Minkowski difference in direction dir
     // isn't somewhere before origin (the test on negative dot product)
     // - because if it is, objects are not intersecting at all.
-    if(ccdVec3Dot(&last.v, &dir) < CCD_ZERO)
-    {
-      collision_free = true;
-      ccd_real_t dist = ccdVec3Len2(&last.v);
-      if(min_dist < 0) min_dist = dist;
-      else min_dist = std::min(min_dist, dist);
+    if (ccdVec3Dot(&last.v, &dir) < CCD_ZERO){
+      return -1; // intersection not found
     }
 
     // add last support vector to simplex
@@ -411,34 +399,108 @@ static ccd_real_t __ccdGJKDist(const void *obj1, const void *obj2,
 
     // if doSimplex returns 1 if objects intersect, -1 if objects don't
     // intersect and 0 if algorithm should continue
-    ccd_real_t dist;
-    do_simplex_res = doSimplexDist(simplex, &dir, &dist);
+    do_simplex_res = doSimplex(simplex, &dir);
+    if (do_simplex_res == 1){
+      return 0; // intersection found
+    }else if (do_simplex_res == -1){
+      return -1; // intersection not found
+    }
 
-    if((do_simplex_res == 1) && (!collision_free))
-    {
-      return -1; // intersection found
+    if (ccdIsZero(ccdVec3Len2(&dir))){
+      return -1; // intersection not found
+    }
+  }
+
+  // intersection wasn't found
+  return -1;
+}
+
+/// change the libccd distance to add two closest points
+ccd_real_t ccdGJKDist2(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_vec3_t* p1, ccd_vec3_t* p2)
+{
+  unsigned long iterations;
+  ccd_simplex_t simplex;
+  ccd_support_t last; // last support point
+  ccd_vec3_t dir; // direction vector
+  ccd_real_t dist, last_dist;
+
+  // first find an intersection
+  if (__ccdGJK(obj1, obj2, ccd, &simplex) == 0)
+    return -CCD_ONE;
+
+  last_dist = CCD_REAL_MAX;
+
+  for (iterations = 0UL; iterations < ccd->max_iterations; ++iterations) {
+    // get a next direction vector
+    // we are trying to find out a point on the minkowski difference
+    // that is nearest to the origin, so we obtain a point on the
+    // simplex that is nearest and try to exapand the simplex towards
+    // the origin
+    if (ccdSimplexSize(&simplex) == 1){
+      ccdVec3Copy(&dir, &ccdSimplexPoint(&simplex, 0)->v);
+      dist = ccdVec3Len2(&ccdSimplexPoint(&simplex, 0)->v);
+      dist = CCD_SQRT(dist);
+    }else if (ccdSimplexSize(&simplex) == 2){
+      dist = ccdVec3PointSegmentDist2(ccd_vec3_origin,
+                                      &ccdSimplexPoint(&simplex, 0)->v,
+                                      &ccdSimplexPoint(&simplex, 1)->v,
+                                      &dir);
+      dist = CCD_SQRT(dist);
+    }else if(ccdSimplexSize(&simplex) == 3){
+      dist = ccdVec3PointTriDist2(ccd_vec3_origin,
+                                  &ccdSimplexPoint(&simplex, 0)->v,
+                                  &ccdSimplexPoint(&simplex, 1)->v,
+                                  &ccdSimplexPoint(&simplex, 2)->v,
+                                  &dir);
+      dist = CCD_SQRT(dist);
+    }else{ // ccdSimplexSize(&simplex) == 4
+      dist = simplexReduceToTriangle(&simplex, last_dist, &dir);
     }
-    else if(do_simplex_res == -1) collision_free = true;
 
-    if(ccdIsZero(ccdVec3Len2(&dir)))
-      collision_free = true;
-    
+    // touching contact -- do we really need this?
+    // maybe __ccdGJK() solve this alredy.
+    if (ccdIsZero(dist))
+      return -CCD_ONE;
 
-    if(min_dist > 0)
+    // check whether we improved for at least a minimum tolerance
+    if ((last_dist - dist) < ccd->dist_tolerance)
     {
-      ccd_real_t old_min_dist = min_dist;
-      min_dist = std::min(min_dist, dist);
+      if(p1) *p1 = last.v1;
+      if(p2) *p2 = last.v2;
+      return dist;
+    }
+
+    // point direction towards the origin
+    ccdVec3Scale(&dir, -CCD_ONE);
+    ccdVec3Normalize(&dir);
 
-      if((fabs(min_dist - old_min_dist) < tolerance) && (iterations > 0))
-        break;
+    // find out support point
+    __ccdSupport(obj1, obj2, &dir, ccd, &last);
+
+    // record last distance
+    last_dist = dist;
+
+    // check whether we improved for at least a minimum tolerance
+    // this is here probably only for a degenerate cases when we got a
+    // point that is already in the simplex
+    dist = ccdVec3Len2(&last.v);
+    dist = CCD_SQRT(dist);
+    if (CCD_FABS(last_dist - dist) < ccd->dist_tolerance)
+    {
+      if(p1) *p1 = last.v1;
+      if(p2) *p2 = last.v2;
+      return last_dist;
     }
-    else min_dist = dist;
+
+    // add a point to simplex
+    ccdSimplexAdd(&simplex, &last);
   }
 
-  // intersection wasn't found
-  return min_dist;
+  return -CCD_REAL(1.);
 }
-*/
+
+}
+
 
 /** Basic shape to ccd shape */
 static void shapeToGJK(const ShapeBase& s, const Transform3f& tf, ccd_obj_t* o)
@@ -499,8 +561,8 @@ static void supportBox(const void* obj, const ccd_vec3_t* dir_, ccd_vec3_t* v)
   ccdVec3Copy(&dir, dir_);
   ccdQuatRotVec(&dir, &o->rot_inv);
   ccdVec3Set(v, ccdSign(ccdVec3X(&dir)) * o->dim[0],
-                ccdSign(ccdVec3Y(&dir)) * o->dim[1],
-                ccdSign(ccdVec3Z(&dir)) * o->dim[2]);
+             ccdSign(ccdVec3Y(&dir)) * o->dim[1],
+             ccdSign(ccdVec3Z(&dir)) * o->dim[2]);
   ccdQuatRotVec(v, &o->rot);
   ccdVec3Add(v, &o->pos);
 }
@@ -549,8 +611,8 @@ static void supportCyl(const void* obj, const ccd_vec3_t* dir_, ccd_vec3_t* v)
     rad = cyl->radius / zdist;
 
     ccdVec3Set(v, rad * ccdVec3X(&dir),
-                  rad * ccdVec3Y(&dir),
-                  ccdSign(ccdVec3Z(&dir)) * cyl->height);
+               rad * ccdVec3Y(&dir),
+               ccdSign(ccdVec3Z(&dir)) * cyl->height);
   }
 
   // transform support vertex
@@ -668,7 +730,7 @@ static void supportTriangle(const void* obj, const ccd_vec3_t* dir_, ccd_vec3_t*
 static void centerShape(const void* obj, ccd_vec3_t* c)
 {
   const ccd_obj_t *o = static_cast<const ccd_obj_t*>(obj);
-    ccdVec3Copy(c, &o->pos);
+  ccdVec3Copy(c, &o->pos);
 }
 
 static void centerConvex(const void* obj, ccd_vec3_t* c)
@@ -682,9 +744,9 @@ static void centerConvex(const void* obj, ccd_vec3_t* c)
 static void centerTriangle(const void* obj, ccd_vec3_t* c)
 {
   const ccd_triangle_t *o = static_cast<const ccd_triangle_t*>(obj);
-    ccdVec3Copy(c, &o->c);
-    ccdQuatRotVec(c, &o->rot);
-    ccdVec3Add(c, &o->pos);
+  ccdVec3Copy(c, &o->c);
+  ccdQuatRotVec(c, &o->rot);
+  ccdVec3Add(c, &o->pos);
 }
 
 bool GJKCollide(void* obj1, ccd_support_fn supp1, ccd_center_fn cen1,
@@ -712,6 +774,7 @@ bool GJKCollide(void* obj1, ccd_support_fn supp1, ccd_center_fn cen1,
   }
 
 
+  /// libccd returns dir and pos in world space and dir is pointing from object 2 to object 1
   res = ccdMPRPenetration(obj1, obj2, &ccd, &depth, &dir, &pos);
   if(res == 0)
   {
@@ -725,39 +788,12 @@ bool GJKCollide(void* obj1, ccd_support_fn supp1, ccd_center_fn cen1,
   return false;
 }
 
-/*
-bool GJKDistance(void* obj1, ccd_support_fn supp1,
-                 void* obj2, ccd_support_fn supp2,
-                 unsigned int max_iterations, FCL_REAL tolerance_,
-                 FCL_REAL* res)
-{
-  ccd_t ccd;
-  ccd_real_t dist;
-  CCD_INIT(&ccd);
-  ccd.support1 = supp1;
-  ccd.support2 = supp2;
-  
-  ccd.max_iterations = max_iterations;
-  ccd_real_t tolerance = tolerance_;
-  
-
-  ccd_simplex_t simplex;
-  dist = __ccdGJKDist(obj1, obj2, &ccd, &simplex, tolerance);
-  
-  if(dist > 0)
-  {
-    *res = std::sqrt(dist);
-    return true;
-  }
-  else
-    return false;
-}
-*/
 
+/// p1 and p2 are in global coordinate, so needs transform in the narrowphase.h functions
 bool GJKDistance(void* obj1, ccd_support_fn supp1,
                  void* obj2, ccd_support_fn supp2,
                  unsigned int max_iterations, FCL_REAL tolerance,
-                 FCL_REAL* res)
+                 FCL_REAL* res, Vec3f* p1, Vec3f* p2)
 {
   ccd_t ccd;
   ccd_real_t dist;
@@ -768,12 +804,16 @@ bool GJKDistance(void* obj1, ccd_support_fn supp1,
   ccd.max_iterations = max_iterations;
   ccd.dist_tolerance = tolerance;
 
-  dist = ccdGJKDist(obj1, obj2, &ccd);
-  *res = dist;
+  ccd_vec3_t p1_, p2_;
+  dist = libccd_extension::ccdGJKDist2(obj1, obj2, &ccd, &p1_, &p2_);
+  if(p1) p1->setValue(ccdVec3X(&p1_), ccdVec3Y(&p1_), ccdVec3Z(&p1_));
+  if(p2) p2->setValue(ccdVec3X(&p2_), ccdVec3Y(&p2_), ccdVec3Z(&p2_));
+  if(res) *res = dist;
   if(dist < 0) return false;
   else return true;
 }
 
+
 GJKSupportFunction GJKInitializer<Cylinder>::getSupportFunction()
 {
   return &supportCyl;
diff --git a/src/narrowphase/narrowphase.cpp b/src/narrowphase/narrowphase.cpp
index adcda2fc..2a1fc513 100644
--- a/src/narrowphase/narrowphase.cpp
+++ b/src/narrowphase/narrowphase.cpp
@@ -36,6 +36,7 @@
 
 #include "fcl/narrowphase/narrowphase.h"
 #include "fcl/shape/geometric_shapes_utility.h"
+#include "fcl/intersect.h"
 #include <boost/math/constants/constants.hpp>
 #include <vector>
 
@@ -50,84 +51,92 @@ namespace details
 // given by Dan Sunday's page:
 //   http://geomalgorithms.com/a02-_lines.html
 static inline void lineSegmentPointClosestToPoint (const Vec3f &p, const Vec3f &s1, const Vec3f &s2, Vec3f &sp) {
-	Vec3f v = s2 - s1;
-	Vec3f w = p - s1;
+  Vec3f v = s2 - s1;
+  Vec3f w = p - s1;
 
-	FCL_REAL c1 = w.dot(v);
-	FCL_REAL c2 = v.dot(v);
+  FCL_REAL c1 = w.dot(v);
+  FCL_REAL c2 = v.dot(v);
 
-	if (c1 <= 0) {
-		sp = s1;
-	} else if (c2 <= c1) {
-		sp = s2;
-	} else {
-		FCL_REAL b = c1/c2;
-		Vec3f Pb = s1 + v * b;
-		sp = Pb;
-	}
+  if (c1 <= 0) {
+    sp = s1;
+  } else if (c2 <= c1) {
+    sp = s2;
+  } else {
+    FCL_REAL b = c1/c2;
+    Vec3f Pb = s1 + v * b;
+    sp = Pb;
+  }
 }
 
 bool sphereCapsuleIntersect(const Sphere& s1, const Transform3f& tf1, 
                             const Capsule& s2, const Transform3f& tf2,
-                           Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal_)
+                            Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal_)
 {
-	Transform3f tf2_inv (tf2);
-	tf2_inv.inverse();
+  Transform3f tf2_inv (tf2);
+  tf2_inv.inverse();
 
-	Vec3f pos1 (0., 0., 0.5 * s2.lz);
-	Vec3f pos2 (0., 0., -0.5 * s2.lz);
-	Vec3f s_c = tf2_inv.transform(tf1.transform(Vec3f()));
+  Vec3f pos1 (0., 0., 0.5 * s2.lz);
+  Vec3f pos2 (0., 0., -0.5 * s2.lz);
+  Vec3f s_c = tf2_inv.transform(tf1.transform(Vec3f()));
 
-	Vec3f segment_point;
+  Vec3f segment_point;
 
-	lineSegmentPointClosestToPoint (s_c, pos1, pos2, segment_point);
-	Vec3f diff = s_c - segment_point;
+  lineSegmentPointClosestToPoint (s_c, pos1, pos2, segment_point);
+  Vec3f diff = s_c - segment_point;
 
-	FCL_REAL distance = diff.length() - s1.radius - s2.radius;
+  FCL_REAL distance = diff.length() - s1.radius - s2.radius;
 
-	if (distance > 0)
-		return false;
+  if (distance > 0)
+    return false;
 
-	Vec3f normal = diff.normalize() * - FCL_REAL(1);
+  Vec3f normal = diff.normalize() * - FCL_REAL(1);
 
-	if (distance < 0 && penetration_depth)
-		*penetration_depth = -distance;
+  if (distance < 0 && penetration_depth)
+    *penetration_depth = -distance;
 
-	if (normal_)
-		*normal_ = tf2.getQuatRotation().transform(normal);
+  if (normal_)
+    *normal_ = tf2.getQuatRotation().transform(normal);
 
-	if (contact_points) {
-		*contact_points = tf2.transform(segment_point + normal * distance);
-	}
+  if (contact_points) {
+    *contact_points = tf2.transform(segment_point + normal * distance);
+  }
 
-	return true;
+  return true;
 }
 
 bool sphereCapsuleDistance(const Sphere& s1, const Transform3f& tf1, 
-                          const Capsule& s2, const Transform3f& tf2,
-                          FCL_REAL* dist)
+                           const Capsule& s2, const Transform3f& tf2,
+                           FCL_REAL* dist, Vec3f* p1, Vec3f* p2)
 {
-	Transform3f tf2_inv (tf2);
-	tf2_inv.inverse();
+  Transform3f tf2_inv(tf2);
+  tf2_inv.inverse();
 
-	Vec3f pos1 (0., 0., 0.5 * s2.lz);
-	Vec3f pos2 (0., 0., -0.5 * s2.lz);
-	Vec3f s_c = tf2_inv.transform(tf1.transform(Vec3f()));
+  Vec3f pos1(0., 0., 0.5 * s2.lz);
+  Vec3f pos2(0., 0., -0.5 * s2.lz);
+  Vec3f s_c = tf2_inv.transform(tf1.transform(Vec3f()));
 
-	Vec3f segment_point;
+  Vec3f segment_point;
 
-	lineSegmentPointClosestToPoint (s_c, pos1, pos2, segment_point);
-	Vec3f diff = s_c - segment_point;
+  lineSegmentPointClosestToPoint (s_c, pos1, pos2, segment_point);
+  Vec3f diff = s_c - segment_point;
 
-	FCL_REAL distance = diff.length() - s1.radius - s2.radius;
+  FCL_REAL distance = diff.length() - s1.radius - s2.radius;
 
-	if (distance <= 0)
-		return false;
+  if(distance <= 0)
+    return false;
 
-	if (dist)
-		*dist = distance;
+  if(dist) *dist = distance;
 
-	return true;
+  if(p1 || p2) diff.normalize();
+  if(p1)
+  {
+    *p1 = s_c - diff * s1.radius;
+    *p1 = inverse(tf1).transform(tf2.transform(*p1));
+  }
+
+  if(p2) *p2 = segment_point + diff * s1.radius;
+
+  return true;
 }
 
 bool sphereSphereIntersect(const Sphere& s1, const Transform3f& tf1, 
@@ -158,17 +167,21 @@ bool sphereSphereIntersect(const Sphere& s1, const Transform3f& tf1,
 
 bool sphereSphereDistance(const Sphere& s1, const Transform3f& tf1,
                           const Sphere& s2, const Transform3f& tf2,
-                          FCL_REAL* dist)
+                          FCL_REAL* dist, Vec3f* p1, Vec3f* p2)
 {
-  Vec3f diff = tf1.transform(Vec3f()) - tf2.transform(Vec3f());
+  Vec3f o1 = tf1.getTranslation();
+  Vec3f o2 = tf2.getTranslation();
+  Vec3f diff = o1 - o2;
   FCL_REAL len = diff.length();
   if(len > s1.radius + s2.radius)
   {
-    *dist = len - (s1.radius + s2.radius);
+    if(dist) *dist = len - (s1.radius + s2.radius);
+    if(p1) *p1 = inverse(tf1).transform(o1 - diff * (s1.radius / len));
+    if(p2) *p2 = inverse(tf2).transform(o2 + diff * (s2.radius / len));
     return true;
   }
 
-  *dist = -1;
+  if(dist) *dist = -1;
   return false;
 }
 
@@ -200,7 +213,7 @@ FCL_REAL segmentSqrDistance(const Vec3f& from, const Vec3f& to,const Vec3f& p, V
   return diff.dot(diff);	
 }
 
-/** \brief Whether a point's projection is in a triangle */
+/// @brief Whether a point's projection is in a triangle
 bool projectInTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& normal, const Vec3f& p)
 {
   Vec3f edge1(p2 - p1);
@@ -310,6 +323,7 @@ bool sphereTriangleIntersect(const Sphere& s, const Transform3f& tf,
   return false;
 }
 
+
 bool sphereTriangleDistance(const Sphere& sp, const Transform3f& tf,
                             const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
                             FCL_REAL* dist)
@@ -541,18 +555,58 @@ bool sphereTriangleDistance(const Sphere& sp, const Transform3f& tf,
 
   if(sqr_dist > radius * radius)
   {
-    *dist = std::sqrt(sqr_dist) - radius;
+    if(dist) *dist = std::sqrt(sqr_dist) - radius;
     return true;
   }
   else
   {
-    *dist = -1;
+    if(dist) *dist = -1;
     return false;
   }
 }
 
 
+bool sphereTriangleDistance(const Sphere& sp, const Transform3f& tf,
+                            const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
+                            FCL_REAL* dist, Vec3f* p1, Vec3f* p2)
+{
+  if(p1 || p2)
+  {
+    Vec3f o = tf.getTranslation();
+    Project::ProjectResult result;
+    result = Project::projectTriangle(P1, P2, P3, o);
+    if(result.sqr_distance > sp.radius * sp.radius)
+    {
+      if(dist) *dist = std::sqrt(result.sqr_distance);
+      Vec3f project_p = P1 * result.parameterization[0] + P2 * result.parameterization[1] + P3 * result.parameterization[2];
+      Vec3f dir = o - project_p;
+      dir.normalize();
+      if(p1) { *p1 = o - dir * sp.radius; *p1 = inverse(tf).transform(*p1); }
+      if(p2) *p2 = project_p;
+      return true;
+    }
+    else
+      return false;
+  }
+  else
+  {
+    return sphereTriangleDistance(sp, tf, P1, P2, P3, dist);
+  }
+}
+
+
+bool sphereTriangleDistance(const Sphere& sp, const Transform3f& tf1,
+                            const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
+                            FCL_REAL* dist, Vec3f* p1, Vec3f* p2)
+{
+  bool res = details::sphereTriangleDistance(sp, tf1, tf2.transform(P1), tf2.transform(P2), tf2.transform(P2), dist, p1, p2);
+  if(p2) *p2 = inverse(tf2).transform(*p2);
+
+  return res;
+}
+
 
+  
 struct ContactPoint
 {
   Vec3f normal;
@@ -610,36 +664,36 @@ static int intersectRectQuad2(FCL_REAL h[2], FCL_REAL p[8], FCL_REAL ret[16])
       nr = 0;
       for(int i = nq; i > 0; --i) 
       {
-	// go through all points in q and all lines between adjacent points
-	if(sign * pq[dir] < h[dir]) 
+        // go through all points in q and all lines between adjacent points
+        if(sign * pq[dir] < h[dir]) 
         {
-	  // this point is inside the chopping line
-	  pr[0] = pq[0];
-	  pr[1] = pq[1];
-	  pr += 2;
-	  nr++;
-	  if(nr & 8) 
+          // this point is inside the chopping line
+          pr[0] = pq[0];
+          pr[1] = pq[1];
+          pr += 2;
+          nr++;
+          if(nr & 8) 
           {
-	    q = r;
-	    goto done;
-	  }
-	}
-	FCL_REAL* nextq = (i > 1) ? pq+2 : q;
-	if((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) 
+            q = r;
+            goto done;
+          }
+        }
+        FCL_REAL* nextq = (i > 1) ? pq+2 : q;
+        if((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) 
         {
-	  // this line crosses the chopping line
-	  pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) /
-	    (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]);
-	  pr[dir] = sign*h[dir];
-	  pr += 2;
-	  nr++;
-	  if(nr & 8) 
+          // this line crosses the chopping line
+          pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) /
+            (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]);
+          pr[dir] = sign*h[dir];
+          pr += 2;
+          nr++;
+          if(nr & 8) 
           {
-	    q = r;
-	    goto done;
-	  }
-	}
-	pq += 2;
+            q = r;
+            goto done;
+          }
+        }
+        pq += 2;
       }
       q = r;
       r = (q == ret) ? buffer : ret;
@@ -718,13 +772,13 @@ static inline void cullPoints2(int n, FCL_REAL p[], int m, int i0, int iret[])
     {
       if(avail[i]) 
       {
-	diff = std::abs(A[i]-a);
-	if(diff > pi) diff = 2*pi - diff;
-	if(diff < maxdiff) 
+        diff = std::abs(A[i]-a);
+        if(diff > pi) diff = 2*pi - diff;
+        if(diff < maxdiff) 
         {
-	  maxdiff = diff;
-	  *iret = i;
-	}
+          maxdiff = diff;
+          *iret = i;
+        }
       }
     }
     avail[*iret] = 0;
@@ -1268,8 +1322,8 @@ int boxBox2(const Vec3f& side1, const Matrix3f& R1, const Vec3f& T1,
     {
       if(dep[i] > maxdepth) 
       {
-	maxdepth = dep[i];
-	i1 = i;
+        maxdepth = dep[i];
+        i1 = i;
       }
     }
 
@@ -2380,7 +2434,7 @@ bool GJKSolver_libccd::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const T
                                                        const Capsule &s2, const Transform3f& tf2,
                                                        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
-	return details::sphereCapsuleIntersect (s1, tf1, s2, tf2, contact_points, penetration_depth, normal);
+  return details::sphereCapsuleIntersect (s1, tf1, s2, tf2, contact_points, penetration_depth, normal);
 }
 
 template<>
@@ -2558,34 +2612,34 @@ bool GJKSolver_libccd::shapeTriangleIntersect(const Plane& s, const Transform3f&
 
 template<>
 bool GJKSolver_libccd::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
-                                                     const Capsule& s2, const Transform3f& tf2,
-                                                     FCL_REAL* dist) const
+                                                      const Capsule& s2, const Transform3f& tf2,
+                                                      FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereCapsuleDistance(s1, tf1, s2, tf2, dist);
+  return details::sphereCapsuleDistance(s1, tf1, s2, tf2, dist, p1, p2);
 }
 
 template<>
 bool GJKSolver_libccd::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
                                                      const Sphere& s2, const Transform3f& tf2,
-                                                     FCL_REAL* dist) const
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereSphereDistance(s1, tf1, s2, tf2, dist);
+  return details::sphereSphereDistance(s1, tf1, s2, tf2, dist, p1, p2);
 }
 
 template<>
 bool GJKSolver_libccd::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf,
                                                      const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, 
-                                                     FCL_REAL* dist) const
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereTriangleDistance(s, tf, P1, P2, P3, dist);
+  return details::sphereTriangleDistance(s, tf, P1, P2, P3, dist, p1, p2);
 }
 
 template<> 
 bool GJKSolver_libccd::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf1, 
                                                      const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
-                                                     FCL_REAL* dist) const
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereTriangleDistance(s, tf1, tf2.transform(P1), tf2.transform(P2), tf2.transform(P3), dist);
+  return details::sphereTriangleDistance(s, tf1, P1, P2, P3, tf2, dist, p1, p2);
 }
 
 
@@ -2594,10 +2648,10 @@ bool GJKSolver_libccd::shapeTriangleDistance<Sphere>(const Sphere& s, const Tran
 
 template<>
 bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1,
-                                                       const Capsule &s2, const Transform3f& tf2,
-                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
+                                                      const Capsule &s2, const Transform3f& tf2,
+                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
-	return details::sphereCapsuleIntersect (s1, tf1, s2, tf2, contact_points, penetration_depth, normal);
+  return details::sphereCapsuleIntersect (s1, tf1, s2, tf2, contact_points, penetration_depth, normal);
 }
 
 template<>
@@ -2773,34 +2827,34 @@ bool GJKSolver_indep::shapeTriangleIntersect(const Plane& s, const Transform3f&
 
 template<>
 bool GJKSolver_indep::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
-                                                    const Capsule& s2, const Transform3f& tf2,
-                                                    FCL_REAL* dist) const
+                                                     const Capsule& s2, const Transform3f& tf2,
+                                                     FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereCapsuleDistance(s1, tf1, s2, tf2, dist);
+  return details::sphereCapsuleDistance(s1, tf1, s2, tf2, dist, p1, p2);
 }
 
 template<>
 bool GJKSolver_indep::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
                                                     const Sphere& s2, const Transform3f& tf2,
-                                                    FCL_REAL* dist) const
+                                                    FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereSphereDistance(s1, tf1, s2, tf2, dist);
+  return details::sphereSphereDistance(s1, tf1, s2, tf2, dist, p1, p2);
 }
 
 template<>
 bool GJKSolver_indep::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf,
                                                     const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, 
-                                                    FCL_REAL* dist) const
+                                                    FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereTriangleDistance(s, tf, P1, P2, P3, dist);
+  return details::sphereTriangleDistance(s, tf, P1, P2, P3, dist, p1, p2);
 }
 
 template<> 
 bool GJKSolver_indep::shapeTriangleDistance<Sphere>(const Sphere& s, const Transform3f& tf1, 
                                                     const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2,
-                                                    FCL_REAL* dist) const
+                                                    FCL_REAL* dist, Vec3f* p1, Vec3f* p2) const
 {
-  return details::sphereTriangleDistance(s, tf1, tf2.transform(P1), tf2.transform(P2), tf2.transform(P3), dist);
+  return details::sphereTriangleDistance(s, tf1, P1, P2, P3, tf2, dist, p1, p2);
 }
 
 
diff --git a/src/shape/geometric_shapes.cpp b/src/shape/geometric_shapes.cpp
index 3450ce57..ce537dfc 100644
--- a/src/shape/geometric_shapes.cpp
+++ b/src/shape/geometric_shapes.cpp
@@ -186,7 +186,7 @@ void Plane::computeLocalAABB()
   aabb_radius = (aabb_local.min_ - aabb_center).length();
 }
 
-void Triangle2::computeLocalAABB()
+void TriangleP::computeLocalAABB()
 {
   computeBV<AABB>(*this, Transform3f(), aabb_local);
   aabb_center = aabb_local.center();
diff --git a/src/shape/geometric_shapes_utility.cpp b/src/shape/geometric_shapes_utility.cpp
index bbe7423d..6c25ab5e 100644
--- a/src/shape/geometric_shapes_utility.cpp
+++ b/src/shape/geometric_shapes_utility.cpp
@@ -203,7 +203,7 @@ std::vector<Vec3f> getBoundVertices(const Convex& convex, const Transform3f& tf)
   return result;
 }
 
-std::vector<Vec3f> getBoundVertices(const Triangle2& triangle, const Transform3f& tf)
+std::vector<Vec3f> getBoundVertices(const TriangleP& triangle, const Transform3f& tf)
 {
   std::vector<Vec3f> result(3);
   result[0] = tf.transform(triangle.a);
@@ -333,7 +333,7 @@ void computeBV<AABB, Convex>(const Convex& s, const Transform3f& tf, AABB& bv)
 }
 
 template<>
-void computeBV<AABB, Triangle2>(const Triangle2& s, const Transform3f& tf, AABB& bv)
+void computeBV<AABB, TriangleP>(const TriangleP& s, const Transform3f& tf, AABB& bv)
 {
   bv = AABB(tf.transform(s.a), tf.transform(s.b), tf.transform(s.c));
 }
diff --git a/src/traversal/traversal_node_bvhs.cpp b/src/traversal/traversal_node_bvhs.cpp
index fd91349f..7e47e121 100644
--- a/src/traversal/traversal_node_bvhs.cpp
+++ b/src/traversal/traversal_node_bvhs.cpp
@@ -465,14 +465,14 @@ bool meshConservativeAdvancementTraversalNodeCanStop(FCL_REAL c,
     {
       const ConservativeAdvancementStackData& data2 = stack[stack.size() - 2];
       d = data2.d;
-      n = data2.P2 - data2.P1;
+      n = data2.P2 - data2.P1; n.normalize();
       c1 = data2.c1;
       c2 = data2.c2;
       stack[stack.size() - 2] = stack[stack.size() - 1];
     }
     else
     {
-      n = data.P2 - data.P1;
+      n = data.P2 - data.P1; n.normalize();
       c1 = data.c1;
       c2 = data.c2;
     }
@@ -572,14 +572,14 @@ bool meshConservativeAdvancementOrientedNodeCanStop(FCL_REAL c,
     {
       const ConservativeAdvancementStackData& data2 = stack[stack.size() - 2];
       d = data2.d;
-      n = data2.P2 - data2.P1;
+      n = data2.P2 - data2.P1; n.normalize();
       c1 = data2.c1;
       c2 = data2.c2;
       stack[stack.size() - 2] = stack[stack.size() - 1];
     }
     else
     {
-      n = data.P2 - data.P1;
+      n = data.P2 - data.P1; n.normalize();
       c1 = data.c1;
       c2 = data.c2;
     }
@@ -591,9 +591,9 @@ bool meshConservativeAdvancementOrientedNodeCanStop(FCL_REAL c,
       getBVAxis(model1->getBV(c1).bv, 0) * n[0] +
       getBVAxis(model1->getBV(c1).bv, 1) * n[2] +
       getBVAxis(model1->getBV(c1).bv, 2) * n[2];
-    Matrix3f R0;
+    Quaternion3f R0;
     motion1->getCurrentRotation(R0);
-    n_transformed = R0 * n_transformed;
+    n_transformed = R0.transform(n_transformed);
     n_transformed.normalize();
 
     TBVMotionBoundVisitor<BV> mb_visitor1(model1->getBV(c1).bv, n_transformed), mb_visitor2(model2->getBV(c2).bv, -n_transformed);
@@ -682,10 +682,10 @@ void meshConservativeAdvancementOrientedNodeLeafTesting(int b1, int b2,
   /// n is the local frame of object 1, pointing from object 1 to object2
   Vec3f n = P2 - P1;
   /// turn n into the global frame, pointing from object 1 to object 2
-  Matrix3f R0;
+  Quaternion3f R0;
   motion1->getCurrentRotation(R0);
-  Vec3f n_transformed = R0 * n;
-  n_transformed.normalize();
+  Vec3f n_transformed = R0.transform(n);
+  n_transformed.normalize(); // normalized here
 
   TriangleMotionBoundVisitor mb_visitor1(t11, t12, t13, n_transformed), mb_visitor2(t21, t22, t23, -n_transformed);
   FCL_REAL bound1 = motion1->computeMotionBound(mb_visitor1);
@@ -732,7 +732,7 @@ void MeshConservativeAdvancementTraversalNodeRSS::leafTesting(int b1, int b2) co
                                                               motion1, motion2,
                                                               enable_statistics,
                                                               min_distance,
-                                                              p1, p2,
+                                                              closest_p1, closest_p2,
                                                               last_tri_id1, last_tri_id2,
                                                               delta_t,
                                                               num_leaf_tests);
@@ -780,7 +780,7 @@ void MeshConservativeAdvancementTraversalNodeOBBRSS::leafTesting(int b1, int b2)
                                                               motion1, motion2,
                                                               enable_statistics,
                                                               min_distance,
-                                                              p1, p2,
+                                                              closest_p1, closest_p2,
                                                               last_tri_id1, last_tri_id2,
                                                               delta_t,
                                                               num_leaf_tests);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6638b19e..1e06285c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -28,6 +28,7 @@ add_fcl_test(test_fcl_frontlist test_fcl_frontlist.cpp test_fcl_utility.cpp)
 add_fcl_test(test_fcl_math test_fcl_math.cpp test_fcl_utility.cpp)
 
 add_fcl_test(test_fcl_sphere_capsule test_fcl_sphere_capsule.cpp)
+add_fcl_test(test_fcl_simple test_fcl_simple.cpp)
 
 if (FCL_HAVE_OCTOMAP)
   add_fcl_test(test_fcl_octomap test_fcl_octomap.cpp test_fcl_utility.cpp)
diff --git a/test/test_fcl_geometric_shapes.cpp b/test/test_fcl_geometric_shapes.cpp
index dff6ffa0..0d45432b 100644
--- a/test/test_fcl_geometric_shapes.cpp
+++ b/test/test_fcl_geometric_shapes.cpp
@@ -41,6 +41,7 @@
 #include "fcl/narrowphase/narrowphase.h"
 #include "fcl/collision.h"
 #include "test_fcl_utility.h"
+#include "fcl/ccd/motion.h"
 #include <iostream>
 
 using namespace fcl;
@@ -52,6 +53,66 @@ GJKSolver_indep solver2;
 
 #define BOOST_CHECK_FALSE(p) BOOST_CHECK(!(p))
 
+BOOST_AUTO_TEST_CASE(gjkcache)
+{
+  Cylinder s1(5, 10);
+  Cone s2(5, 10);
+
+  CollisionRequest request;
+  request.enable_cached_gjk_guess = true;
+  request.gjk_solver_type = GST_INDEP;
+
+  TranslationMotion motion(Transform3f(Vec3f(-20.0, -20.0, -20.0)), Transform3f(Vec3f(20.0, 20.0, 20.0)));
+
+  int N = 1000;  
+  FCL_REAL dt = 1.0 / (N - 1);
+
+  /// test exploiting spatial coherence
+  Timer timer1;
+  timer1.start();
+  std::vector<bool> result1(N);
+  for(int i = 0; i < N; ++i)
+  {
+    motion.integrate(dt * i);
+    Transform3f tf;
+    motion.getCurrentTransform(tf);
+
+    CollisionResult result;
+
+    collide(&s1, Transform3f(), &s2, tf, request, result);
+    result1[i] = result.isCollision();
+    request.cached_gjk_guess = result.cached_gjk_guess; // use cached guess
+  }
+
+  timer1.stop();
+
+  /// test without exploiting spatial coherence
+  Timer timer2;
+  timer2.start();
+  std::vector<bool> result2(N);
+  request.enable_cached_gjk_guess = false;
+  for(int i = 0; i < N; ++i)
+  {
+    motion.integrate(dt * i);
+    Transform3f tf;
+    motion.getCurrentTransform(tf);
+
+    CollisionResult result;
+
+    collide(&s1, Transform3f(), &s2, tf, request, result);
+    result2[i] = result.isCollision();
+  }
+
+  timer2.stop();
+
+  std::cout << timer1.getElapsedTime() << " " << timer2.getElapsedTime() << std::endl;
+
+  for(std::size_t i = 0; i < result1.size(); ++i)
+  {
+    BOOST_CHECK(result1[i] == result2[i]);
+  }
+}
+
 BOOST_AUTO_TEST_CASE(shapeIntersection_spheresphere)
 {
   Sphere s1(20);
@@ -68,73 +129,73 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_spheresphere)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(40, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(40, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(40, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(40, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(40, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(40, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(30, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(30, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(30, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(30.01, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(30.01, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(30.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(29.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(29.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(29.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(29.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform, NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(-29.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-29.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(-29.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-29.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(-30, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-30, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-30, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -155,25 +216,25 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_boxbox)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform, NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(15, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(15, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(15, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(15.01, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(15.01, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(15.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   Quaternion3f q;
@@ -181,13 +242,13 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_boxbox)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(q), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(q), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(q), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(q), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(q), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(q), request, result) > 0);
   BOOST_CHECK(res);
 }
 
@@ -208,38 +269,38 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_spherebox)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform, NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(22.5, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(22.5, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(22.5, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(22.501, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(22.501, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(22.501, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(22.4, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(22.4, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(22.4, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(22.4, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(22.4, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(22.4, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 }
 
@@ -260,37 +321,37 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_cylindercylinder)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform, NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(9.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(9.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(9.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(9.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(9.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(9.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(10, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(10, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(10, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(10.01, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(10.01, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(10.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -311,49 +372,49 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_conecone)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform, NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(9.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(9.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(9.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(9.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(9.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(9.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(10.001, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(10.001, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(10.001, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(10.001, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(10.001, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(10.001, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(0, 0, 9.9)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(0, 0, 9.9)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(0, 0, 9.9)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(0, 0, 9.9)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(0, 0, 9.9)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(0, 0, 9.9)), request, result) > 0);
   BOOST_CHECK(res);
 }
 
@@ -374,61 +435,61 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_conecylinder)
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform, NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(9.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(9.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(9.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(9.9, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(9.9, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(9.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(10.01, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(10, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(10, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(10.01, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(10.01, 0, 0)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(10.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(0, 0, 9.9)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(0, 0, 9.9)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(0, 0, 9.9)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(0, 0, 9.9)), NULL, NULL, NULL);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(0, 0, 9.9)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(0, 0, 9.9)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver1.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(0, 0, 10.01)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(0, 0, 10)), &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(0, 0, 10)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver1.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(0, 0, 10.01)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(0, 0, 10.01)), &solver1, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(0, 0, 10.01)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1805,7 +1866,7 @@ BOOST_AUTO_TEST_CASE(shapeDistance_spheresphere)
 
   bool res;
   FCL_REAL dist = -1;
-  
+  Vec3f closest_p1, closest_p2;
   res = solver1.shapeDistance(s1, Transform3f(), s2, Transform3f(Vec3f(40, 0, 0)), &dist);
   BOOST_CHECK(fabs(dist - 10) < 0.001);
   BOOST_CHECK(res);
@@ -2057,12 +2118,14 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   Vec3f normal;  
   bool res;
 
+  request.gjk_solver_type = GST_INDEP; // use indep GJK solver
+
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(40, 0, 0)), NULL, NULL, NULL);
   BOOST_CHECK_FALSE(res); 
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(40, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(40, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(40, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(40, 0, 0)), NULL, NULL, NULL);
@@ -2070,7 +2133,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(40, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(40, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(40, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
 
@@ -2079,7 +2142,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(30, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(30, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(30, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2088,7 +2151,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(30.01, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(30.01, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(30.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
 
@@ -2097,7 +2160,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(29.9, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(29.9, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2106,7 +2169,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(29.9, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(29.9, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2115,7 +2178,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2124,7 +2187,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, transform, s2, transform, &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform, &solver2, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform, request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2133,7 +2196,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(-29.9, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-29.9, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2143,7 +2206,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(-29.9, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-29.9, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-29.9, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -2152,7 +2215,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, Transform3f(), s2, Transform3f(Vec3f(-30, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-30, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, Transform3f(Vec3f(-30, 0, 0)), request, result) > 0);
   BOOST_CHECK(res);
 
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), NULL, NULL, NULL);
@@ -2160,7 +2223,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_spheresphere)
   res = solver2.shapeIntersect(s1, transform, s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), &contact, &penetration_depth, &normal);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), &solver2, request, result) > 0);
+  res = (collide(&s1, transform, &s2, transform * Transform3f(Vec3f(-30.01, 0, 0)), request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
diff --git a/test/test_fcl_shape_mesh_consistency.cpp b/test/test_fcl_shape_mesh_consistency.cpp
index 5119b08e..cc15cad4 100644
--- a/test/test_fcl_shape_mesh_consistency.cpp
+++ b/test/test_fcl_shape_mesh_consistency.cpp
@@ -48,9 +48,6 @@ using namespace fcl;
 
 #define BOOST_CHECK_FALSE(p) BOOST_CHECK(!(p))
 
-GJKSolver_libccd solver1;
-GJKSolver_indep solver2;
-
 FCL_REAL extents[6] = {0, 0, 0, 10, 10, 10};
 
 BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_libccd)
@@ -71,16 +68,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_libccd)
   pose.setTranslation(Vec3f(50, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);  
 
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
   for(std::size_t i = 0; i < 10; ++i)
@@ -93,31 +90,31 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_libccd)
 
     res.clear(); res1.clear();
     distance(&s1, pose1, &s2, pose2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   }
 
   pose.setTranslation(Vec3f(40.1, 0, 0));
 
   res.clear(), res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
 
@@ -130,16 +127,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -163,16 +160,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_boxbox_libccd)
   pose.setTranslation(Vec3f(50, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
   for(std::size_t i = 0; i < 10; ++i)
@@ -184,32 +181,32 @@ BOOST_AUTO_TEST_CASE(consistency_distance_boxbox_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   }
 
   pose.setTranslation(Vec3f(15.1, 0, 0));
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   for(std::size_t i = 0; i < 10; ++i)
@@ -221,16 +218,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_boxbox_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -254,16 +251,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_libccd)
   pose.setTranslation(Vec3f(20, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -275,32 +272,32 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   }
   
   pose.setTranslation(Vec3f(15, 0, 0)); // libccd cannot use small value here :( 
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -312,16 +309,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -345,15 +342,15 @@ BOOST_AUTO_TEST_CASE(consistency_distance_conecone_libccd)
   pose.setTranslation(Vec3f(20, 0, 0));
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -365,32 +362,32 @@ BOOST_AUTO_TEST_CASE(consistency_distance_conecone_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   }
   
   pose.setTranslation(Vec3f(15, 0, 0)); // libccd cannot use small value here :( 
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver1, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver1, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver1, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -402,16 +399,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_conecone_libccd)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver1, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver1, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver1, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -428,6 +425,7 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_GJK)
   generateBVHModel(s2_rss, s2, Transform3f(), 16, 16);
 
   DistanceRequest request;
+  request.gjk_solver_type = GST_INDEP;
   DistanceResult res, res1;
 
   Transform3f pose;
@@ -435,16 +433,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_GJK)
   pose.setTranslation(Vec3f(50, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);  
 
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
 
@@ -458,31 +456,31 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_GJK)
 
     res.clear(); res1.clear();
     distance(&s1, pose1, &s2, pose2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   }
 
   pose.setTranslation(Vec3f(40.1, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 4);
 
 
@@ -495,16 +493,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_spheresphere_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 4);
   }
 }
@@ -528,16 +526,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_boxbox_GJK)
   pose.setTranslation(Vec3f(50, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
   for(std::size_t i = 0; i < 10; ++i)
@@ -549,32 +547,32 @@ BOOST_AUTO_TEST_CASE(consistency_distance_boxbox_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.01);
   }
 
   pose.setTranslation(Vec3f(15.1, 0, 0));
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   for(std::size_t i = 0; i < 10; ++i)
@@ -586,16 +584,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_boxbox_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -619,16 +617,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_GJK)
   pose.setTranslation(Vec3f(20, 0, 0));
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -640,22 +638,22 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     if(fabs(res1.min_distance - res.min_distance) / res.min_distance > 0.05)
       std::cout << "low resolution: " << res1.min_distance << " " << res.min_distance << std::endl;
     else
       BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     if(fabs(res1.min_distance - res.min_distance) / res.min_distance > 0.05)
       std::cout << "low resolution: " << res1.min_distance << " " << res.min_distance << std::endl;
     else
       BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     if(fabs(res1.min_distance - res.min_distance) / res.min_distance > 0.05)
       std::cout << "low resolution: " << res1.min_distance << " " << res.min_distance << std::endl;
     else
@@ -665,16 +663,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_GJK)
   pose.setTranslation(Vec3f(10.1, 0, 0));
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -686,16 +684,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_cylindercylinder_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -719,16 +717,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_conecone_GJK)
   pose.setTranslation(Vec3f(20, 0, 0));
 
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -740,32 +738,32 @@ BOOST_AUTO_TEST_CASE(consistency_distance_conecone_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 0.05);
   }
   
   pose.setTranslation(Vec3f(10.1, 0, 0));
   
   res.clear(); res1.clear();
-  distance(&s1, Transform3f(), &s2, pose, &solver2, request, res);
-  distance(&s1_rss, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2, pose, request, res);
+  distance(&s1_rss, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   res1.clear();
-  distance(&s1, Transform3f(), &s2_rss, pose, &solver2, request, res1);
+  distance(&s1, Transform3f(), &s2_rss, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
   res1.clear();
-  distance(&s1_rss, Transform3f(), &s2, pose, &solver2, request, res1);
+  distance(&s1_rss, Transform3f(), &s2, pose, request, res1);
   BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   
   for(std::size_t i = 0; i < 10; ++i)
@@ -777,16 +775,16 @@ BOOST_AUTO_TEST_CASE(consistency_distance_conecone_GJK)
     Transform3f pose2 = t * pose;
 
     res.clear(); res1.clear();
-    distance(&s1, pose1, &s2, pose2, &solver2, request, res);
-    distance(&s1_rss, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2, pose2, request, res);
+    distance(&s1_rss, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1, pose1, &s2_rss, pose2, &solver2, request, res1);
+    distance(&s1, pose1, &s2_rss, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
 
     res1.clear();
-    distance(&s1_rss, pose1, &s2, pose2, &solver2, request, res1);
+    distance(&s1_rss, pose1, &s2, pose2, request, res1);
     BOOST_CHECK(fabs(res1.min_distance - res.min_distance) / res.min_distance < 2);
   }
 }
@@ -821,31 +819,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_libccd)
   // s1 is mesh, s2 is shape --> collision free
   // all are reasonable
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(40, 0, 0));
@@ -853,31 +851,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_libccd)
   pose_obb.setTranslation(Vec3f(40, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   
   pose.setTranslation(Vec3f(30, 0, 0));
@@ -885,31 +883,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_libccd)
   pose_obb.setTranslation(Vec3f(30, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   
   pose.setTranslation(Vec3f(29.9, 0, 0));
@@ -917,31 +915,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_libccd)
   pose_obb.setTranslation(Vec3f(29.8, 0, 0)); // 29.9 fails, result depends on mesh precision
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -950,31 +948,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_libccd)
   pose_obb.setTranslation(Vec3f(-29.8, 0, 0)); // 29.9 fails, result depends on mesh precision
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(-30, 0, 0));
@@ -982,31 +980,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_libccd)
   pose_obb.setTranslation(Vec3f(-30, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1038,31 +1036,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_libccd)
   // s1 is mesh, s2 is shape --> collision free
   // all are reasonable
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(15.01, 0, 0));
@@ -1070,31 +1068,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_libccd)
   pose_obb.setTranslation(Vec3f(15.01, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(14.99, 0, 0));
@@ -1102,31 +1100,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_libccd)
   pose_obb.setTranslation(Vec3f(14.99, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 }
 
@@ -1158,31 +1156,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_libccd)
   // s1 is mesh, s2 is shape --> collision free
   // all are reasonable
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(22.4, 0, 0));
@@ -1190,31 +1188,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_libccd)
   pose_obb.setTranslation(Vec3f(22.4, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(22.51, 0, 0));
@@ -1222,31 +1220,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_libccd)
   pose_obb.setTranslation(Vec3f(22.51, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1277,31 +1275,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_cylindercylinder_libccd)
   pose_obb.setTranslation(Vec3f(9.99, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(10.01, 0, 0));
@@ -1309,31 +1307,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_cylindercylinder_libccd)
   pose_obb.setTranslation(Vec3f(10.01, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1364,31 +1362,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_libccd)
   pose_obb.setTranslation(Vec3f(9.9, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(10.1, 0, 0));
@@ -1396,31 +1394,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_libccd)
   pose_obb.setTranslation(Vec3f(10.1, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(0, 0, 9.9));
@@ -1428,31 +1426,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_libccd)
   pose_obb.setTranslation(Vec3f(0, 0, 9.9));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(0, 0, 10.1));
@@ -1460,31 +1458,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_libccd)
   pose_obb.setTranslation(Vec3f(0, 0, 10.1));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver1, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver1, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver1, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1506,6 +1504,8 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   generateBVHModel(s2_obb, s2, Transform3f(), 16, 16);
 
   CollisionRequest request;
+  request.gjk_solver_type = GST_INDEP;
+
   CollisionResult result;
 
   bool res;
@@ -1519,31 +1519,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   // s1 is mesh, s2 is shape --> collision free
   // all are reasonable
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(40, 0, 0));
@@ -1551,31 +1551,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   pose_obb.setTranslation(Vec3f(40, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   
   pose.setTranslation(Vec3f(30, 0, 0));
@@ -1583,31 +1583,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   pose_obb.setTranslation(Vec3f(30, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   
   pose.setTranslation(Vec3f(29.9, 0, 0));
@@ -1615,31 +1615,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   pose_obb.setTranslation(Vec3f(29.8, 0, 0)); // 29.9 fails, result depends on mesh precision
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
 
@@ -1648,31 +1648,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   pose_obb.setTranslation(Vec3f(-29.8, 0, 0)); // 29.9 fails, result depends on mesh precision
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(-30, 0, 0));
@@ -1680,31 +1680,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spheresphere_GJK)
   pose_obb.setTranslation(Vec3f(-30, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1724,6 +1724,8 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_GJK)
   generateBVHModel(s2_obb, s2, Transform3f());
 
   CollisionRequest request;
+  request.gjk_solver_type = GST_INDEP;
+
   CollisionResult result;
 
   bool res;
@@ -1736,31 +1738,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_GJK)
   // s1 is mesh, s2 is shape --> collision free
   // all are reasonable
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(15.01, 0, 0));
@@ -1768,31 +1770,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_GJK)
   pose_obb.setTranslation(Vec3f(15.01, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(14.99, 0, 0));
@@ -1800,31 +1802,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_boxbox_GJK)
   pose_obb.setTranslation(Vec3f(14.99, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 }
 
@@ -1844,6 +1846,8 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_GJK)
   generateBVHModel(s2_obb, s2, Transform3f());
 
   CollisionRequest request;
+  request.gjk_solver_type = GST_INDEP;
+
   CollisionResult result;
 
   bool res;
@@ -1856,31 +1860,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_GJK)
   // s1 is mesh, s2 is shape --> collision free
   // all are reasonable
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(22.4, 0, 0));
@@ -1888,31 +1892,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_GJK)
   pose_obb.setTranslation(Vec3f(22.4, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(22.51, 0, 0));
@@ -1920,31 +1924,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_spherebox_GJK)
   pose_obb.setTranslation(Vec3f(22.51, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -1964,6 +1968,8 @@ BOOST_AUTO_TEST_CASE(consistency_collision_cylindercylinder_GJK)
   generateBVHModel(s2_obb, s2, Transform3f(), 16, 16);
 
   CollisionRequest request;
+  request.gjk_solver_type = GST_INDEP;
+
   CollisionResult result;
 
   bool res;
@@ -1975,31 +1981,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_cylindercylinder_GJK)
   pose_obb.setTranslation(Vec3f(9.99, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(10.01, 0, 0));
@@ -2007,31 +2013,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_cylindercylinder_GJK)
   pose_obb.setTranslation(Vec3f(10.01, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
 
@@ -2051,6 +2057,8 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_GJK)
   generateBVHModel(s2_obb, s2, Transform3f(), 16, 16);
 
   CollisionRequest request;
+  request.gjk_solver_type = GST_INDEP;
+
   CollisionResult result;
 
   bool res;
@@ -2062,31 +2070,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_GJK)
   pose_obb.setTranslation(Vec3f(9.9, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(10.1, 0, 0));
@@ -2094,31 +2102,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_GJK)
   pose_obb.setTranslation(Vec3f(10.1, 0, 0));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 
   pose.setTranslation(Vec3f(0, 0, 9.9));
@@ -2126,31 +2134,31 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_GJK)
   pose_obb.setTranslation(Vec3f(0, 0, 9.9));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK(res);
 
   pose.setTranslation(Vec3f(0, 0, 10.1));
@@ -2158,30 +2166,30 @@ BOOST_AUTO_TEST_CASE(consistency_collision_conecone_GJK)
   pose_obb.setTranslation(Vec3f(0, 0, 10.1));
 
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_aabb, pose_aabb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2_obb, pose_obb, &s1, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_aabb, pose_aabb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, &solver2, request, result) > 0);
+  res = (collide(&s1, Transform3f(), &s2_obb, pose_obb, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_aabb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_aabb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s2, pose, &s1_obb, Transform3f(), &solver2, request, result) > 0);
+  res = (collide(&s2, pose, &s1_obb, Transform3f(), request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
   result.clear();
-  res = (collide(&s1_aabb, Transform3f(), &s2, pose, &solver2, request, result) > 0);
+  res = (collide(&s1_aabb, Transform3f(), &s2, pose, request, result) > 0);
   BOOST_CHECK_FALSE(res);
 }
diff --git a/test/test_fcl_utility.cpp b/test/test_fcl_utility.cpp
index 300c69ad..e5c0404b 100644
--- a/test/test_fcl_utility.cpp
+++ b/test/test_fcl_utility.cpp
@@ -1,5 +1,6 @@
 #include "test_fcl_utility.h"
 #include "fcl/collision.h"
+#include "fcl/continuous_collision.h"
 #include "fcl/distance.h"
 #include <cstdio>
 #include <cstddef>
@@ -359,9 +360,9 @@ bool defaultDistanceFunction(CollisionObject* o1, CollisionObject* o2, void* cda
 
 bool defaultContinuousCollisionFunction(ContinuousCollisionObject* o1, ContinuousCollisionObject* o2, void* cdata_)
 {
-  CollisionData* cdata = static_cast<CollisionData*>(cdata_);
-  const CollisionRequest& request = cdata->request;
-  CollisionResult& result = cdata->result;
+  ContinuousCollisionData* cdata = static_cast<ContinuousCollisionData*>(cdata_);
+  const ContinuousCollisionRequest& request = cdata->request;
+  ContinuousCollisionResult& result = cdata->result;
 
   if(cdata->done) return true;
 
diff --git a/test/test_fcl_utility.h b/test/test_fcl_utility.h
index 173cbafd..f3341504 100644
--- a/test/test_fcl_utility.h
+++ b/test/test_fcl_utility.h
@@ -145,6 +145,24 @@ struct DistanceData
 
 };
 
+/// @brief Continuous collision data stores the continuous collision request and result given the continuous collision algorithm.
+struct ContinuousCollisionData
+{
+  ContinuousCollisionData()
+  {
+    done = false;
+  }
+
+  /// @brief Continuous collision request
+  ContinuousCollisionRequest request;
+
+  /// @brief Continuous collision result
+  ContinuousCollisionResult result;
+
+  /// @brief Whether the continuous collision iteration can stop
+  bool done;
+};
+
 
 
 /// @brief Default collision callback for two objects o1 and o2 in broad phase. return value means whether the broad phase can stop now.
-- 
GitLab