diff --git a/src/distance_capsule_capsule.cpp b/src/distance_capsule_capsule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..112a1ff6cef93ebae20a8507c15d61a55b5adea1
--- /dev/null
+++ b/src/distance_capsule_capsule.cpp
@@ -0,0 +1,373 @@
+// Geometric Tools, LLC
+// Copyright (c) 1998-2011
+// Distributed under the Boost Software License, Version 1.0.
+// http://www.boost.org/LICENSE_1_0.txt
+// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
+//
+// Modified by Florent Lamiraux 2014
+
+#include <cmath>
+#include <limits>
+#include <fcl/math/transform.h>
+#include <fcl/shape/geometric_shapes.h>
+#include "distance_func_matrix.h"
+
+// Note that partial specialization of template functions is not allowed.
+// Therefore, two implementations with the default narrow phase solvers are
+// provided. If another narrow phase solver were to be used, the default
+// template implementation would be called, unless the function is also
+// specialized for this new type.
+//
+// One solution would be to make narrow phase solvers derive from an abstract
+// class and specialize the template for this abstract class.
+namespace fcl {
+  class GJKSolver_libccd;
+  class GJKSolver_indep;
+
+  template <>
+  FCL_REAL ShapeShapeDistance <Capsule, Capsule, GJKSolver_libccd>
+  (const CollisionGeometry* o1, const Transform3f& tf1,
+   const CollisionGeometry* o2, const Transform3f& tf2,
+   const GJKSolver_libccd*, const DistanceRequest& request,
+   DistanceResult& result)
+  {
+    const Capsule* c1 = static_cast <const Capsule*> (o1);
+    const Capsule* c2 = static_cast <const Capsule*> (o2);
+
+    // We assume that capsules are centered at the origin.
+    fcl::Vec3f center1 = tf1.getTranslation ();
+    fcl::Vec3f center2 = tf2.getTranslation ();
+    // We assume that capsules are oriented along z-axis.
+    fcl::Vec3f direction1 = tf1.getRotation ().getColumn (2);
+    fcl::Vec3f direction2 = tf2.getRotation ().getColumn (2);
+    FCL_REAL halfLength1 = 0.5*c1->lz;
+    FCL_REAL halfLength2 = 0.5*c2->lz;
+
+    Vec3f diff = center1 - center2;
+    FCL_REAL a01 = -direction1.dot (direction2);
+    FCL_REAL b0 = diff.dot (direction1);
+    FCL_REAL b1 = -diff.dot (direction2);
+    FCL_REAL c = diff.sqrLength ();
+    FCL_REAL det = fabs (1.0 - a01*a01);
+    FCL_REAL s1, s2, sqrDist, extDet0, extDet1, tmpS0, tmpS1;
+    FCL_REAL epsilon = std::numeric_limits<FCL_REAL>::epsilon () * 100;
+
+    if (det >= epsilon) {
+      // Segments are not parallel.
+      s1 = a01*b1 - b0;
+      s2 = a01*b0 - b1;
+      extDet0 = halfLength1*det;
+      extDet1 = halfLength2*det;
+
+      if (s1 >= -extDet0) {
+	if (s1 <= extDet0) {
+	  if (s2 >= -extDet1) {
+	    if (s2 <= extDet1) {  // region 0 (interior)
+	      // Minimum at interior points of segments.
+	      FCL_REAL invDet = (1.0)/det;
+	      s1 *= invDet;
+	      s2 *= invDet;
+	      sqrDist = s1*(s1 + a01*s2 + 2.0*b0) +
+		s2*(a01*s1 + s2 + 2.0*b1) + c;
+	    }
+	    else { // region 3 (side)
+	      s2 = halfLength2;
+	      tmpS0 = -(a01*s2 + b0);
+	      if (tmpS0 < -halfLength1) {
+		s1 = -halfLength1;
+		sqrDist = s1*(s1 - 2.0*tmpS0) +
+		  s2*(s2 + 2.0*b1) + c;
+	      }
+	      else if (tmpS0 <= halfLength1) {
+		s1 = tmpS0;
+		sqrDist = -s1*s1 + s2*(s2 + 2.0*b1) + c;
+	      }
+	      else {
+		s1 = halfLength1;
+		sqrDist = s1*(s1 - 2.0*tmpS0) +
+		  s2*(s2 + 2.0*b1) + c;
+	      }
+	    }
+	  }
+	  else { // region 7 (side)
+	    s2 = -halfLength2;
+	    tmpS0 = -(a01*s2 + b0);
+	    if (tmpS0 < -halfLength1) {
+	      s1 = -halfLength1;
+	      sqrDist = s1*(s1 - 2.0*tmpS0) +
+		s2*(s2 + 2.0*b1) + c;
+	    } else if (tmpS0 <= halfLength1) {
+	      s1 = tmpS0;
+	      sqrDist = -s1*s1 + s2*(s2 + 2.0*b1) + c;
+	    } else {
+	      s1 = halfLength1;
+	      sqrDist = s1*(s1 - 2.0*tmpS0) +
+		s2*(s2 + 2.0*b1) + c;
+	    }
+	  }
+	}
+	else {
+	  if (s2 >= -extDet1) {
+	    if (s2 <= extDet1) {  // region 1 (side)
+	      s1 = halfLength1;
+	      tmpS1 = -(a01*s1 + b1);
+	      if (tmpS1 < -halfLength2) {
+		s2 = -halfLength2;
+		sqrDist = s2*(s2 - 2.0*tmpS1) +
+		  s1*(s1 + 2.0*b0) + c;
+	      }
+	      else if (tmpS1 <= halfLength2) {
+		s2 = tmpS1;
+		sqrDist = -s2*s2 + s1*(s1 + 2.0*b0) + c;
+	      }
+	      else {
+		s2 = halfLength2;
+		sqrDist = s2*(s2 - 2.0*tmpS1) +
+		  s1*(s1 + 2.0*b0) + c;
+	      }
+	    }
+	    else { // region 2 (corner)
+	      s2 = halfLength2;
+	      tmpS0 = -(a01*s2 + b0);
+	      if (tmpS0 < -halfLength1) {
+		s1 = -halfLength1;
+		sqrDist = s1*(s1 - 2.0*tmpS0) +
+		  s2*(s2 + 2.0*b1) + c;
+	      }
+	      else if (tmpS0 <= halfLength1) {
+		s1 = tmpS0;
+		sqrDist = -s1*s1 + s2*(s2 + 2.0*b1) + c;
+	      }
+	      else {
+		s1 = halfLength1;
+		tmpS1 = -(a01*s1 + b1);
+		if (tmpS1 < -halfLength2) {
+		  s2 = -halfLength2;
+		  sqrDist = s2*(s2 - 2.0*tmpS1) +
+		    s1*(s1 + 2.0*b0) + c;
+		}
+		else if (tmpS1 <= halfLength2) {
+		  s2 = tmpS1;
+		  sqrDist = -s2*s2 + s1*(s1 + 2.0*b0) + c;
+		}
+		else {
+		  s2 = halfLength2;
+		  sqrDist = s2*(s2 - 2.0*tmpS1) +
+		    s1*(s1 + 2.0*b0) + c;
+		}
+	      }
+	    }
+	  }
+	  else {  // region 8 (corner)
+	    s2 = -halfLength2;
+	    tmpS0 = -(a01*s2 + b0);
+	    if (tmpS0 < -halfLength1) {
+	      s1 = -halfLength1;
+	      sqrDist = s1*(s1 - 2.0*tmpS0) +
+		s2*(s2 + 2.0*b1) + c;
+	    }
+	    else if (tmpS0 <= halfLength1) {
+	      s1 = tmpS0;
+	      sqrDist = -s1*s1 + s2*(s2 + 2.0*b1) + c;
+	    }
+	    else {
+	      s1 = halfLength1;
+	      tmpS1 = -(a01*s1 + b1);
+	      if (tmpS1 > halfLength2) {
+		s2 = halfLength2;
+		sqrDist = s2*(s2 - 2.0*tmpS1) +
+		  s1*(s1 + 2.0*b0) + c;
+	      }
+	      else if (tmpS1 >= -halfLength2) {
+		s2 = tmpS1;
+		sqrDist = -s2*s2 + s1*(s1 + 2.0*b0) + c;
+	      }
+	      else {
+		s2 = -halfLength2;
+		sqrDist = s2*(s2 - 2.0*tmpS1) +
+		  s1*(s1 + 2.0*b0) + c;
+	      }
+	    }
+	  }
+	}
+      }
+      else {
+	if (s2 >= -extDet1) {
+	  if (s2 <= extDet1) { // region 5 (side)
+	    s1 = -halfLength1;
+	    tmpS1 = -(a01*s1 + b1);
+	    if (tmpS1 < -halfLength2) {
+	      s2 = -halfLength2;
+	      sqrDist = s2*(s2 - 2.0*tmpS1) +
+		s1*(s1 + 2.0*b0) + c;
+	    }
+	    else if (tmpS1 <= halfLength2) {
+	      s2 = tmpS1;
+	      sqrDist = -s2*s2 + s1*(s1 + 2.0*b0) + c;
+	    }
+	    else {
+	      s2 = halfLength2;
+	      sqrDist = s2*(s2 - 2.0*tmpS1) +
+		s1*(s1 + 2.0*b0) + c;
+	    }
+	  }
+	  else { // region 4 (corner)
+	    s2 = halfLength2;
+	    tmpS0 = -(a01*s2 + b0);
+	    if (tmpS0 > halfLength1) {
+	      s1 = halfLength1;
+	      sqrDist = s1*(s1 - 2.0*tmpS0) +
+		s2*(s2 + 2.0*b1) + c;
+	    }
+	    else if (tmpS0 >= -halfLength1) {
+	      s1 = tmpS0;
+	      sqrDist = -s1*s1 + s2*(s2 + 2.0*b1) + c;
+	    }
+	    else {
+	      s1 = -halfLength1;
+	      tmpS1 = -(a01*s1 + b1);
+	      if (tmpS1 < -halfLength2) {
+		s2 = -halfLength2;
+		sqrDist = s2*(s2 - 2.0*tmpS1) +
+		  s1*(s1 + 2.0*b0) + c;
+	      }
+	      else if (tmpS1 <= halfLength2) {
+		s2 = tmpS1;
+		sqrDist = -s2*s2 + s1*(s1 + 2.0*b0) + c;
+	      }
+	      else {
+		s2 = halfLength2;
+		sqrDist = s2*(s2 - 2.0*tmpS1) +
+		  s1*(s1 + 2.0*b0) + c;
+	      }
+	    }
+	  }
+	}
+	else {  // region 6 (corner)
+	  s2 = -halfLength2;
+	  tmpS0 = -(a01*s2 + b0);
+	  if (tmpS0 > halfLength1) {
+	    s1 = halfLength1;
+	    sqrDist = s1*(s1 - 2.0*tmpS0) +
+	      s2*(s2 + 2.0*b1) + c;
+	  }
+	  else if (tmpS0 >= -halfLength1) {
+	    s1 = tmpS0;
+	    sqrDist = -s1*s1 + s2*(s2 + 2.0*b1) + c;
+	  }
+	  else {
+	    s1 = -halfLength1;
+	    tmpS1 = -(a01*s1 + b1);
+	    if (tmpS1 < -halfLength2) {
+	      s2 = -halfLength2;
+	      sqrDist = s2*(s2 - 2.0*tmpS1) +
+		s1*(s1 + 2.0*b0) + c;
+	    }
+	    else if (tmpS1 <= halfLength2) {
+	      s2 = tmpS1;
+	      sqrDist = -s2*s2 + s1*(s1 + 2.0*b0) + c;
+	    }
+	    else {
+	      s2 = halfLength2;
+	      sqrDist = s2*(s2 - 2.0*tmpS1) +
+		s1*(s1 + 2.0*b0) + c;
+	    }
+	  }
+	}
+      }
+    }
+    else {
+      // The segments are parallel.  The average b0 term is designed to
+      // ensure symmetry of the function.  That is, dist(seg0,seg1) and
+      // dist(seg1,seg0) should produce the same number.
+      FCL_REAL e0pe1 = halfLength1 + halfLength2;
+      FCL_REAL sign = (a01 > 0.0 ? -1.0 : 1.0);
+      FCL_REAL b0Avr = (0.5)*(b0 - sign*b1);
+      FCL_REAL lambda = -b0Avr;
+      if (lambda < -e0pe1) {
+	lambda = -e0pe1;
+      }
+      else if (lambda > e0pe1) {
+	lambda = e0pe1;
+      }
+
+      s2 = -sign*lambda*halfLength2/e0pe1;
+      s1 = lambda + sign*s2;
+      sqrDist = lambda*(lambda + 2.0*b0Avr) + c;
+    }
+
+    Vec3f closestOnSegment1 = center1 + s1*direction1;
+    Vec3f closestOnSegment2 = center2 + s2*direction2;
+
+    Vec3f unitVector = closestOnSegment2 - closestOnSegment1;
+    FCL_REAL distance = sqrt (sqrDist);
+    if (distance >= epsilon) {
+      unitVector /= distance;
+    } else {
+      unitVector.setZero ();
+    }
+    // Update distance result.
+    result.min_distance = distance - c1->radius - c2->radius;
+    if (request.enable_nearest_points) {
+      result.nearest_points [0] = closestOnSegment1 + c1->radius * unitVector;
+      result.nearest_points [1] = closestOnSegment2 - c2->radius * unitVector;
+    }
+    result.o1 = o1;
+    result.o2 = o2;
+    result.b1 = -1;
+    result.b2 = -1;
+    return result.min_distance;
+  }
+
+  template <>
+  FCL_REAL ShapeShapeDistance <Capsule, Capsule, GJKSolver_indep>
+  (const CollisionGeometry* o1, const Transform3f& tf1,
+   const CollisionGeometry* o2, const Transform3f& tf2,
+   const GJKSolver_indep*, const DistanceRequest& request,
+   DistanceResult& result)
+  {
+    GJKSolver_libccd* unused = 0x0;
+    return ShapeShapeDistance <Capsule, Capsule, GJKSolver_libccd>
+      (o1, tf1, o2, tf2, unused, request, result);
+  }
+
+  template <>
+  std::size_t ShapeShapeCollide <Capsule, Capsule, GJKSolver_indep>
+  (const CollisionGeometry* o1, const Transform3f& tf1,
+   const CollisionGeometry* o2, const Transform3f& tf2,
+   const GJKSolver_indep*, const CollisionRequest& request,
+   CollisionResult& result)
+  {
+    GJKSolver_libccd* unused = 0x0;
+    DistanceResult distanceResult;
+    DistanceRequest distanceRequest (request.enable_contact);
+
+    FCL_REAL distance = ShapeShapeDistance <Capsule, Capsule, GJKSolver_libccd>
+      (o1, tf1, o2, tf2, unused, distanceRequest, distanceResult);
+
+    if (distance <= 0) {
+      if (request.enable_contact) {
+	Contact contact (o1, o2, distanceResult.b1, distanceResult.b2);
+	const Vec3f& p1 = distanceResult.nearest_points [0];
+	const Vec3f& p2 = distanceResult.nearest_points [1];
+	contact.pos = .5*(p1+p2);
+	contact.normal = (p2-p1)/(p2-p1).length ();
+	result.addContact (contact);
+      }
+      return 1;
+    }
+    return 0;
+  }
+
+  template<>
+  std::size_t ShapeShapeCollide <Capsule, Capsule, GJKSolver_libccd>
+  (const CollisionGeometry* o1, const Transform3f& tf1,
+   const CollisionGeometry* o2, const Transform3f& tf2,
+   const GJKSolver_libccd* nsolver, const CollisionRequest& request,
+   CollisionResult& result)
+  {
+    GJKSolver_indep* unused = 0x0;
+    return ShapeShapeCollide <Capsule, Capsule, GJKSolver_indep>
+      (o1, tf1, o2, tf2, unused, request, result);
+  }
+} // namespace fcl
diff --git a/src/distance_func_matrix.h b/src/distance_func_matrix.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4933c69d3443065b79d1e9cbd4889acfb2e47e9
--- /dev/null
+++ b/src/distance_func_matrix.h
@@ -0,0 +1,53 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2014, CNRS-LAAS
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Willow Garage, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \author Florent Lamiraux */
+
+#include <fcl/collision_data.h>
+
+namespace fcl {
+  template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver>
+    FCL_REAL ShapeShapeDistance
+    (const CollisionGeometry* o1, const Transform3f& tf1,
+     const CollisionGeometry* o2, const Transform3f& tf2,
+     const NarrowPhaseSolver* nsolver, const DistanceRequest& request,
+     DistanceResult& result);
+
+  template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver>
+    std::size_t ShapeShapeCollide
+    (const CollisionGeometry* o1, const Transform3f& tf1,
+     const CollisionGeometry* o2, const Transform3f& tf2, 
+     const NarrowPhaseSolver* nsolver, const CollisionRequest& request,
+     CollisionResult& result);
+}
diff --git a/test/test_fcl_capsule_capsule.cpp b/test/test_fcl_capsule_capsule.cpp
index 72c2661a03a87f37c368010cbc92374f6d010a4a..4e77a4387be132ef6261168c14b876323506c749 100644
--- a/test/test_fcl_capsule_capsule.cpp
+++ b/test/test_fcl_capsule_capsule.cpp
@@ -48,7 +48,7 @@
 #include <fcl/shape/geometric_shapes.h>
 
 using namespace fcl;
