diff --git a/trunk/fcl/include/fcl/conservative_advancement.h b/trunk/fcl/include/fcl/conservative_advancement.h
index fdaa8e656aa884e6523c59b27b16358ded18de5f..0fe7b2d3b6a9b5a3592ff3c58bb9ce9b23d9ead8 100644
--- a/trunk/fcl/include/fcl/conservative_advancement.h
+++ b/trunk/fcl/include/fcl/conservative_advancement.h
@@ -41,20 +41,17 @@
 #include "fcl/vec_3f.h"
 #include "fcl/collision_object.h"
 #include "fcl/collision_data.h"
+#include "fcl/motion_base.h"
 
 
 namespace fcl
 {
 
-
+template<typename BV>
 int conservativeAdvancement(const CollisionObject* o1,
-                            const Vec3f R1_1[3], const Vec3f& T1_1,
-                            const Vec3f R1_2[3], const Vec3f& T1_2,
-                            const Vec3f& O1,
+                            MotionBase<BV>* motion1,
                             const CollisionObject* o2,
-                            const Vec3f R2_1[3], const Vec3f& T2_1,
-                            const Vec3f R2_2[3], const Vec3f& T2_2,
-                            const Vec3f& O2,
+                            MotionBase<BV>* motion2,
                             int num_max_contacts, bool exhaustive, bool enable_contact,
                             std::vector<Contact>& contacts,
                             BVH_REAL& toc);
diff --git a/trunk/fcl/include/fcl/motion.h b/trunk/fcl/include/fcl/motion.h
index 6d7ae88e05930e5d1ca557b85cc1a49c3fb00e4a..0df7beaf470943472cc0fd1598fe85b6b9d9f2c4 100644
--- a/trunk/fcl/include/fcl/motion.h
+++ b/trunk/fcl/include/fcl/motion.h
@@ -46,6 +46,165 @@
 namespace fcl
 {
 
+template<typename BV>
+class ScrewMotion : public MotionBase<BV>
+{
+public:
+  /** Default transformations are all identities */
+  ScrewMotion()
+  {
+    /** Default angular velocity is zero */
+    axis = Vec3f(1, 0, 0);
+    angular_vel = 0;
+
+    /** Default reference point is local zero point */
+
+    /** Default linear velocity is zero */
+    linear_vel = 0;
+  }
+
+  /** \brief Construct motion from the initial rotation/translation and goal rotation/translation */
+  ScrewMotion(const Vec3f R1[3], const Vec3f& T1,
+              const Vec3f R2[3], const Vec3f& T2)
+  {
+    t1 = SimpleTransform(R1, T1);
+    t2 = SimpleTransform(R2, T2);
+
+    /** Current time is zero, so the transformation is t1 */
+    t = t1;
+
+    computeScrewParameter();
+  }
+
+  /** \brief Integrate the motion from 0 to dt
+   * We compute the current transformation from zero point instead of from last integrate time, for precision.
+   */
+  bool integrate(double dt)
+  {
+    if(dt > 1) dt = 1;
+
+    t.setQuatRotation(absoluteRotation(dt));
+    t.setTranslation(p + axis * (dt * linear_vel) - t.getQuatRotation().transform(p));
+
+    return true;
+  }
+
+  /** \brief Compute the motion bound for a bounding volume along a given direction n
+   * For general BV, not implemented so return trivial 0
+   */
+  BVH_REAL computeMotionBound(const BV& bv, const Vec3f& n) const { return 0.0; }
+
+  BVH_REAL computeMotionBound(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& n) const
+  {
+    BVH_REAL proj_max = ((t1.getQuatRotation().transform(a) + t1.getTranslation() - p).cross(axis)).sqrLength();
+    BVH_REAL tmp;
+    tmp = ((t1.getQuatRotation().transform(b) + t1.getTranslation() - p).cross(axis)).sqrLength();
+    if(tmp > proj_max) proj_max = tmp;
+    tmp = ((t1.getQuatRotation().transform(c) + t1.getTranslation() - p).cross(axis)).sqrLength();
+    if(tmp > proj_max) proj_max = tmp;
+
+    proj_max = sqrt(proj_max);
+
+    BVH_REAL v_dot_n = axis.dot(n) * linear_vel;
+    BVH_REAL w_cross_n = (axis.cross(n)).length() * angular_vel;
+    BVH_REAL mu = v_dot_n + w_cross_n * proj_max;
+
+    return mu;
+  }
+
+  /** \brief Get the rotation and translation in current step */
+  void getCurrentTransform(Vec3f R[3], Vec3f& T) const
+  {
+    for(int i = 0; i < 3; ++i)
+    {
+      R[i] = t.getRotation()[i];
+    }
+
+    T = t.getTranslation();
+  }
+
+  void getCurrentRotation(Vec3f R[3]) const
+  {
+    for(int i = 0; i < 3; ++i)
+      R[i] = t.getRotation()[i];
+  }
+
+  void getCurrentTranslation(Vec3f& T) const
+  {
+    T = t.getTranslation();
+  }
+
+protected:
+  void computeScrewParameter()
+  {
+    SimpleQuaternion deltaq = t2.getQuatRotation() * t1.getQuatRotation().inverse();
+    deltaq.toAxisAngle(axis, angular_vel);
+    if(angular_vel < 0)
+    {
+      angular_vel = -angular_vel;
+      axis = -axis;
+    }
+
+    if(angular_vel < 1e-10)
+    {
+      angular_vel = 0;
+      axis = t2.getTranslation() - t1.getTranslation();
+      linear_vel = axis.length();
+      p = t1.getTranslation();
+    }
+    else
+    {
+      Vec3f o = t2.getTranslation() - t1.getTranslation();
+      p = (t1.getTranslation() + t2.getTranslation() + axis.cross(o) * (1.0 / tan(angular_vel / 2.0))) * 0.5;
+      linear_vel = o.dot(axis);
+    }
+  }
+
+  SimpleQuaternion deltaRotation(BVH_REAL dt) const
+  {
+    SimpleQuaternion res;
+    res.fromAxisAngle(axis, (BVH_REAL)(dt * angular_vel));
+    return res;
+  }
+
+  SimpleQuaternion absoluteRotation(BVH_REAL dt) const
+  {
+    SimpleQuaternion delta_t = deltaRotation(dt);
+    return delta_t * t1.getQuatRotation();
+  }
+
+  /** \brief The transformation at time 0 */
+  SimpleTransform t1;
+
+  /** \brief The transformation at time 1 */
+  SimpleTransform t2;
+
+  /** \brief The transformation at current time t */
+  SimpleTransform t;
+
+  /** \brief screw axis */
+  Vec3f axis;
+
+  /** \brief A point on the axis S */
+  Vec3f p;
+
+  /** \brief linear velocity along the axis */
+  BVH_REAL linear_vel;
+
+  /** \brief angular velocity */
+  BVH_REAL angular_vel;
+};
+
+
+/** \brief Compute the motion bound for a bounding volume along a given direction n
+ * according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||R0(ci) x w||. w is the angular axis (normalized)
+ * and ci are the endpoints of the generator primitives of RSS.
+ * Notice that all bv parameters are in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
+ */
+template<>
+BVH_REAL ScrewMotion<RSS>::computeMotionBound(const RSS& bv, const Vec3f& n) const;
+
+
 /** \brief Linear interpolation motion
  * Each Motion is assumed to have constant linear velocity and angular velocity
  * The motion is R(t)(p - p_ref) + p_ref + T(t)
@@ -57,7 +216,7 @@ template<typename BV>
 class InterpMotion : public MotionBase<BV>
 {
 public:
-  /** Default transformations are all identities */
+  /** \brief Default transformations are all identities */
   InterpMotion()
   {
     /** Default angular velocity is zero */
@@ -121,24 +280,24 @@ public:
   BVH_REAL computeMotionBound(const BV& bv, const Vec3f& n) const { return 0.0; }
 
   /** \brief Compute the motion bound for a triangle along a given direction n
-   * according to mu < |v * n| + ||w x n||(max||ci*||) where ||ci*|| = ||ci x w||. w is the angular axis (normalized)
+   * according to mu < |v * n| + ||w x n||(max||ci*||) where ||ci*|| = ||R0(ci) x w|| / \|w\|. w is the angular velocity
    * and ci are the triangle vertex coordinates.
    * Notice that the triangle is in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
    */
   BVH_REAL computeMotionBound(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& n) const
   {
-    BVH_REAL c_proj_max = ((a - reference_p).cross(angular_axis)).sqrLength();
+    BVH_REAL proj_max = ((t1.getQuatRotation().transform(a - reference_p)).cross(angular_axis)).sqrLength();
     BVH_REAL tmp;
-    tmp = ((b - reference_p).cross(angular_axis)).sqrLength();
-    if(tmp > c_proj_max) c_proj_max = tmp;
-    tmp = ((c - reference_p).cross(angular_axis)).sqrLength();
-    if(tmp > c_proj_max) c_proj_max = tmp;
+    tmp = ((t1.getQuatRotation().transform(b - reference_p)).cross(angular_axis)).sqrLength();
+    if(tmp > proj_max) proj_max = tmp;
+    tmp = ((t1.getQuatRotation().transform(c - reference_p)).cross(angular_axis)).sqrLength();
+    if(tmp > proj_max) proj_max = tmp;
 
-    c_proj_max = sqrt(c_proj_max);
+    proj_max = sqrt(proj_max);
 
     BVH_REAL v_dot_n = linear_vel.dot(n);
     BVH_REAL w_cross_n = (angular_axis.cross(n)).length() * angular_vel;
-    BVH_REAL mu = v_dot_n + w_cross_n * c_proj_max;
+    BVH_REAL mu = v_dot_n + w_cross_n * proj_max;
 
     return mu;
   }
@@ -180,16 +339,16 @@ protected:
   }
 
 
-  SimpleQuaternion deltaRotation(BVH_REAL t) const
+  SimpleQuaternion deltaRotation(BVH_REAL dt) const
   {
     SimpleQuaternion res;
-    res.fromAxisAngle(angular_axis, (BVH_REAL)(t * angular_vel));
+    res.fromAxisAngle(angular_axis, (BVH_REAL)(dt * angular_vel));
     return res;
   }
 
-  SimpleQuaternion absoluteRotation(BVH_REAL t) const
+  SimpleQuaternion absoluteRotation(BVH_REAL dt) const
   {
-    SimpleQuaternion delta_t = deltaRotation(t);
+    SimpleQuaternion delta_t = deltaRotation(dt);
     return delta_t * t1.getQuatRotation();
   }
 
@@ -217,7 +376,7 @@ protected:
 
 
 /** \brief Compute the motion bound for a bounding volume along a given direction n
- * according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||ci x w||. w is the angular axis (normalized)
+ * according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||R0(ci) x w||. w is the angular axis (normalized)
  * and ci are the endpoints of the generator primitives of RSS.
  * Notice that all bv parameters are in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
  */
diff --git a/trunk/fcl/include/fcl/traversal_node_bvhs.h b/trunk/fcl/include/fcl/traversal_node_bvhs.h
index 84fa30614492404e870cdddf3f9f2304648fb91d..6cdfd7a54a2dfc201fc4863d6dd7b4353390311f 100644
--- a/trunk/fcl/include/fcl/traversal_node_bvhs.h
+++ b/trunk/fcl/include/fcl/traversal_node_bvhs.h
@@ -951,8 +951,8 @@ public:
     last_tri_id1 = 0;
     last_tri_id2 = 0;
 
-    rel_err = 0.01;
-    abs_err = 0.01;
+    rel_err = 0;
+    abs_err = 0;
 
     min_distance = std::numeric_limits<BVH_REAL>::max();
   }
@@ -1061,7 +1061,7 @@ public:
   {
     delta_t = 1;
     toc = 0;
-    t_err = (BVH_REAL)0.001;
+    t_err = (BVH_REAL)0;
 
     w = w_;
 
@@ -1126,9 +1126,10 @@ public:
     BVH_REAL bound2 = motion2->computeMotionBound(q1, q2, q3, n);
 
     BVH_REAL bound = bound1 + bound2;
-    if(bound < d) bound = d;
 
-    BVH_REAL cur_delta_t = d / bound;
+    BVH_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;
@@ -1166,9 +1167,11 @@ public:
       BVH_REAL bound2 = motion2->computeMotionBound((this->tree2 + c2)->bv, n);
 
       BVH_REAL bound = bound1 + bound2;
-      if(bound < c) bound = c;
 
-      BVH_REAL cur_delta_t = c / bound;
+      BVH_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;
 
diff --git a/trunk/fcl/src/conservative_advancement.cpp b/trunk/fcl/src/conservative_advancement.cpp
index 2a167bc0b2216b5f37235d0e58d0fb1d7087a5e7..9e7e1fb940dcd5918f6339e49c9ffbcc28b638ca 100644
--- a/trunk/fcl/src/conservative_advancement.cpp
+++ b/trunk/fcl/src/conservative_advancement.cpp
@@ -46,14 +46,11 @@
 namespace fcl
 {
 
+template<typename BV>
 int conservativeAdvancement(const CollisionObject* o1,
-                            const Vec3f R1_1[3], const Vec3f& T1_1,
-                            const Vec3f R1_2[3], const Vec3f& T1_2,
-                            const Vec3f& O1,
+                            MotionBase<BV>* motion1,
                             const CollisionObject* o2,
-                            const Vec3f R2_1[3], const Vec3f& T2_1,
-                            const Vec3f R2_2[3], const Vec3f& T2_2,
-                            const Vec3f& O2,
+                            MotionBase<BV>* motion2,
                             int num_max_contacts, bool exhaustive, bool enable_contact,
                             std::vector<Contact>& contacts,
                             BVH_REAL& toc)
@@ -85,7 +82,16 @@ int conservativeAdvancement(const CollisionObject* o1,
   if(!initialize(cnode, *model1, *model2))
     std::cout << "initialize error" << std::endl;
 
-  relativeTransform(R1_1, T1_1, R2_1, T2_1, cnode.R, cnode.T);
+
+  Vec3f R1_0[3];
+  Vec3f R2_0[3];
+  Vec3f T1_0;
+  Vec3f T2_0;
+
+  motion1->getCurrentTransform(R1_0, T1_0);
+  motion2->getCurrentTransform(R2_0, T2_0);
+
+  relativeTransform(R1_0, T1_0, R2_0, T2_0, cnode.R, cnode.T);
 
   cnode.enable_statistics = false;
   cnode.num_max_contacts = num_max_contacts;
@@ -106,13 +112,10 @@ int conservativeAdvancement(const CollisionObject* o1,
 
   MeshConservativeAdvancementTraversalNodeRSS node;
 
-  initialize(node, *model1, *model2, R1_1, T1_1, R2_1, T2_1);
-
-  InterpMotion<RSS> motion1(R1_1, T1_1, R1_2, T1_2, O1);
-  InterpMotion<RSS> motion2(R2_1, T2_1, R2_2, T2_2, O2);
+  initialize(node, *model1, *model2, R1_0, T1_0, R2_0, T2_0);
 
-  node.motion1 = &motion1;
-  node.motion2 = &motion2;
+  node.motion1 = motion1;
+  node.motion2 = motion2;
 
 
   do
@@ -133,7 +136,7 @@ int conservativeAdvancement(const CollisionObject* o1,
 
     distanceRecurse(&node, 0, 0, NULL);
 
-    if(node.delta_t < node.t_err)
+    if(node.delta_t <= node.t_err)
     {
       // std::cout << node.delta_t << " " << node.t_err << std::endl;
       break;
@@ -160,4 +163,14 @@ int conservativeAdvancement(const CollisionObject* o1,
   return 0;
 }
 
+
+template int conservativeAdvancement<RSS>(const CollisionObject* o1,
+                                          MotionBase<RSS>* motion1,
+                                          const CollisionObject* o2,
+                                          MotionBase<RSS>* motion2,
+                                          int num_max_contacts, bool exhaustive, bool enable_contact,
+                                          std::vector<Contact>& contacts,
+                                          BVH_REAL& toc);
+
+
 }
diff --git a/trunk/fcl/src/motion.cpp b/trunk/fcl/src/motion.cpp
index cc20b2588d3ff755fced9fe060d303b6910c7332..6dffab0828f234315972de8d118edc4d98d732b9 100644
--- a/trunk/fcl/src/motion.cpp
+++ b/trunk/fcl/src/motion.cpp
@@ -43,13 +43,13 @@ namespace fcl
 template<>
 BVH_REAL InterpMotion<RSS>::computeMotionBound(const RSS& bv, const Vec3f& n) const
 {
-  BVH_REAL c_proj_max = ((bv.Tr - reference_p).cross(angular_axis)).sqrLength();
+  BVH_REAL c_proj_max = ((t1.getQuatRotation().transform(bv.Tr - reference_p)).cross(angular_axis)).sqrLength();
   BVH_REAL tmp;
-  tmp = ((bv.Tr + bv.axis[0] * bv.l[0] - reference_p).cross(angular_axis)).sqrLength();
+  tmp = ((t1.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0] - reference_p)).cross(angular_axis)).sqrLength();
   if(tmp > c_proj_max) c_proj_max = tmp;
-  tmp = ((bv.Tr + bv.axis[1] * bv.l[1] - reference_p).cross(angular_axis)).sqrLength();
+  tmp = ((t1.getQuatRotation().transform(bv.Tr + bv.axis[1] * bv.l[1] - reference_p)).cross(angular_axis)).sqrLength();
   if(tmp > c_proj_max) c_proj_max = tmp;
-  tmp = ((bv.Tr + bv.axis[0] * bv.l[0] + bv.axis[1] * bv.l[1] - reference_p).cross(angular_axis)).sqrLength();
+  tmp = ((t1.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0] + bv.axis[1] * bv.l[1] - reference_p)).cross(angular_axis)).sqrLength();
   if(tmp > c_proj_max) c_proj_max = tmp;
 
   c_proj_max = sqrt(c_proj_max);
@@ -61,4 +61,27 @@ BVH_REAL InterpMotion<RSS>::computeMotionBound(const RSS& bv, const Vec3f& n) co
   return mu;
 }
 
+template<>
+BVH_REAL ScrewMotion<RSS>::computeMotionBound(const RSS& bv, const Vec3f& n) const
+{
+  BVH_REAL c_proj_max = ((t1.getQuatRotation().transform(bv.Tr)).cross(axis)).sqrLength();
+  BVH_REAL tmp;
+  tmp = ((t1.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0])).cross(axis)).sqrLength();
+  if(tmp > c_proj_max) c_proj_max = tmp;
+  tmp = ((t1.getQuatRotation().transform(bv.Tr + bv.axis[1] * bv.l[1])).cross(axis)).sqrLength();
+  if(tmp > c_proj_max) c_proj_max = tmp;
+  tmp = ((t1.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0] + bv.axis[1] * bv.l[1])).cross(axis)).sqrLength();
+  if(tmp > c_proj_max) c_proj_max = tmp;
+
+  c_proj_max = sqrt(c_proj_max);
+
+  BVH_REAL v_dot_n = axis.dot(n) * linear_vel;
+  BVH_REAL w_cross_n = (axis.cross(n)).length() * angular_vel;
+  BVH_REAL origin_proj = ((t1.getTranslation() - p).cross(axis)).length();
+
+  BVH_REAL mu = v_dot_n + w_cross_n * (c_proj_max + bv.r + origin_proj);
+
+  return mu;
+}
+
 }
diff --git a/trunk/fcl/src/traversal_node_bvhs.cpp b/trunk/fcl/src/traversal_node_bvhs.cpp
index 1e1ed2376a7570697ec3002503c6ed2ee2c0e215..f8a278707071e49d101ca06a075504062460c88f 100644
--- a/trunk/fcl/src/traversal_node_bvhs.cpp
+++ b/trunk/fcl/src/traversal_node_bvhs.cpp
@@ -422,9 +422,11 @@ bool MeshConservativeAdvancementTraversalNode<OBB>::canStop(BVH_REAL c) const
     BVH_REAL bound2 = motion2->computeMotionBound(this->model2->getBV(c2).bv, n_transformed);
 
     BVH_REAL bound = bound1 + bound2;
-    if(bound < c) bound = c;
 
-    BVH_REAL cur_delta_t = c / bound;
+    BVH_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;
 
@@ -480,9 +482,11 @@ bool MeshConservativeAdvancementTraversalNode<RSS>::canStop(BVH_REAL c) const
     BVH_REAL bound2 = motion2->computeMotionBound(this->model2->getBV(c2).bv, n_transformed);
 
     BVH_REAL bound = bound1 + bound2;
-    if(bound < c) bound = c;
 
-    BVH_REAL cur_delta_t = c / bound;
+    BVH_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;
 