-typedef boost::shared_ptr <fcl::CollisionGeometry> CollisionGeometryPtr_t;
+typedef boost::shared_ptr <CollisionGeometry> CollisionGeometryPtr_t;
 
 BOOST_AUTO_TEST_CASE(distance_capsulecapsule_origin)
 {
@@ -62,8 +62,8 @@ BOOST_AUTO_TEST_CASE(distance_capsulecapsule_origin)
   CollisionObject o2 (s2, tf2);
 
   // Enable computation of nearest points
-  fcl::DistanceRequest distanceRequest (true);
-  fcl::DistanceResult distanceResult;
+  DistanceRequest distanceRequest (true);
+  DistanceResult distanceResult;
 
   distance (&o1, &o2, distanceRequest, distanceResult);
 
@@ -89,8 +89,8 @@ BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformXY)
   CollisionObject o2 (s2, tf2);
 
   // Enable computation of nearest points
-  fcl::DistanceRequest distanceRequest (true);
-  fcl::DistanceResult distanceResult;
+  DistanceRequest distanceRequest (true);
+  DistanceResult distanceResult;
 
   distance (&o1, &o2, distanceRequest, distanceResult);
 
@@ -117,8 +117,8 @@ BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformZ)
   CollisionObject o2 (s2, tf2);
 
   // Enable computation of nearest points