diff --git a/trunk/fcl/test/test_core_conservative_advancement.cpp b/trunk/fcl/test/test_core_conservative_advancement.cpp
index bf718d5f348ffcaf7b9cbbb66025ed6f7d722682..71141cf56443388a8b532d060c078d226ca8dd4d 100644
--- a/trunk/fcl/test/test_core_conservative_advancement.cpp
+++ b/trunk/fcl/test/test_core_conservative_advancement.cpp
@@ -43,22 +43,35 @@
 using namespace fcl;
 
 
-bool CA_ccd_Test(const Transform& tf1, const Transform& tf2,
-                 const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                 const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
-                 SplitMethodType split_method,
-                 bool use_COM,
-                 BVH_REAL& toc);
-
-bool interp_ccd_Test(const Transform& tf1, const Transform& tf2,
-                     const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                     const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
-                     SplitMethodType split_method,
-                     unsigned int nsamples,
-                     bool use_COM,
-                     BVH_REAL& toc);
-
-unsigned int n_dcd_samples = 10;
+bool CA_linear_Test(const Transform& tf1, const Transform& tf2,
+                    const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                    const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                    SplitMethodType split_method,
+                    bool use_COM,
+                    BVH_REAL& toc);
+
+bool CA_screw_Test(const Transform& tf1, const Transform& tf2,
+                   const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                   const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                   SplitMethodType split_method,
+                   BVH_REAL& toc);
+
+bool linear_interp_Test(const Transform& tf1, const Transform& tf2,
+                        const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                        const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                        SplitMethodType split_method,
+                        unsigned int nsamples,
+                        bool use_COM,
+                        BVH_REAL& toc);
+
+bool screw_interp_Test(const Transform& tf1, const Transform& tf2,
+                       const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                       const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                       SplitMethodType split_method,
+                       unsigned int nsamples,
+                       BVH_REAL& toc);
+
+unsigned int n_dcd_samples = 100;
 
 int main()
 {
@@ -70,7 +83,7 @@ int main()
   std::vector<Transform> transforms; // t0
   std::vector<Transform> transforms2; // t1
   BVH_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000};
-  BVH_REAL delta_trans[] = {10, 10, 10};
+  BVH_REAL delta_trans[] = {100, 100, 100};
   int n = 100;
 
   generateRandomTransform(extents, transforms, transforms2, delta_trans, 0.005 * 2 * 3.1415, n);
@@ -79,25 +92,33 @@ int main()
   {
     std::cout << i << std::endl;
     BVH_REAL toc;
-    bool res = CA_ccd_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, false, toc);
+    bool res = CA_linear_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, false, toc);
 
     BVH_REAL toc2;
-    bool res2 = CA_ccd_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, true, toc2);
+    bool res2 = CA_linear_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, true, toc2);
 
     BVH_REAL toc3;
-    bool res3 = interp_ccd_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, n_dcd_samples, false, toc3);
+    bool res3 = linear_interp_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, n_dcd_samples, false, toc3);
 
     BVH_REAL toc4;
-    bool res4 = interp_ccd_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, n_dcd_samples, true, toc4);
+    bool res4 = linear_interp_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, n_dcd_samples, true, toc4);
+
+    BVH_REAL toc5;
+    bool res5 = CA_screw_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, toc5);
+
+    BVH_REAL toc6;
+    bool res6 = screw_interp_Test(transforms[i], transforms2[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, n_dcd_samples, toc6);
 
 
     if(res) std::cout << "yes "; else std::cout << "no ";
     if(res2) std::cout << "yes "; else std::cout << "no ";
     if(res3) std::cout << "yes "; else std::cout << "no ";
     if(res4) std::cout << "yes "; else std::cout << "no ";
+    if(res5) std::cout << "yes "; else std::cout << "no ";
+    if(res6) std::cout << "yes "; else std::cout << "no ";
     std::cout << std::endl;
 
-    std::cout << toc << " " << toc2 << " " << toc3 << " " << toc4 << std::endl;
+    std::cout << toc << " " << toc2 << " " << toc3 << " " << toc4 << " " << toc5 << " " << toc6 << std::endl;
     std::cout << std::endl;
   }
 