-  fcl::DistanceRequest distanceRequest (true);
-  fcl::DistanceResult distanceResult;
+  DistanceRequest distanceRequest (true);
+  DistanceResult distanceResult;
 
   distance (&o1, &o2, distanceRequest, distanceResult);
 
@@ -146,8 +146,8 @@ BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformZ2)
   CollisionObject o2 (s2, tf2);
 
   // Enable computation of nearest points
-  fcl::DistanceRequest distanceRequest (true);
-  fcl::DistanceResult distanceResult;
+  DistanceRequest distanceRequest (true);
+  DistanceResult distanceResult;
 
   distance (&o1, &o2, distanceRequest, distanceResult);
 
@@ -160,8 +160,8 @@ BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformZ2)
 	    << ", p2 = " << distanceResult.nearest_points [1]
 	    << ", distance = " << distanceResult.min_distance << std::endl;
 
-  const fcl::Vec3f& p1 = distanceResult.nearest_points [0];
-  const fcl::Vec3f& p2 = distanceResult.nearest_points [1];
+  const Vec3f& p1 = distanceResult.nearest_points [0];
+  const Vec3f& p2 = distanceResult.nearest_points [1];
 
   BOOST_CHECK_CLOSE(distanceResult.min_distance, 10.1, 1e-6);
   CHECK_CLOSE_TO_0 (p1 [0], 1e-4);