@@ -106,12 +127,12 @@ int main()
 }
 
 
-bool CA_ccd_Test(const Transform& tf1, const Transform& tf2,
-                 const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                 const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
-                 SplitMethodType split_method,
-                 bool use_COM,
-                 BVH_REAL& toc)
+bool CA_linear_Test(const Transform& tf1, const Transform& tf2,
+                    const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                    const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                    SplitMethodType split_method,
+                    bool use_COM,
+                    BVH_REAL& toc)
 {
   BVHModel<RSS> m1;
   BVHModel<RSS> m2;
@@ -149,15 +170,60 @@ bool CA_ccd_Test(const Transform& tf1, const Transform& tf2,
     m2_ref *= (1.0 / vertices2.size());
   }
 
-  int b = conservativeAdvancement(&m1, tf1.R, tf1.T, tf2.R, tf2.T, m1_ref,
-                          &m2, R2, T2, R2, T2, m2_ref,
-                          1, false, false, contacts, toc);
+  InterpMotion<RSS> motion1(tf1.R, tf1.T, tf2.R, tf2.T, m1_ref);
+  InterpMotion<RSS> motion2(R2, T2, R2, T2, m2_ref);
+
+  int b = conservativeAdvancement(&m1, &motion1,
+                                  &m2, &motion2,
+                                  1, false, false, contacts, toc);
 
   return (b > 0);
 }
 
+bool CA_screw_Test(const Transform& tf1, const Transform& tf2,
+                   const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                   const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                   SplitMethodType split_method,
+                   BVH_REAL& toc)
+{
+  BVHModel<RSS> m1;
+  BVHModel<RSS> m2;
+
+  m1.bv_splitter.reset(new BVSplitter<RSS>(split_method));
+  m2.bv_splitter.reset(new BVSplitter<RSS>(split_method));
+
+  m1.beginModel();
+  m1.addSubModel(vertices1, triangles1);
+  m1.endModel();
 
-bool interp_ccd_Test(const Transform& tf1, const Transform& tf2,
+  m2.beginModel();
+  m2.addSubModel(vertices2, triangles2);
+  m2.endModel();
+
+  Vec3f R2[3];
+  Vec3f T2;
+  R2[0] = Vec3f(1, 0, 0);
+  R2[1] = Vec3f(0, 1, 0);
+  R2[2] = Vec3f(0, 0, 1);
+
+  std::vector<Contact> contacts;
+
+  Vec3f m1_ref;
+  Vec3f m2_ref;
+
+
+  ScrewMotion<RSS> motion1(tf1.R, tf1.T, tf2.R, tf2.T);
+  ScrewMotion<RSS> motion2(R2, T2, R2, T2);
+
+  int b = conservativeAdvancement(&m1, &motion1,
+                                  &m2, &motion2,
+                                  1, false, false, contacts, toc);
+
+
+  return (b > 0);
+
+}
+bool linear_interp_Test(const Transform& tf1, const Transform& tf2,
                      const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
                      const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
                      SplitMethodType split_method,
@@ -165,7 +231,6 @@ bool interp_ccd_Test(const Transform& tf1, const Transform& tf2,
                      bool use_COM,
                      BVH_REAL& toc)
 {
-
   BVHModel<RSS> m1;
   BVHModel<RSS> m2;
 
@@ -232,5 +297,73 @@ bool interp_ccd_Test(const Transform& tf1, const Transform& tf2,
     }
   }
 
+  toc = 1;
+  return false;
+}
+
+bool screw_interp_Test(const Transform& tf1, const Transform& tf2,
+                       const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
+                       const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2,
+                       SplitMethodType split_method,
+                       unsigned int nsamples,
+                       BVH_REAL& toc)
+{
+  BVHModel<RSS> m1;
+  BVHModel<RSS> m2;
+
+  m1.bv_splitter.reset(new BVSplitter<RSS>(split_method));
+  m2.bv_splitter.reset(new BVSplitter<RSS>(split_method));
+
+  m1.beginModel();
+  m1.addSubModel(vertices1, triangles1);
+  m1.endModel();
+
+  m2.beginModel();
+  m2.addSubModel(vertices2, triangles2);
+  m2.endModel();
+
+  Vec3f R2[3];
+  Vec3f T2;
+  R2[0] = Vec3f(1, 0, 0);
+  R2[1] = Vec3f(0, 1, 0);
+  R2[2] = Vec3f(0, 0, 1);
+
+  Vec3f m1_ref;
+  Vec3f m2_ref;
+
+
+  ScrewMotion<RSS> motion1(tf1.R, tf1.T, tf2.R, tf2.T);
+
+  for(unsigned int i = 0; i <= nsamples; ++i)
+  {
+    BVH_REAL curt = i / (BVH_REAL)nsamples;
+
+    Vec3f R[3];
+    Vec3f T;
+    motion1.integrate(curt);
+    motion1.getCurrentTransform(R, T);
+
+    m1.setTransform(R, T);
+    m2.setTransform(R2, T2);
+
+    MeshCollisionTraversalNodeRSS node;
+    if(!initialize(node, (const BVHModel<RSS>&)m1, (const BVHModel<RSS>&)m2))
+      std::cout << "initialize error" << std::endl;
+
+    node.enable_statistics = false;
+    node.num_max_contacts = 1;
+    node.exhaustive = false;
+    node.enable_contact = false;
+
+    collide(&node);
+
+    if(node.pairs.size() > 0)
+    {
+      toc = curt;
+      return true;
+    }
+  }
+
+  toc = 1;
   return false;
 }