diff --git a/.travis.yml b/.travis.yml
index 8a7593e12731348cb1ab3f9182ee4bcaac6fc217..b34dd4f9ceb367fb0765e9ef07f3e9aad5a94c61 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,30 +4,78 @@ env:
   global:
     - CTEST_PARALLEL_LEVEL=4
     - CTEST_OUTPUT_ON_FAILURE=1
+    - CXX_FLAGS_DEBUG="-O1"
+    - BUILD_PYTHON_INTERFACE=ON
     - MAKEFLAGS="-j2"
 
+cache:
+  ccache: true
+
 matrix:
   include:
-    - dist: trusty
-      compiler: gcc
+    - name: "Trusty - Release - g++"
       env: BUILD_TYPE=Release
-    - dist: xenial
-      compiler: gcc
+      dist: trusty
+      compiler: g++
+      addons:
+        apt:
+          packages:
+            - cmake
+            - libboost-all-dev
+            - libassimp-dev
+            - libeigen3-dev
+
+    - name: "Xenial - Release - g++"
       env: BUILD_TYPE=Release
-    - dist: bionic
-      compiler: gcc
+      dist: xenial
+      compiler: g++
+      addons:
+        apt:
+          packages:
+            - cmake
+            - libboost-all-dev
+            - libassimp-dev
+            - libeigen3-dev
+            - liboctomap-dev
+
+    - name: "Bionic - Release - g++"
       env: BUILD_TYPE=Release
-    - dist: bionic
-      compiler: gcc
+      dist: bionic
+      compiler: g++
+      addons:
+        apt:
+          packages:
+            - cmake
+            - libboost-all-dev
+            - libassimp-dev
+            - libeigen3-dev
+            - liboctomap-dev
+
+    - name: "Bionic - Debug - g++"
       env: BUILD_TYPE=Debug
-    - os: osx
-      compiler: clang
+      dist: bionic
+      compiler: g++
+      addons:
+        apt:
+          packages:
+            - cmake
+            - libboost-all-dev
+            - libassimp-dev
+            - libeigen3-dev
+            - liboctomap-dev
+
+    - name: "OSX - Release - clang"
       env: BUILD_TYPE=Release
+      os: osx
+      compiler: clang
+      cache:
+        ccache: true
+        directories:
+          - $HOME/Library/Caches/Homebrew
 
-install:
-  # Install dependencies for FCL
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then 'ci/install_linux.sh' ; fi
-  - if [ "$TRAVIS_OS_NAME" = "osx"   ]; then 'ci/install_osx.sh'   ; fi
+before_install:
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then source travis_custom/custom_before_install_linux.sh ; fi
+  - if [ "$TRAVIS_OS_NAME" = "osx"   ]; then source travis_custom/custom_before_install_osx.sh   ; fi
 
 script:
   # Create build directory
@@ -35,7 +83,7 @@ script:
   - cd build
 
   # Configure
-  - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS=-w ..
+  - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS=-w -DCMAKE_CXX_FLAGS_DEBUG=${CXX_FLAGS_DEBUG} -DBUILD_PYTHON_INTERFACE=${BUILD_PYTHON_INTERFACE} ..
 
   # Build
   - make
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d2d53d9cb4c80233995131989a1bef1a2cd28046..2b787c5a8ebf7f9ebc20075e75531bdfb3bb6cce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,16 +34,17 @@
 
 cmake_minimum_required(VERSION 2.8)
 set(CXX_DISABLE_WERROR TRUE)
-include(cmake/base.cmake)
-include(cmake/eigen.cmake)
-include(cmake/boost.cmake)
-include(cmake/hpp.cmake)
 
 set(PROJECT_NAME hpp-fcl)
 set(PROJECT_DESCRIPTION
   "HPP fork of FCL -- The Flexible Collision Library"
   )
 
+include(cmake/eigen.cmake)
+include(cmake/boost.cmake)
+include(cmake/python.cmake)
+include(cmake/hpp.cmake)
+
 IF(APPLE)
   SET(CMAKE_MACOSX_RPATH TRUE)
   SET(CMAKE_SKIP_BUILD_RPATH  FALSE)
@@ -57,7 +58,11 @@ IF(APPLE)
   endif("${isSystemDir}" STREQUAL "-1")
 ENDIF(APPLE)
 
-setup_hpp_project()
+OPTION(BUILD_PYTHON_INTERFACE "Build the python bindings" OFF)
+
+# Tell CMake that we compute the PROJECT_VERSION manually.
+CMAKE_POLICY(SET CMP0048 OLD)
+project(${PROJECT_NAME} CXX)
 
 add_required_dependency("eigen3 >= 3.0.0")
 include_directories(SYSTEM ${EIGEN3_INCLUDE_DIRS})
@@ -66,10 +71,13 @@ include_directories(SYSTEM ${EIGEN3_INCLUDE_DIRS})
 set (RUN_TESTS TRUE CACHE BOOL "compile and run unit tests")
 
 # Required dependencies
+set(BOOST_COMPONENTS thread date_time system)
 if (RUN_TESTS)
-  set(BOOST_COMPONENTS thread date_time filesystem system unit_test_framework)
-else ()
-  set(BOOST_COMPONENTS thread date_time system)
+  set(BOOST_COMPONENTS ${BOOST_COMPONENTS} filesystem unit_test_framework)
+endif ()
+if (BUILD_PYTHON_INTERFACE)
+  FINDPYTHON()
+  set(BOOST_COMPONENTS ${BOOST_COMPONENTS} python)
 endif ()
 
 search_for_boost()
@@ -97,10 +105,8 @@ ADD_REQUIRED_DEPENDENCY("assimp >= 2.0")
 if(ASSIMP_FOUND)
   if (NOT ${ASSIMP_VERSION} VERSION_LESS "2.0.1150")
     add_definitions(-DHPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES)
-    SET(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES TRUE)
     message(STATUS "Assimp version has unified headers")
   else()
-    SET(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES FALSE)
     message(STATUS "Assimp version does not have unified headers")
   endif()
 endif()
@@ -118,57 +124,53 @@ SET(${PROJECT_NAME}_HEADERS
   include/hpp/fcl/BV/kDOP.h
   include/hpp/fcl/narrowphase/narrowphase.h
   include/hpp/fcl/narrowphase/gjk.h
-  include/hpp/fcl/shape/geometric_shapes_utility.h
   include/hpp/fcl/shape/geometric_shape_to_BVH_model.h
   include/hpp/fcl/shape/geometric_shapes.h
   include/hpp/fcl/distance_func_matrix.h
   include/hpp/fcl/collision.h
-  include/hpp/fcl/collision_node.h
   include/hpp/fcl/collision_func_matrix.h
   include/hpp/fcl/distance.h
   include/hpp/fcl/math/matrix_3f.h
   include/hpp/fcl/math/vec_3f.h
-  include/hpp/fcl/math/tools.h
+  include/hpp/fcl/math/types.h
   include/hpp/fcl/math/transform.h
-  include/hpp/fcl/traversal/details/traversal.h
-  include/hpp/fcl/traversal/traversal_node_shapes.h
-  include/hpp/fcl/traversal/traversal_node_setup.h
-  include/hpp/fcl/traversal/traversal_recurse.h
-  include/hpp/fcl/traversal/traversal_node_octree.h
-  include/hpp/fcl/traversal/traversal_node_bvhs.h
-  include/hpp/fcl/traversal/traversal_node_bvh_shape.h
-  include/hpp/fcl/traversal/traversal_node_base.h
   include/hpp/fcl/data_types.h
-  include/hpp/fcl/BVH/BV_splitter.h
   include/hpp/fcl/BVH/BVH_internal.h
   include/hpp/fcl/BVH/BVH_model.h
-  include/hpp/fcl/BVH/BV_fitter.h
   include/hpp/fcl/BVH/BVH_front.h
   include/hpp/fcl/BVH/BVH_utility.h
-  include/hpp/fcl/intersect.h
   include/hpp/fcl/collision_object.h
   include/hpp/fcl/collision_utility.h
   include/hpp/fcl/octree.h
   include/hpp/fcl/fwd.hh
   include/hpp/fcl/mesh_loader/assimp.h
   include/hpp/fcl/mesh_loader/loader.h
+  include/hpp/fcl/internal/BV_fitter.h
+  include/hpp/fcl/internal/BV_splitter.h
+  include/hpp/fcl/internal/intersect.h
+  include/hpp/fcl/internal/tools.h
+  include/hpp/fcl/internal/traversal_node_base.h
+  include/hpp/fcl/internal/traversal_node_bvh_shape.h
+  include/hpp/fcl/internal/traversal_node_bvhs.h
+  include/hpp/fcl/internal/traversal_node_octree.h
+  include/hpp/fcl/internal/traversal_node_setup.h
+  include/hpp/fcl/internal/traversal_node_shapes.h
+  include/hpp/fcl/internal/traversal_recurse.h
+  include/hpp/fcl/internal/traversal.h
   )
 
 add_subdirectory(src)
+if (BUILD_PYTHON_INTERFACE)
+  add_subdirectory(python)
+endif ()
 if (RUN_TESTS)
   add_subdirectory(test)
 endif ()
 
 pkg_config_append_libs("hpp-fcl")
 PKG_CONFIG_APPEND_BOOST_LIBS(thread date_time filesystem system)
-IF(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES)
-  # FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES kept for backard compatibility reasons.
-  PKG_CONFIG_APPEND_CFLAGS("-DFCL_USE_ASSIMP_UNIFIED_HEADER_NAMES -DHPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES")
-ENDIF(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES)
 IF(HPP_FCL_HAVE_OCTOMAP)
   # FCL_HAVE_OCTOMAP kept for backward compatibility reasons.
   PKG_CONFIG_APPEND_CFLAGS(
     "-DHPP_FCL_HAVE_OCTOMAP -DFCL_HAVE_OCTOMAP -DOCTOMAP_MAJOR_VERSION=${OCTOMAP_MAJOR_VERSION} -DOCTOMAP_MINOR_VERSION=${OCTOMAP_MINOR_VERSION} -DOCTOMAP_PATCH_VERSION=${OCTOMAP_PATCH_VERSION}")
 ENDIF(HPP_FCL_HAVE_OCTOMAP)
-
-setup_hpp_project_finalize()
diff --git a/README.md b/README.md
index 26b99ec6bf79fb50c1234d21450c744f6a0b06a3..6641511a9ea4e6e0dcff1f764f8b7e9cfbc68029 100644
--- a/README.md
+++ b/README.md
@@ -4,4 +4,8 @@
 [![Pipeline status](https://gepgitlab.laas.fr/humanoid-path-planner/hpp-fcl/badges/master/pipeline.svg)](https://gepgitlab.laas.fr/humanoid-path-planner/hpp-fcl/commits/master)
 [![Coverage report](https://gepgitlab.laas.fr/humanoid-path-planner/hpp-fcl/badges/master/coverage.svg?job=doc-coverage)](http://projects.laas.fr/gepetto/doc/humanoid-path-planner/hpp-fcl/master/coverage/)
 
-This project is a fork from https://github.com/flexible-collision-library/fcl. The main difference is the computation of a lower bound of the distance between two objects when collision checking is performed and no collision is found.
+This project is a fork from https://github.com/flexible-collision-library/fcl.
+
+The main differences are.
+- the use of a safety margin when detecting collision,
+- the computation of a lower bound of the distance between two objects when collision checking is performed and no collision is found.
diff --git a/ci/install_linux.sh b/ci/install_linux.sh
deleted file mode 100755
index db894789de15500662bb69b03a187bdc8c287af8..0000000000000000000000000000000000000000
--- a/ci/install_linux.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-sudo apt-get -qq update
-
-########################
-# Mendatory dependencies
-########################
-sudo apt-get -qq --yes --force-yes install cmake
-sudo apt-get -qq --yes --force-yes install libboost-all-dev
-sudo apt-get -qq --yes --force-yes install libassimp-dev
-sudo apt-get -qq --yes --force-yes install libeigen3-dev
-
-# Octomap
-git clone https://github.com/OctoMap/octomap
-cd octomap
-git checkout tags/v1.8.0
-mkdir build
-cd build
-cmake ..
-make
-sudo make install
-
diff --git a/ci/install_osx.sh b/ci/install_osx.sh
deleted file mode 100755
index 9f90326aad01b93f0d96bb99646271cd22e9affe..0000000000000000000000000000000000000000
--- a/ci/install_osx.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-brew tap homebrew/science
-
-brew install git
-brew install cmake
-brew install boost
-brew install libccd
-brew install assimp
-brew install eigen
-brew install octomap
diff --git a/cmake b/cmake
index 441552634e4c427956be7b2834a6bbf894b24f0c..46dc4a57521bde14ea75c959b6b4f887af50c65d 160000
--- a/cmake
+++ b/cmake
@@ -1 +1 @@
-Subproject commit 441552634e4c427956be7b2834a6bbf894b24f0c
+Subproject commit 46dc4a57521bde14ea75c959b6b4f887af50c65d
diff --git a/doc/gjk.py b/doc/gjk.py
new file mode 100644
index 0000000000000000000000000000000000000000..06d25c93e542616768cdb5486df11e7f11f3d50b
--- /dev/null
+++ b/doc/gjk.py
@@ -0,0 +1,355 @@
+#!/usr/bin/env python3
+import pdb
+import sys
+
+# ABC = AB^AC
+# (ABC^AJ).a = (j.c - j.b) a.a + (j.a - j.c) b.a + (j.b - j.a) c.a, for j = b or c
+
+segment_fmt = "{j}a_aa"
+plane_fmt = ""
+edge_fmt = "{j}a * {b}a_{c}a + {j}{b} * {c}a_aa - {j}{c} * {b}a_aa"
+
+# These checks must be negative and not positive, as in the cheat sheet.
+# They are the same as in the cheat sheet, except that we consider (...).dot(A) instead of (...).dot(-A)
+plane_tests = [ "C.dot (a_cross_b)", "D.dot(a_cross_c)", "-D.dot(a_cross_b)" ]
+checks =  plane_tests \
+        + [ edge_fmt.format (**{'j':j,'b':"b",'c':"c"}) for j in [ "b", "c" ] ] \
+        + [ edge_fmt.format (**{'j':j,'b':"c",'c':"d"}) for j in [ "c", "d" ] ] \
+        + [ edge_fmt.format (**{'j':j,'b':"d",'c':"b"}) for j in [ "d", "b" ] ] \
+        + [ segment_fmt.format(**{'j':j}) for j in [ "b", "c", "d" ] ]
+checks_hr = [ "ABC.AO >= 0", "ACD.AO >= 0", "ADB.AO >= 0" ] \
+        + [ "(ABC ^ {}).AO >= 0".format(n) for n in [ "AB", "AC" ] ] \
+        + [ "(ACD ^ {}).AO >= 0".format(n) for n in [ "AC", "AD" ] ] \
+        + [ "(ADB ^ {}).AO >= 0".format(n) for n in [ "AD", "AB" ] ] \
+        + [ "AB.AO >= 0", "AC.AO >= 0", "AD.AO >= 0" ]
+
+# weights of the checks.
+weights = [ 2, ] * 3 + [ 3, ] * 6 + [ 1, ] * 3
+
+# Segment tests first, because they have lower weight.
+#tests = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ]
+tests = [9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, ]
+assert len(tests) == len(checks)
+assert sorted(tests) == list(range(len(tests)))
+
+regions = [ "ABC", "ACD", "ADB", "AB", "AC", "AD", "A", "Inside", ]
+cases = list(range(len(regions)))
+
+# The following 3 lists refer to table doc/GJK_tetrahedra_boolean_table.ods
+
+# A check ID is (+/- (index+1)) where a minus sign encodes a NOT operation
+# and index refers to an index in list checks.
+
+# definitions is a list of list of check IDs to be ANDed.
+# For instance, a0.a3.!a4 -> [ 1, 4, -5]
+definitions = [
+        [  1,  4,- 5 ],
+        [  2,  6,- 7 ],
+        [  3,  8,- 9 ],
+        [- 4,  9, 10 ],
+        [- 6,  5, 11 ],
+        [- 8,  7, 12 ],
+        [-10,-11,-12 ],
+        [- 1,- 2,- 3 ],
+        ]
+# conditions is a list of (list of (list of check IDs to be ANDed) to be ORed).
+conditions = [
+        [],
+        [],
+        [],
+        [],
+        [],
+        [],
+        [],
+        [ ], #[ [10, 11, 12], ], # I don't think this is always true...
+        ]
+# rejections is a list of (list of (list of check IDs to be ANDed) to be ORed).
+rejections = [
+        [ [  2,  6,  7], [  3,-  8,-  9], ],
+        [ [  3,  8,  9], [  1,-  4,-  5], ],
+        [ [  1,  4,  5], [  2,-  6,-  7], ],
+        [ [- 1,- 3], ],
+        [ [- 2,- 1], ],
+        [ [- 3,- 2], ],
+        [ [  4,- 5], [  6,- 7], [  8,- 9], ],
+        [],
+        ]
+
+implications = [
+        [ [  4,  5, 10, ], [ 11],],
+        [ [  6,  7, 11, ], [ 12],],
+        [ [  8,  9, 12, ], [ 10],],
+
+        [ [- 4,- 5, 11, ], [ 10],],
+        [ [- 6,- 7, 12, ], [ 11],],
+        [ [- 8,- 9, 10, ], [ 12],],
+
+        [ [  1,  4,  5,  6], [- 7] ],
+        [ [  2,  6,  9,  8], [- 9] ],
+        [ [  3,  8,  9,  4], [- 5] ],
+
+        [ [- 4,  5,  10,], [- 11] ],
+        [ [  4,- 5,- 10,], [  11] ],
+        [ [- 6,  7,  11,], [- 12] ],
+        [ [  6,- 7,- 11,], [  12] ],
+        [ [- 8,  9,  12,], [- 10] ],
+        [ [  8,- 9,- 12,], [  10] ],
+
+        [ [ 10, 3, 9, -12, 4, -5], [1] ],
+        [ [ 10, -3, 1, -4], [9] ],
+        [ [ 10, -3, -1, 2, -6, 11], [5] ],
+        [ [ -10, 11, 2, -12, -5, -1], [6] ],
+        [ [ -10,11,-2,1,5], [-6] ],
+        [ [-10,-11,12,1,-7,-2,4],[-5]],
+        [ [-10,-11,12,-3,2,7],[-8]],
+        [ [-10,-11,12,-3,-2],[-1]],
+        ]
+
+def set_test_values (current_tests, test_values, itest, value):
+    def satisfies (values, indices):
+        for k in indices:
+            if k > 0 and values[ k-1] != True : return False
+            if k < 0 and values[-k-1] != False: return False
+        return True
+
+    remaining_tests = list(current_tests)
+    next_test_values = list(test_values)
+
+    remaining_tests.remove (itest)
+    next_test_values[itest] = value
+    rerun = True
+    while rerun:
+        rerun = False
+        for impl in implications:
+            if satisfies(next_test_values, impl[0]):
+                for id in impl[1]:
+                    k = (id - 1) if id > 0 else (-id-1)
+                    if k in remaining_tests:
+                        next_test_values[k] = (id > 0)
+                        remaining_tests.remove(k)
+                        rerun = True
+                    else:
+                        if next_test_values[k] != (id > 0):
+                            raise ValueError ("Absurd case")
+    return remaining_tests, next_test_values
+
+def set_tests_values (current_tests, test_values, itests, values):
+    for itest,value in zip(itests,values):
+        current_tests, test_values = set_test_values (current_tests, test_values, itest, value)
+    return current_tests, test_values
+
+def apply_test_values (cases, test_values):
+    def canSatisfy (values, indices):
+        for k in indices:
+            if k > 0 and values[ k-1] == False: return False
+            if k < 0 and values[-k-1] == True : return False
+        return True
+    def satisfies (values, indices):
+        for k in indices:
+            if k > 0 and values[ k-1] != True : return False
+            if k < 0 and values[-k-1] != False: return False
+        return True
+
+    # Check all cases.
+    left_cases = []
+    for case in cases:
+        defi = definitions[case]
+        conds = conditions[case]
+        rejs = rejections[case]
+        if satisfies (test_values, defi):
+            # A definition is True, stop recursion
+            return [ case ]
+        if not canSatisfy (test_values, defi):
+            continue
+        for cond in conds:
+            if satisfies (test_values, cond):
+                # A condition is True, stop recursion
+                return [ case ]
+        append = True
+        for rej in rejs:
+            if satisfies (test_values, rej):
+                # A rejection is True, discard this case
+                append = False
+                break
+        if append: left_cases.append (case)
+    return left_cases
+
+def max_number_of_tests (current_tests, cases, test_values = [None,]*len(tests), prevBestScore = float('inf'), prevScore = 0):
+    for test in current_tests:
+        assert test_values[test] == None, "Test " +str(test)+ " already performed"
+
+    left_cases = apply_test_values (cases, test_values)
+
+    if len(left_cases) == 1:
+        return prevScore, { 'case': left_cases[0], }
+    elif len(left_cases) == 0:
+        return prevScore, { 'case': None, 'comments': [ "applied " + str(test_values), "to " + ", ".join([regions[c] for c in cases ]) ] }
+
+    assert len(current_tests) > 0, "No more test but " + str(left_cases) + " remains"
+
+    currentBestScore = prevBestScore
+    bestScore = float('inf')
+    bestOrder = [None, None]
+    for i, test in enumerate(current_tests):
+        assert bestScore >= currentBestScore
+
+        currentScore = prevScore + len(left_cases) * weights[test]
+        #currentScore = prevScore + weights[test]
+        if currentScore > currentBestScore: # Cannot do better -> stop
+            continue
+
+        try:
+            remaining_tests, next_test_values = set_test_values (current_tests, test_values, test, True)
+        except ValueError:
+            remaining_tests = None
+
+        if remaining_tests is not None:
+            # Do not put this in try catch as I do not want other ValueError to be understood as an infeasible branch.
+            score_if_t, order_if_t = max_number_of_tests (remaining_tests, left_cases, next_test_values, currentBestScore, currentScore)
+            if score_if_t >= currentBestScore: # True didn't do better -> stop
+                continue
+        else:
+            score_if_t, order_if_t = prevScore, None
+
+        try:
+            remaining_tests, next_test_values = set_test_values (current_tests, test_values, test, False)
+        except ValueError:
+            remaining_tests = None
+
+        if remaining_tests is not None:
+            # Do not put this in try catch as I do not want other ValueError to be understood as an infeasible branch.
+            score_if_f, order_if_f = max_number_of_tests (remaining_tests, left_cases, next_test_values, currentBestScore, currentScore)
+        else:
+            score_if_f, order_if_f = prevScore, None
+
+        currentScore = max(score_if_t, score_if_f)
+        if currentScore < bestScore:
+            if currentScore < currentBestScore:
+                bestScore = currentScore
+                bestOrder = { 'test': test, 'true': order_if_t, 'false': order_if_f }
+                #pdb.set_trace()
+                currentBestScore = currentScore
+                if len(tests) == len(current_tests):
+                    print ("New best score: {}".format(currentBestScore))
+
+    return bestScore, bestOrder
+
+def printComments (order, indent, file):
+    if 'comments' in order:
+        for comment in order['comments']:
+            print (indent + "// " + comment, file=file)
+
+def printOrder (order, indent = "", start=True,file=sys.stdout,curTests=[]):
+    if start:
+        print ("bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)", file=file)
+        print ("{", file=file)
+        print (indent+"// The code of this function was generated using doc/gjk.py", file=file)
+        print (indent+"const vertex_id_t a = 3, b = 2, c = 1, d = 0;", file=file)
+        for l in "abcd":
+            print (indent+"const Vec3f& {} (current.vertex[{}]->w);".format(l.upper(),l), file=file)
+        print (indent+"const FCL_REAL aa = A.squaredNorm();".format(l), file=file)
+        for l in "dcb":
+            for m in "abcd":
+                if m <= l:
+                    print (indent+"const FCL_REAL {0}{1}    = {2}.dot({3});".format(l,m,l.upper(),m.upper()), file=file)
+                else:
+                    print (indent+"const FCL_REAL& {0}{1}    = {1}{0};".format(l,m), file=file)
+            print (indent+"const FCL_REAL {0}a_aa = {0}a - aa;".format(l), file=file)
+        for l0,l1 in zip("bcd","cdb"):
+            print (indent+"const FCL_REAL {0}a_{1}a = {0}a - {1}a;".format(l0,l1), file=file)
+        for l in "bc":
+            print (indent+"const Vec3f a_cross_{0} = A.cross({1});".format(l,l.upper()), file=file)
+        print("", file=file)
+        print(       "#define REGION_INSIDE()               "+indent+"\\", file=file)
+        print(indent+"  ray.setZero();                      \\", file=file)
+        print(indent+"  next.vertex[0] = current.vertex[d]; \\", file=file)
+        print(indent+"  next.vertex[1] = current.vertex[c]; \\", file=file)
+        print(indent+"  next.vertex[2] = current.vertex[b]; \\", file=file)
+        print(indent+"  next.vertex[3] = current.vertex[a]; \\", file=file)
+        print(indent+"  next.rank=4;                        \\", file=file)
+        print(indent+"  return true;", file=file)
+        print("", file=file)
+
+    if 'case' in order:
+        case = order['case']
+        if case is None:
+            print (indent + "// There are no case corresponding to this set of tests.", file=file)
+            printComments (order, indent, file)
+            print (indent + "assert(false);", file=file)
+            return
+        region = regions[case]
+        print (indent + "// Region " + region, file=file)
+        printComments (order, indent, file)
+        toFree = ['b', 'c', 'd']
+        if region == "Inside":
+            print (indent + "REGION_INSIDE()", file=file)
+            toFree = []
+        elif region == 'A':
+            print (indent + "originToPoint (current, a, A, next, ray);", file=file)
+        elif len(region)==2:
+            a = region[0]
+            B = region[1]
+            print (indent + "originToSegment (current, a, {b}, A, {B}, {B}-A, -{b}a_aa, next, ray);".format(
+                **{ 'b':B.lower(), 'B':B,} ), file=file)
+            toFree.remove(B.lower())
+        elif len(region)==3:
+            B = region[1]
+            C = region[2]
+            test = plane_tests[['ABC','ACD','ADB'].index(region)]
+            if test.startswith('-'): test = test[1:]
+            else:                    test = '-'+test
+            print (indent + "originToTriangle (current, a, {b}, {c}, ({B}-A).cross({C}-A), {t}, next, ray);".format(
+                **{'b':B.lower(), 'c':C.lower(), 'B':B, 'C':C, 't':test}), file=file)
+            toFree.remove(B.lower())
+            toFree.remove(C.lower())
+        else:
+            assert False, "Unknown region " + region
+        for pt in toFree:
+            print (indent + "free_v[nfree++] = current.vertex[{}];".format(pt), file=file)
+    else:
+        assert "test" in order and 'true' in order and 'false' in order
+        check    = checks[order['test']]
+        check_hr = checks_hr[order['test']]
+        printComments (order, indent, file)
+        nextTests_t=curTests+["a"+str(order['test']+1),]
+        nextTests_f=curTests+["!a"+str(order['test']+1),]
+        if order['true'] is None:
+            if order['false'] is None:
+                print (indent + """assert(false && "Case {} should never happen.");""".format(check_hr))
+            else:
+                print (indent + "assert(!({} <= 0)); // Not {} / {}".format(check, check_hr, ".".join(nextTests_f)), file=file)
+                printOrder (order['false'], indent=indent, start=False, file=file, curTests=nextTests_f)
+        elif order['false'] is None:
+            print (indent + "assert({} <= 0); // {} / {}".format(check, check_hr, ".".join(nextTests_t)), file=file)
+            printOrder (order['true'], indent=indent, start=False, file=file, curTests=nextTests_t)
+        else:
+            print (indent + "if ({} <= 0) {{ // if {} / {}".format(check, check_hr, ".".join(nextTests_t)), file=file)
+            printOrder (order['true'], indent=indent+"  ", start=False, file=file, curTests=nextTests_t)
+            print (indent + "}} else {{ // not {} / {}".format(check_hr, ".".join(nextTests_f)), file=file)
+            printOrder (order['false'], indent=indent+"  ", start=False, file=file, curTests=nextTests_f)
+            print (indent + "}} // end of {}".format(check_hr), file=file)
+
+    if start:
+        print ("",file=file)
+        print ("#undef REGION_INSIDE", file=file)
+        print (indent+"return false;", file=file)
+        print ("}", file=file)
+
+def unit_tests ():
+    # a4, a5, a10, a11, a12
+    cases = list(range(len(regions)))
+    pdb.set_trace()
+    left_cases = apply_test_values (cases,
+            test_values=[None,None,None,True,True,None,None,None,None,True,True,True])
+    assert len(left_cases) > 1
+
+#unit_tests()
+
+score, order = max_number_of_tests (tests, cases)
+
+print(score)
+printOrder(order, indent="  ")
+
+# TODO add weights such that:
+# - it is preferred to have all the use of one check in one branch.
+#   idea: ponderate by the number of remaining tests.
diff --git a/include/hpp/fcl/BV/AABB.h b/include/hpp/fcl/BV/AABB.h
index 0b93c48a0ab6829d21abf18557526aa2f1d442b5..55a5e4adb92a73b9d2b8416c487b1075a8bac831 100644
--- a/include/hpp/fcl/BV/AABB.h
+++ b/include/hpp/fcl/BV/AABB.h
@@ -39,14 +39,17 @@
 #define HPP_FCL_AABB_H
 
 #include <stdexcept>
-#include <hpp/fcl/math/vec_3f.h>
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 
 namespace hpp
 {
 namespace fcl
 {
   class CollisionRequest;
+/// @defgroup Bounding_Volume 
+/// regroup class of differents types of bounding volume.
+/// @{
+
 /// @brief A class describing the AABB collision structure, which is a box in 3D space determined by two diagonal points
 class AABB
 {
@@ -82,6 +85,20 @@ public:
   {
   }
 
+  /// @name Bounding volume API
+  /// Common API to BVs.
+  /// @{
+  
+  /// @brief Check whether the AABB contains a point
+  inline bool contain(const Vec3f& p) const
+  {
+    if(p[0] < min_[0] || p[0] > max_[0]) return false;
+    if(p[1] < min_[1] || p[1] > max_[1]) return false;
+    if(p[2] < min_[2] || p[2] > max_[2]) return false;
+
+    return true;
+  }
+  
   /// @brief Check whether two AABB are overlap
   inline bool overlap(const AABB& other) const
   {
@@ -97,53 +114,14 @@ public:
   }    
 
   /// Not implemented
-  inline bool overlap(const AABB& other, const CollisionRequest&,
-                      FCL_REAL& sqrDistLowerBound) const
-  {
-    sqrDistLowerBound = sqrt (-1);
-    return overlap (other);
-  }
+  bool overlap(const AABB& other, const CollisionRequest& request,
+               FCL_REAL& sqrDistLowerBound) const;
 
-  /// @brief Check whether the AABB contains another AABB
-  inline bool contain(const AABB& other) const
-  {
-    return (other.min_[0] >= min_[0]) && (other.max_[0] <= max_[0]) && (other.min_[1] >= min_[1]) && (other.max_[1] <= max_[1]) && (other.min_[2] >= min_[2]) && (other.max_[2] <= max_[2]);
-  }
-
-
-  /// @brief Check whether two AABB are overlapped along specific axis
-  inline bool axisOverlap(const AABB& other, int axis_id) const
-  {
-    if(min_[axis_id] > other.max_[axis_id]) return false;
-
-    if(max_[axis_id] < other.min_[axis_id]) return false;
-
-    return true;
-  }
-
-  /// @brief Check whether two AABB are overlap and return the overlap part
-  inline bool overlap(const AABB& other, AABB& overlap_part) const
-  {
-    if(!overlap(other))
-    {
-      return false;
-    }
-    
-    overlap_part.min_ = min_.cwiseMax(other.min_);
-    overlap_part.max_ = max_.cwiseMin(other.max_);
-    return true;
-  }
-
-
-  /// @brief Check whether the AABB contains a point
-  inline bool contain(const Vec3f& p) const
-  {
-    if(p[0] < min_[0] || p[0] > max_[0]) return false;
-    if(p[1] < min_[1] || p[1] > max_[1]) return false;
-    if(p[2] < min_[2] || p[2] > max_[2]) return false;
+  /// @brief Distance between two AABBs
+  FCL_REAL distance(const AABB& other) const;
 
-    return true;
-  }
+  /// @brief Distance between two AABBs; P and Q, should not be NULL, return the nearest points 
+  FCL_REAL distance(const AABB& other, Vec3f* P, Vec3f* Q) const;
 
   /// @brief Merge the AABB and a point
   inline AABB& operator += (const Vec3f& p)
@@ -168,6 +146,18 @@ public:
     return res += other;
   }
 
+  /// @brief Size of the AABB (used in BV_Splitter to order two AABBs)
+  inline FCL_REAL size() const
+  {
+    return (max_ - min_).squaredNorm();
+  }
+
+  /// @brief Center of the AABB
+  inline  Vec3f center() const
+  {
+    return (min_ + max_) * 0.5;
+  }
+
   /// @brief Width of the AABB
   inline FCL_REAL width() const
   {
@@ -186,40 +176,31 @@ public:
     return max_[2] - min_[2];
   }
 
-  /// @brief Volume of the AABB
+    /// @brief Volume of the AABB
   inline FCL_REAL volume() const
   {
     return width() * height() * depth();
-  }  
-
-  /// @brief Size of the AABB (used in BV_Splitter to order two AABBs)
-  inline FCL_REAL size() const
-  {
-    return (max_ - min_).squaredNorm();
   }
 
-  /// @brief Radius of the AABB
-  inline FCL_REAL radius() const
-  {
-    return (max_ - min_).norm() / 2;
-  }
+  /// @}
 
-  /// @brief Center of the AABB
-  inline  Vec3f center() const
+  /// @brief Check whether the AABB contains another AABB
+  inline bool contain(const AABB& other) const
   {
-    return (min_ + max_) * 0.5;
+    return (other.min_[0] >= min_[0]) && (other.max_[0] <= max_[0]) && (other.min_[1] >= min_[1]) && (other.max_[1] <= max_[1]) && (other.min_[2] >= min_[2]) && (other.max_[2] <= max_[2]);
   }
 
-  /// @brief Distance between two AABBs; P and Q, should not be NULL, return the nearest points 
-  FCL_REAL distance(const AABB& other, Vec3f* P, Vec3f* Q) const;
-
-  /// @brief Distance between two AABBs
-  FCL_REAL distance(const AABB& other) const;
-
-  /// @brief whether two AABB are equal
-  inline bool equal(const AABB& other) const
+  /// @brief Check whether two AABB are overlap and return the overlap part
+  inline bool overlap(const AABB& other, AABB& overlap_part) const
   {
-    return isEqual(min_, other.min_) && isEqual(max_, other.max_);
+    if(!overlap(other))
+    {
+      return false;
+    }
+    
+    overlap_part.min_ = min_.cwiseMax(other.min_);
+    overlap_part.max_ = max_.cwiseMin(other.max_);
+    return true;
   }
 
   /// @brief expand the half size of the AABB by delta, and keep the center unchanged.
@@ -269,7 +250,6 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const AABB& b1, const AABB& b2
 bool overlap(const Matrix3f& R0, const Vec3f& T0, const AABB& b1,
 	     const AABB& b2, const CollisionRequest& request,
              FCL_REAL& sqrDistLowerBound);
-
 }
 
 } // namespace hpp
diff --git a/include/hpp/fcl/BV/BV.h b/include/hpp/fcl/BV/BV.h
index d88aa1fc7396825555968e0c3c854045a2d14bd0..238ec16bfc416c9235741900d1f28c9577b931d2 100644
--- a/include/hpp/fcl/BV/BV.h
+++ b/include/hpp/fcl/BV/BV.h
@@ -47,7 +47,7 @@
 #include <hpp/fcl/BV/kIOS.h>
 #include <hpp/fcl/math/transform.h>
 
-/** \brief Main namespace */
+/** @brief Main namespace */
 namespace hpp
 {
 namespace fcl
@@ -90,43 +90,7 @@ class Converter<AABB, OBB>
 {
 public:
   static void convert(const AABB& bv1, const Transform3f& tf1, OBB& bv2)
-  {    
-    /*
-    bv2.To = tf1.transform(bv1.center());
-
-    /// Sort the AABB edges so that AABB extents are ordered.
-    FCL_REAL d[3] = {bv1.width(), bv1.height(), bv1.depth() };
-    std::size_t id[3] = {0, 1, 2};
-
-    for(std::size_t i = 1; i < 3; ++i)
-    {
-      for(std::size_t j = i; j > 0; --j)
-      {
-        if(d[j] > d[j-1])
-        {
-          {
-            FCL_REAL tmp = d[j];
-            d[j] = d[j-1];
-            d[j-1] = tmp;
-          }
-          {
-            std::size_t tmp = id[j];
-            id[j] = id[j-1];
-            id[j-1] = tmp;
-          }
-        }
-      }
-    }
-
-    Vec3f extent = (bv1.max_ - bv1.min_) * 0.5;
-    bv2.extent = Vec3f(extent[id[0]], extent[id[1]], extent[id[2]]);
-    const Matrix3f& R = tf1.getRotation();
-    bool left_hand = (id[0] == (id[1] + 1) % 3);
-    bv2.axis[0] = left_hand ? -R.col(id[0]) : R.col(id[0]);
-    bv2.axis[1] = R.col(id[1]);
-    bv2.axis[2] = R.col(id[2]);
-    */
-
+  {   
     bv2.To.noalias() = tf1.transform(bv1.center());
     bv2.extent.noalias() = (bv1.max_ - bv1.min_) * 0.5;
     bv2.axes.noalias() = tf1.getRotation();
@@ -161,7 +125,7 @@ class Converter<RSS, OBB>
 public:
   static void convert(const RSS& bv1, const Transform3f& tf1, OBB& bv2)
   {
-    bv2.extent.noalias() = Vec3f(bv1.l[0] * 0.5 + bv1.r, bv1.l[1] * 0.5 + bv1.r, bv1.r);
+    bv2.extent.noalias() = Vec3f(bv1.length[0] * 0.5 + bv1.radius, bv1.length[1] * 0.5 + bv1.radius, bv1.radius);
     bv2.To.noalias() = tf1.transform(bv1.Tr);
     bv2.axes.noalias() = tf1.getRotation() * bv1.axes;
   }
@@ -204,9 +168,9 @@ public:
     bv2.Tr = tf1.transform(bv1.To);
     bv2.axes.noalias() = tf1.getRotation() * bv1.axes;
  
-    bv2.r = bv1.extent[2];
-    bv2.l[0] = 2 * (bv1.extent[0] - bv2.r);
-    bv2.l[1] = 2 * (bv1.extent[1] - bv2.r);
+    bv2.radius = bv1.extent[2];
+    bv2.length[0] = 2 * (bv1.extent[0] - bv2.radius);
+    bv2.length[1] = 2 * (bv1.extent[1] - bv2.radius);
   }
 };
 
@@ -219,9 +183,9 @@ public:
     bv2.Tr.noalias() = tf1.transform(bv1.Tr);
     bv2.axes.noalias() = tf1.getRotation() * bv1.axes;
 
-    bv2.r = bv1.r;
-    bv2.l[0] = bv1.l[0];
-    bv2.l[1] = bv1.l[1];
+    bv2.radius = bv1.radius;
+    bv2.length[0] = bv1.length[0];
+    bv2.length[1] = bv1.length[1];
   }
 };
 
@@ -268,9 +232,9 @@ public:
     }
 
     Vec3f extent = (bv1.max_ - bv1.min_) * 0.5;
-    bv2.r = extent[id[2]];
-    bv2.l[0] = (extent[id[0]] - bv2.r) * 2;
-    bv2.l[1] = (extent[id[1]] - bv2.r) * 2;
+    bv2.radius = extent[id[2]];
+    bv2.length[0] = (extent[id[0]] - bv2.radius) * 2;
+    bv2.length[1] = (extent[id[1]] - bv2.radius) * 2;
 
     const Matrix3f& R = tf1.getRotation();
     bool left_hand = (id[0] == (id[1] + 1) % 3);
diff --git a/include/hpp/fcl/BV/BV_node.h b/include/hpp/fcl/BV/BV_node.h
index 5889b740367f4b97b7424e71af45642c92c3c458..86e858f2f40b5da2857b229ceb9e8b6d13f32985 100644
--- a/include/hpp/fcl/BV/BV_node.h
+++ b/include/hpp/fcl/BV/BV_node.h
@@ -39,8 +39,7 @@
 #ifndef HPP_FCL_BV_NODE_H
 #define HPP_FCL_BV_NODE_H
 
-#include <hpp/fcl/math/vec_3f.h>
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 
 #include <hpp/fcl/BV/BV.h>
 #include <iostream>
@@ -50,6 +49,10 @@ namespace hpp
 namespace fcl
 {
 
+/// @defgroup Construction_Of_BVH 
+/// regroup class which are used to build BVH (Bounding Volume Hierarchy)
+/// @{
+
 /// @brief BVNodeBase encodes the tree structure for BVH
 struct BVNodeBase
 {
diff --git a/include/hpp/fcl/BV/OBB.h b/include/hpp/fcl/BV/OBB.h
index f3897cf37808f0d7ee54ee583ceba5159c070264..32468de639bbef10eea0ac63c1b873e4b5d583ae 100644
--- a/include/hpp/fcl/BV/OBB.h
+++ b/include/hpp/fcl/BV/OBB.h
@@ -38,9 +38,7 @@
 #ifndef HPP_FCL_OBB_H
 #define HPP_FCL_OBB_H
 
-
-#include <hpp/fcl/math/vec_3f.h>
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 
 namespace hpp
 {
@@ -48,6 +46,9 @@ namespace fcl
 {
   class CollisionRequest;
 
+/// @addtogroup Bounding_Volume
+/// @{
+
 /// @brief Oriented bounding box class
 class OBB
 {
@@ -62,26 +63,22 @@ public:
   /// @brief Half dimensions of OBB
   Vec3f extent;
 
+  /// @brief Check whether the OBB contains a point.
+  bool contain(const Vec3f& p) const;
+
   /// Check collision between two OBB
-  /// \return true if collision happens. 
+  /// @return true if collision happens. 
   bool overlap(const OBB& other) const;
 
   /// Check collision between two OBB
-  /// \return true if collision happens. 
-  /// \retval sqrDistLowerBound squared lower bound on distance between boxes if
+  /// @return true if collision happens. 
+  /// @retval sqrDistLowerBound squared lower bound on distance between boxes if
   ///         they do not overlap.
   bool overlap(const OBB& other, const CollisionRequest& request,
                FCL_REAL& sqrDistLowerBound) const;
 
-  
-  /// @brief Check collision between two OBB and return the overlap part. For OBB, the overlap_part return value is NOT used as the overlap part of two obbs usually is not an obb. 
-  bool overlap(const OBB& other, OBB& /*overlap_part*/) const
-  {
-    return overlap(other);
-  }
-
-  /// @brief Check whether the OBB contains a point.
-  bool contain(const Vec3f& p) const;
+  /// @brief Distance between two OBBs, not implemented.
+  FCL_REAL distance(const OBB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
 
   /// @brief A simple way to merge the OBB and a point (the result is not compact).
   OBB& operator += (const Vec3f& p);
@@ -96,6 +93,18 @@ public:
   /// @brief Return the merged OBB of current OBB and the other one (the result is not compact).
   OBB operator + (const OBB& other) const;
 
+  /// @brief Size of the OBB (used in BV_Splitter to order two OBBs)
+  inline FCL_REAL size() const
+  {
+    return extent.squaredNorm();
+  }
+
+  /// @brief Center of the OBB
+  inline const Vec3f& center() const
+  {
+    return To;
+  }
+
   /// @brief Width of the OBB.
   inline FCL_REAL width() const
   {
@@ -119,22 +128,6 @@ public:
   {
     return width() * height() * depth();
   }
-
-  /// @brief Size of the OBB (used in BV_Splitter to order two OBBs)
-  inline FCL_REAL size() const
-  {
-    return extent.squaredNorm();
-  }
-
-  /// @brief Center of the OBB
-  inline const Vec3f& center() const
-  {
-    return To;
-  }
-
-
-  /// @brief Distance between two OBBs, not implemented.
-  FCL_REAL distance(const OBB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
 };
 
 
@@ -151,9 +144,9 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBB& b1,
 
 
 /// Check collision between two boxes
-/// \param B, T orientation and position of first box,
-/// \param a half dimensions of first box,
-/// \param b half dimensions of second box.
+/// @param B, T orientation and position of first box,
+/// @param a half dimensions of first box,
+/// @param b half dimensions of second box.
 /// The second box is in identity configuration.
 bool obbDisjoint(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b);
 }
diff --git a/include/hpp/fcl/BV/OBBRSS.h b/include/hpp/fcl/BV/OBBRSS.h
index bc8d715c95ccc5d552b8f42a04cac105902e1c20..def7ce67ddd35cc54d5bd654acdeb8c138b5622f 100644
--- a/include/hpp/fcl/BV/OBBRSS.h
+++ b/include/hpp/fcl/BV/OBBRSS.h
@@ -48,6 +48,9 @@ namespace fcl
 {
   class CollisionRequest;
 
+/// @addtogroup Bounding_Volume
+/// @{
+
 /// @brief Class merging the OBB and RSS, can handle collision and distance simultaneously
 class OBBRSS
 {
@@ -59,6 +62,12 @@ public:
   /// @brief RSS member, for distance
   RSS rss;
 
+/// @brief Check whether the OBBRSS contains a point
+  inline bool contain(const Vec3f& p) const
+  {
+    return obb.contain(p);
+  }
+
   /// @brief Check collision between two OBBRSS
   bool overlap(const OBBRSS& other) const
   {
@@ -66,7 +75,7 @@ public:
   }
 
   /// Check collision between two OBBRSS
-  /// \retval sqrDistLowerBound squared lower bound on distance between
+  /// @retval sqrDistLowerBound squared lower bound on distance between
   ///         objects if they do not overlap.
   bool overlap(const OBBRSS& other, const CollisionRequest& request,
                FCL_REAL& sqrDistLowerBound) const
@@ -74,16 +83,10 @@ public:
     return obb.overlap(other.obb, request, sqrDistLowerBound);
   }
 
-  /// @brief Check collision between two OBBRSS and return the overlap part.
-  bool overlap(const OBBRSS& other, OBBRSS& /*overlap_part*/) const
-  {
-    return overlap(other);
-  }
-
-  /// @brief Check whether the OBBRSS contains a point
-  inline bool contain(const Vec3f& p) const
+  /// @brief Distance between two OBBRSS; P and Q , is not NULL, returns the nearest points
+  FCL_REAL distance(const OBBRSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const
   {
-    return obb.contain(p);
+    return rss.distance(other.rss, P, Q);
   }
 
   /// @brief Merge the OBBRSS and a point
@@ -110,6 +113,18 @@ public:
     return result;
   }
 
+    /// @brief Size of the OBBRSS (used in BV_Splitter to order two OBBRSS)
+  inline FCL_REAL size() const
+  {
+    return obb.size();
+  }
+
+  /// @brief Center of the OBBRSS
+  inline const Vec3f& center() const
+  {
+    return obb.center();
+  }
+
   /// @brief Width of the OBRSS
   inline FCL_REAL width() const
   {
@@ -133,42 +148,30 @@ public:
   {
     return obb.volume();
   }
-
-  /// @brief Size of the OBBRSS (used in BV_Splitter to order two OBBRSS)
-  inline FCL_REAL size() const
-  {
-    return obb.size();
-  }
-
-  /// @brief Center of the OBBRSS
-  inline const Vec3f& center() const
-  {
-    return obb.center();
-  }
-
-  /// @brief Distance between two OBBRSS; P and Q , is not NULL, returns the nearest points
-  FCL_REAL distance(const OBBRSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const
-  {
-    return rss.distance(other.rss, P, Q);
-  }
 };
 
-/// @brief Translate the OBBRSS bv
-OBBRSS translate(const OBBRSS& bv, const Vec3f& t);
-
 /// @brief Check collision between two OBBRSS, b1 is in configuration (R0, T0) and b2 is in indentity
-bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2);
+inline bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2)
+{
+  return overlap(R0, T0, b1.obb, b2.obb);
+}
 
 /// Check collision between two OBBRSS
-/// \param  b1 first OBBRSS in configuration (R0, T0)
-/// \param  b2 second OBBRSS in identity position
-/// \retval squared lower bound on the distance if OBBRSS do not overlap.
-bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1,
-             const OBBRSS& b2, const CollisionRequest& request,
-	     FCL_REAL& sqrDistLowerBound);
+/// @param  b1 first OBBRSS in configuration (R0, T0)
+/// @param  b2 second OBBRSS in identity position
+/// @retval squared lower bound on the distance if OBBRSS do not overlap.
+inline bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1,
+                    const OBBRSS& b2, const CollisionRequest& request,
+	            FCL_REAL& sqrDistLowerBound)
+{
+  return overlap(R0, T0, b1.obb, b2.obb, request, sqrDistLowerBound);
+}
 
 /// @brief Computate distance between two OBBRSS, b1 is in configuation (R0, T0) and b2 is in indentity; P and Q, is not NULL, returns the nearest points
-FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2, Vec3f* P = NULL, Vec3f* Q = NULL);
+inline FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2, Vec3f* P = NULL, Vec3f* Q = NULL)
+{
+  return distance(R0, T0, b1.rss, b2.rss, P, Q);
+}
 
 }
 
diff --git a/include/hpp/fcl/BV/RSS.h b/include/hpp/fcl/BV/RSS.h
index 6822e97e42abb8ab1186e1e78a0fd3ed74bba667..a380de68c2b033bda110b5bee23d1dfa679058bb 100644
--- a/include/hpp/fcl/BV/RSS.h
+++ b/include/hpp/fcl/BV/RSS.h
@@ -39,8 +39,7 @@
 #define HPP_FCL_RSS_H
 
 #include <stdexcept>
-#include <hpp/fcl/math/vec_3f.h>
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <boost/math/constants/constants.hpp>
 
 namespace hpp
@@ -49,6 +48,9 @@ namespace fcl
 {
 
   class CollisionRequest;
+/// @addtogroup Bounding_Volume
+/// @{
+
 /// @brief A class for rectangle sphere-swept bounding volume
 class RSS
 {
@@ -61,10 +63,14 @@ public:
   Vec3f Tr;
 
   /// @brief Side lengths of rectangle
-  FCL_REAL l[2];
+  FCL_REAL length[2];
 
   /// @brief Radius of sphere summed with rectangle to form RSS
-  FCL_REAL r;
+  FCL_REAL radius;
+
+
+  /// @brief Check whether the RSS contains a point
+  inline bool contain(const Vec3f& p) const;
 
   /// @brief Check collision between two RSS
   bool overlap(const RSS& other) const;
@@ -77,15 +83,8 @@ public:
     return overlap (other);
   }
 
-  /// @brief Check collision between two RSS and return the overlap part.
-  /// For RSS, we return nothing, as the overlap part of two RSSs usually is not a RSS.
-  bool overlap(const RSS& other, RSS& /*overlap_part*/) const
-  {
-    return overlap(other);
-  }
-
-  /// @brief Check whether the RSS contains a point
-  inline bool contain(const Vec3f& p) const;
+  /// @brief the distance between two RSS; P and Q, if not NULL, return the nearest points
+  FCL_REAL distance(const RSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
 
   /// @brief A simple way to merge the RSS and a point, not compact.
   /// @todo This function may have some bug.
@@ -101,51 +100,51 @@ public:
   /// @brief Return the merged RSS of current RSS and the other one
   RSS operator + (const RSS& other) const;
 
+
+  /// @brief Size of the RSS (used in BV_Splitter to order two RSSs)
+  inline FCL_REAL size() const
+  {
+    return (std::sqrt(length[0] * length[0] + length[1] * length[1]) + 2 * radius);
+  }
+
+  /// @brief The RSS center
+  inline const Vec3f& center() const
+  {
+    return Tr;
+  }
+
   /// @brief Width of the RSS
   inline FCL_REAL width() const
   {
-    return l[0] + 2 * r;
+    return length[0] + 2 * radius;
   }
 
   /// @brief Height of the RSS
   inline FCL_REAL height() const
   {
-    return l[1] + 2 * r;
+    return length[1] + 2 * radius;
   }
 
   /// @brief Depth of the RSS
   inline FCL_REAL depth() const
   {
-    return 2 * r;
+    return 2 * radius;
   }
 
   /// @brief Volume of the RSS
   inline FCL_REAL volume() const
   {
-    return (l[0] * l[1] * 2 * r + 4 * boost::math::constants::pi<FCL_REAL>() * r * r * r);
-  }
-
-  /// @brief Size of the RSS (used in BV_Splitter to order two RSSs)
-  inline FCL_REAL size() const
-  {
-    return (std::sqrt(l[0] * l[0] + l[1] * l[1]) + 2 * r);
+    return (length[0] * length[1] * 2 * radius + 4 * boost::math::constants::pi<FCL_REAL>() * radius * radius * radius);
   }
 
-  /// @brief The RSS center
-  inline const Vec3f& center() const
+  /// @brief Check collision between two RSS and return the overlap part.
+  /// For RSS, we return nothing, as the overlap part of two RSSs usually is not a RSS.
+  bool overlap(const RSS& other, RSS& /*overlap_part*/) const
   {
-    return Tr;
+    return overlap(other);
   }
-
-  /// @brief the distance between two RSS; P and Q, if not NULL, return the nearest points
-  FCL_REAL distance(const RSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
-
 };
 
-
-/// @brief Translate the RSS bv
-RSS translate(const RSS& bv, const Vec3f& t);
-
 /// @brief distance between two RSS bounding volumes
 /// P and Q (optional return values) are the closest points in the rectangles, not the RSS. But the direction P - Q is the correct direction for cloest points
 /// Notice that P and Q are both in the local frame of the first RSS (not global frame and not even the local frame of object 1)
@@ -165,4 +164,4 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2,
 
 } // namespace hpp
 
-#endif
+#endif
\ No newline at end of file
diff --git a/include/hpp/fcl/BV/kDOP.h b/include/hpp/fcl/BV/kDOP.h
index da5901624e1f4f8f8e5d380b024daaf36d7c8f26..6a5c6aabe88b7a3a8cb6398ef2365b8d41d0119f 100644
--- a/include/hpp/fcl/BV/kDOP.h
+++ b/include/hpp/fcl/BV/kDOP.h
@@ -39,7 +39,7 @@
 #define HPP_FCL_KDOP_H
 
 #include <stdexcept>
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 
 namespace hpp
 {
@@ -48,6 +48,9 @@ namespace fcl
 
   class CollisionRequest;
 
+  /// @addtogroup Bounding_Volume
+  /// @{
+
 /// @brief KDOP class describes the KDOP collision structures. K is set as the template parameter, which should be 16, 18, or 24
 ///  The KDOP structure is defined by some pairs of parallel planes defined by some axes. 
 /// For K = 16, the planes are 6 AABB planes and 10 diagonal planes that cut off some space of the edges:
@@ -85,6 +88,10 @@ namespace fcl
 template<size_t N>
 class KDOP
 {
+private:
+  /// @brief Origin's distances to N KDOP planes
+  FCL_REAL dist_[N];
+
 public:
 
   /// @brief Creating kDOP containing nothing
@@ -107,8 +114,8 @@ public:
     return overlap (other);
   }
 
-  //// @brief Check whether one point is inside the KDOP
-  bool inside(const Vec3f& p) const;
+    /// @brief The distance between two KDOP<N>. Not implemented.
+  FCL_REAL distance(const KDOP<N>& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
 
   /// @brief Merge the point and the KDOP
   KDOP<N>& operator += (const Vec3f& p);
@@ -119,6 +126,19 @@ public:
   /// @brief Create a KDOP by mergin two KDOPs
   KDOP<N> operator + (const KDOP<N>& other) const;
 
+   /// @brief Size of the kDOP (used in BV_Splitter to order two kDOPs)
+  inline FCL_REAL size() const
+  {
+    return width() * width() + height() * height() + depth() * depth();
+  }
+
+  /// @brief The (AABB) center
+  inline Vec3f center() const
+  {
+    return Vec3f(dist_[0] + dist_[N / 2], dist_[1] + dist_[N / 2 + 1], dist_[2] + dist_[N / 2 + 2]) * 0.5;
+  }
+
+
   /// @brief The (AABB) width
   inline FCL_REAL width() const
   {
@@ -143,26 +163,6 @@ public:
     return width() * height() * depth();
   }
 
-  /// @brief Size of the kDOP (used in BV_Splitter to order two kDOPs)
-  inline FCL_REAL size() const
-  {
-    return width() * width() + height() * height() + depth() * depth();
-  }
-
-  /// @brief The (AABB) center
-  inline Vec3f center() const
-  {
-    return Vec3f(dist_[0] + dist_[N / 2], dist_[1] + dist_[N / 2 + 1], dist_[2] + dist_[N / 2 + 2]) * 0.5;
-  }
-
-  /// @brief The distance between two KDOP<N>. Not implemented.
-  FCL_REAL distance(const KDOP<N>& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
-
-private:
-  /// @brief Origin's distances to N KDOP planes
-  FCL_REAL dist_[N];
-
-public:
   inline FCL_REAL dist(std::size_t i) const
   {
     return dist_[i];
@@ -173,6 +173,8 @@ public:
     return dist_[i];
   }
 
+  //// @brief Check whether one point is inside the KDOP
+  bool inside(const Vec3f& p) const;
 
 };
 
diff --git a/include/hpp/fcl/BV/kIOS.h b/include/hpp/fcl/BV/kIOS.h
index a7228168d3d3ffcbf45defdeb6acf6d850037fb7..be1a4f0bb0d050646ed287c66245f940d43f3d3a 100644
--- a/include/hpp/fcl/BV/kIOS.h
+++ b/include/hpp/fcl/BV/kIOS.h
@@ -46,7 +46,10 @@ namespace hpp
 namespace fcl
 {
   class CollisionRequest;
- 
+
+/// @addtogroup Bounding_Volume
+/// @{
+
 /// @brief A class describing the kIOS collision structure, which is a set of spheres.
 class kIOS
 {
@@ -93,6 +96,9 @@ public:
   /// @ OBB related with kIOS
   OBB obb;
 
+  /// @brief Check whether the kIOS contains a point
+  inline bool contain(const Vec3f& p) const;
+
   /// @brief Check collision between two kIOS
   bool overlap(const kIOS& other) const;
 
@@ -100,16 +106,8 @@ public:
   bool overlap(const kIOS& other, const CollisionRequest&,
                FCL_REAL& sqrDistLowerBound) const;
 
-  /// @brief Check collision between two kIOS and return the overlap part.
-  /// For kIOS, we return nothing, as the overlappart of two kIOS usually is not an kIOS
-  /// @todo Not efficient. It first checks the sphere collisions and then use OBB for further culling.
-  bool overlap(const kIOS& other, kIOS& /*overlap_part*/) const
-  {
-    return overlap(other);
-  }
-
-  /// @brief Check whether the kIOS contains a point
-  inline bool contain(const Vec3f& p) const;
+  /// @brief The distance between two kIOS
+  FCL_REAL distance(const kIOS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
 
   /// @brief A simple way to merge the kIOS and a point
   kIOS& operator += (const Vec3f& p);
@@ -124,6 +122,9 @@ public:
   /// @brief Return the merged kIOS of current kIOS and the other one
   kIOS operator + (const kIOS& other) const;
 
+  /// @brief size of the kIOS (used in BV_Splitter to order two kIOSs)
+  FCL_REAL size() const;
+
   /// @brief Center of the kIOS
   const Vec3f& center() const
   {
@@ -141,12 +142,6 @@ public:
 
   /// @brief Volume of the kIOS
   FCL_REAL volume() const;
-
-  /// @brief size of the kIOS (used in BV_Splitter to order two kIOSs)
-  FCL_REAL size() const;
-
-  /// @brief The distance between two kIOS
-  FCL_REAL distance(const kIOS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
 };
 
 
diff --git a/include/hpp/fcl/BVH/BVH_model.h b/include/hpp/fcl/BVH/BVH_model.h
index 1f29a9bbbb8b18f3f5b34b3b605ad2c51758e386..095ff21c250877fb5b5c42a94aa0b6a89d7b3756 100644
--- a/include/hpp/fcl/BVH/BVH_model.h
+++ b/include/hpp/fcl/BVH/BVH_model.h
@@ -41,8 +41,6 @@
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/BVH/BVH_internal.h>
 #include <hpp/fcl/BV/BV_node.h>
-#include <hpp/fcl/BVH/BV_splitter.h>
-#include <hpp/fcl/BVH/BV_fitter.h>
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
@@ -52,13 +50,39 @@ namespace hpp
 namespace fcl
 {
 
-/// @brief A class describing the bounding hierarchy of a mesh model or a point cloud model (which is viewed as a degraded version of mesh)
-template<typename BV>
-class BVHModel : public CollisionGeometry,
-                 private boost::noncopyable
-{
+/// @addtogroup Construction_Of_BVH
+/// @{
+
+class ConvexBase;
+
+template <typename BV> class BVFitter;
+template <typename BV> class BVSplitter;
 
+/// @brief A base class describing the bounding hierarchy of a mesh model or a point cloud model (which is viewed as a degraded version of mesh)
+class BVHModelBase : public CollisionGeometry
+{
 public:
+  /// @brief Geometry point data
+  Vec3f* vertices;
+
+  /// @brief Geometry triangle index data, will be NULL for point clouds
+  Triangle* tri_indices;
+
+  /// @brief Geometry point data in previous frame
+  Vec3f* prev_vertices;
+
+  /// @brief Number of triangles
+  int num_tris;
+
+  /// @brief Number of points
+  int num_vertices;
+
+  /// @brief The state of BVH building process
+  BVHBuildState build_state;
+
+  /// @brief Convex<Triangle> representation of this object
+  boost::shared_ptr< ConvexBase > convex;
+  
   /// @brief Model type described by the instance
   BVHModelType getModelType() const
   {
@@ -71,64 +95,32 @@ public:
   }
 
   /// @brief Constructing an empty BVH
-  BVHModel() : vertices(NULL),
-               tri_indices(NULL),
-               prev_vertices(NULL),
-               num_tris(0),
-               num_vertices(0),
-               build_state(BVH_BUILD_STATE_EMPTY),
-               bv_splitter(new BVSplitter<BV>(SPLIT_METHOD_MEAN)),
-               bv_fitter(new BVFitter<BV>()),
-               num_tris_allocated(0),
-               num_vertices_allocated(0),
-               num_bvs_allocated(0),
-               num_vertex_updated(0),
-               primitive_indices(NULL),
-               bvs(NULL),
-               num_bvs(0)
+  BVHModelBase() : vertices(NULL),
+                   tri_indices(NULL),
+                   prev_vertices(NULL),
+                   num_tris(0),
+                   num_vertices(0),
+                   build_state(BVH_BUILD_STATE_EMPTY),
+                   num_tris_allocated(0),
+                   num_vertices_allocated(0),
+                   num_vertex_updated(0)
   {
   }
 
   /// @brief copy from another BVH
-  BVHModel(const BVHModel& other);
+  BVHModelBase(const BVHModelBase& other);
 
   /// @brief deconstruction, delete mesh data related.
-  ~BVHModel()
+  virtual ~BVHModelBase ()
   {
     delete [] vertices;
     delete [] tri_indices;
-    delete [] bvs;
-
     delete [] prev_vertices;
-    delete [] primitive_indices;
-  }
-
-  /// @brief We provide getBV() and getNumBVs() because BVH may be compressed (in future), so we must provide some flexibility here
-  
-  /// @brief Access the bv giving the its index
-  const BVNode<BV>& getBV(int id) const
-  {
-    return bvs[id];
-  }
-
-  /// @brief Access the bv giving the its index
-  BVNode<BV>& getBV(int id)
-  {
-    return bvs[id];
-  }
-
-  /// @brief Get the number of bv in the BVH
-  int getNumBVs() const
-  {
-    return num_bvs;
   }
 
   /// @brief Get the object type: it is a BVH
   OBJECT_TYPE getObjectType() const { return OT_BVH; }
 
-  /// @brief Get the BV type: default is unknown
-  NODE_TYPE getNodeType() const { return BV_UNKNOWN; }
-
   /// @brief Compute the AABB for the BVH, used for broad-phase collision
   void computeLocalAABB();
 
@@ -150,7 +142,6 @@ public:
   /// @brief End BVH model construction, will build the bounding volume hierarchy
   int endModel();
 
-
   /// @brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame)
   int beginReplaceModel();
 
@@ -166,7 +157,6 @@ public:
   /// @brief End BVH model replacement, will also refit or rebuild the bounding volume hierarchy
   int endReplaceModel(bool refit = true, bool bottomup = true);
 
-
   /// @brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame).
   /// The current frame will be saved as the previous frame in prev_vertices.
   int beginUpdateModel();
@@ -183,16 +173,16 @@ public:
   /// @brief End BVH model update, will also refit or rebuild the bounding volume hierarchy
   int endUpdateModel(bool refit = true, bool bottomup = true);
 
-  /// @brief Check the number of memory used
-  int memUsage(int msg) const;
+  /// @brief Build this Convex<Triangle> representation of this model.
+  /// \note this only takes the points of this model. It does not check that the
+  ///       object is convex. It does not compute a convex hull.
+  void buildConvexRepresentation(bool share_memory);
+
+  virtual int memUsage(int msg) const = 0;
 
   /// @brief This is a special acceleration: BVH_model default stores the BV's transform in world coordinate. However, we can also store each BV's transform related to its parent 
   /// BV node. When traversing the BVH, this can save one matrix transformation.
-  void makeParentRelative()
-  {
-    Matrix3f I (Matrix3f::Identity());
-    makeParentRelativeRecurse(0, I, Vec3f());
-  }
+  virtual void makeParentRelative() = 0;
 
   Vec3f computeCOM() const
   {
@@ -244,41 +234,89 @@ public:
     return C.trace() * Matrix3f::Identity() - C;
   }
 
-public:
-  /// @brief Geometry point data
-  Vec3f* vertices;
-
-  /// @brief Geometry triangle index data, will be NULL for point clouds
-  Triangle* tri_indices;
+protected:
+  virtual void deleteBVs() = 0;
+  virtual bool allocateBVs() = 0;
 
-  /// @brief Geometry point data in previous frame
-  Vec3f* prev_vertices;
+  /// @brief Build the bounding volume hierarchy
+  virtual int buildTree() = 0;
 
-  /// @brief Number of triangles
-  int num_tris;
+  /// @brief Refit the bounding volume hierarchy
+  virtual int refitTree(bool bottomup) = 0;
 
-  /// @brief Number of points
-  int num_vertices;
+  int num_tris_allocated;
+  int num_vertices_allocated;
+  int num_vertex_updated; /// for ccd vertex update
+};
 
-  /// @brief The state of BVH building process
-  BVHBuildState build_state;
+/// @brief A class describing the bounding hierarchy of a mesh model or a point cloud model (which is viewed as a degraded version of mesh)
+template<typename BV>
+class BVHModel : public BVHModelBase
+{
 
+public:
   /// @brief Split rule to split one BV node into two children
-  boost::shared_ptr<BVSplitterBase<BV> > bv_splitter;
+  boost::shared_ptr<BVSplitter<BV> > bv_splitter;
 
   /// @brief Fitting rule to fit a BV node to a set of geometry primitives
-  boost::shared_ptr<BVFitterBase<BV> > bv_fitter;
+  boost::shared_ptr<BVFitter<BV> > bv_fitter;
+
+  /// @brief Constructing an empty BVH
+  BVHModel();
+
+  /// @brief copy from another BVH
+  BVHModel(const BVHModel& other);
+
+  /// @brief deconstruction, delete mesh data related.
+  ~BVHModel()
+  {
+    delete [] bvs;
+    delete [] primitive_indices;
+  }
+
+  /// @brief We provide getBV() and getNumBVs() because BVH may be compressed (in future), so we must provide some flexibility here
+  
+  /// @brief Access the bv giving the its index
+  const BVNode<BV>& getBV(int id) const
+  {
+    assert (id < num_bvs);
+    return bvs[id];
+  }
+
+  /// @brief Access the bv giving the its index
+  BVNode<BV>& getBV(int id)
+  {
+    assert (id < num_bvs);
+    return bvs[id];
+  }
+
+  /// @brief Get the number of bv in the BVH
+  int getNumBVs() const
+  {
+    return num_bvs;
+  }
 
+  /// @brief Get the BV type: default is unknown
+  NODE_TYPE getNodeType() const { return BV_UNKNOWN; }
+
+  /// @brief Check the number of memory used
+  int memUsage(int msg) const;
+
+  /// @brief This is a special acceleration: BVH_model default stores the BV's transform in world coordinate. However, we can also store each BV's transform related to its parent 
+  /// BV node. When traversing the BVH, this can save one matrix transformation.
+  void makeParentRelative()
+  {
+    Matrix3f I (Matrix3f::Identity());
+    makeParentRelativeRecurse(0, I, Vec3f());
+  }
 
 private:
+  void deleteBVs();
+  bool allocateBVs();
 
-  int num_tris_allocated;
-  int num_vertices_allocated;
   int num_bvs_allocated;
-  int num_vertex_updated; /// for ccd vertex update
   unsigned int* primitive_indices;
 
-
   /// @brief Bounding volume hierarchy
   BVNode<BV>* bvs;
 
@@ -303,7 +341,7 @@ private:
   /// @brief Recursive kernel for bottomup refitting 
   int recursiveRefitTree_bottomup(int bv_id);
 
-  /// @recursively compute each bv's transform related to its parent. For default BV, only the translation works. 
+  /// @ recursively compute each bv's transform related to its parent. For default BV, only the translation works. 
   /// For oriented BV (OBB, RSS, OBBRSS), special implementation is provided.
   void makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes, const Vec3f& parent_c)
   {
@@ -318,6 +356,7 @@ private:
   }
 };
 
+/// @}
 
 template<>
 void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes, const Vec3f& parent_c);
diff --git a/include/hpp/fcl/BVH/BVH_utility.h b/include/hpp/fcl/BVH/BVH_utility.h
index 85110c265b2d383fa9b72590e69b6f121c6dd393..e87cf918fe29abd65dcf2f25c3b11d5de3670de8 100644
--- a/include/hpp/fcl/BVH/BVH_utility.h
+++ b/include/hpp/fcl/BVH/BVH_utility.h
@@ -46,39 +46,6 @@ namespace hpp
 {
 namespace fcl
 {
-/// @brief Expand the BVH bounding boxes according to the variance matrix corresponding to the data stored within each BV node
-template<typename BV>
-void BVHExpand(BVHModel<BV>& model, const Variance3f* ucs, FCL_REAL r)
-{
-  for(int i = 0; i < model.num_bvs; ++i)
-  {
-    BVNode<BV>& bvnode = model.getBV(i);
-
-    BV bv;
-    for(int j = 0; j < bvnode.num_primitives; ++j)
-    {
-      int v_id = bvnode.first_primitive + j;
-      const Variance3f& uc = ucs[v_id];
-
-      Vec3f& v = model.vertices[bvnode.first_primitive + j];
-
-      for(int k = 0; k < 3; ++k)
-      {
-        bv += (v + uc.axis[k] * (r * uc.sigma[k]));
-        bv += (v - uc.axis[k] * (r * uc.sigma[k]));
-      }
-    }
-
-    bvnode.bv = bv;
-  }
-}
-
-/// @brief Expand the BVH bounding boxes according to the corresponding variance information, for OBB
-void BVHExpand(BVHModel<OBB>& model, const Variance3f* ucs, FCL_REAL r);
-
-/// @brief Expand the BVH bounding boxes according to the corresponding variance information, for RSS
-void BVHExpand(BVHModel<RSS>& model, const Variance3f* ucs, FCL_REAL r);
-
 /// @brief Extract the part of the BVHModel that is inside an AABB.
 /// A triangle in collision with the AABB is considered inside.
 template<typename BV>
@@ -99,7 +66,6 @@ void circumCircleComputation(const Vec3f& a, const Vec3f& b, const Vec3f& c, Vec
 /// @brief Compute the maximum distance from a given center point to a point cloud
 FCL_REAL maximumDistance(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, const Vec3f& query);
 
-
 }
 
 } // namespace hpp
diff --git a/include/hpp/fcl/collision.h b/include/hpp/fcl/collision.h
index f673494defbe47ff01b4217928990d7cbf84bd8f..c17759919ae445a4e69df4b7b75c12ce6c83a8a4 100644
--- a/include/hpp/fcl/collision.h
+++ b/include/hpp/fcl/collision.h
@@ -39,7 +39,7 @@
 #ifndef HPP_FCL_COLLISION_H
 #define HPP_FCL_COLLISION_H
 
-#include <hpp/fcl/math/vec_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/collision_data.h>
 
@@ -52,15 +52,13 @@ namespace fcl
 /// returning all the contact points), whether return detailed contact information (i.e., normal, contact point, depth; otherwise only contact primitive id is returned), this function
 /// performs the collision between them. 
 /// Return value is the number of contacts generated between the two objects.
-
 std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
-                    const CollisionRequest& request,
-                    CollisionResult& result);
+                    const CollisionRequest& request, CollisionResult& result);
 
+/// @copydoc collide(const CollisionObject*, const CollisionObject*, const CollisionRequest&, CollisionResult&)
 std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
                     const CollisionGeometry* o2, const Transform3f& tf2,
-                    const CollisionRequest& request,
-                    CollisionResult& result);
+                    const CollisionRequest& request, CollisionResult& result);
 }
 
 } // namespace hpp
diff --git a/include/hpp/fcl/collision_data.h b/include/hpp/fcl/collision_data.h
index 88ed5d23949ef53f4c8a54375fa72c6f069d589d..fdc9993acfe47bfe90f40230b8f9cb1730c8b0ec 100644
--- a/include/hpp/fcl/collision_data.h
+++ b/include/hpp/fcl/collision_data.h
@@ -41,7 +41,7 @@
 
 #include <hpp/fcl/collision_object.h>
 
-#include <hpp/fcl/math/vec_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <vector>
 #include <set>
 #include <limits>
@@ -215,7 +215,7 @@ public:
   Vec3f cached_gjk_guess;
 
   /// Lower bound on distance between objects if they are disjoint
-  /// \note computed only on request.
+  /// @note computed only on request.
   FCL_REAL distance_lower_bound;
 
 public:
@@ -259,7 +259,7 @@ public:
   }
 
   /// @brief get all the contacts
-  void getContacts(std::vector<Contact>& contacts_)
+  void getContacts(std::vector<Contact>& contacts_) const
   {
     contacts_.resize(contacts.size());
     std::copy(contacts.begin(), contacts.end(), contacts_.begin());
diff --git a/include/hpp/fcl/collision_func_matrix.h b/include/hpp/fcl/collision_func_matrix.h
index 417039ca642447e3ecf0405861e3cf51c25fd233..892ea4013d870af3a8be510593454934f3931f6f 100644
--- a/include/hpp/fcl/collision_func_matrix.h
+++ b/include/hpp/fcl/collision_func_matrix.h
@@ -42,6 +42,7 @@
 
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/collision_data.h>
+#include <hpp/fcl/narrowphase/narrowphase.h>
 
 namespace hpp
 {
@@ -49,7 +50,7 @@ namespace fcl
 {
 
 /// @brief collision matrix stores the functions for collision between different types of objects and provides a uniform call interface
-template<typename NarrowPhaseSolver>
+
 struct CollisionFunctionMatrix
 {
   /// @brief the uniform call interface for collision: for collision, we need know
@@ -57,7 +58,7 @@ struct CollisionFunctionMatrix
   /// 2. the solver for narrow phase collision, this is for the collision between geometric shapes;
   /// 3. the request setting for collision (e.g., whether need to return normal information, whether need to compute cost);
   /// 4. the structure to return collision result
-  typedef std::size_t (*CollisionFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, const CollisionRequest& request, CollisionResult& result);
+  typedef std::size_t (*CollisionFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result);
 
   /// @brief each item in the collision matrix is a function to handle collision between objects of type1 and type2
   CollisionFunc collision_matrix[NODE_COUNT][NODE_COUNT];
diff --git a/include/hpp/fcl/collision_object.h b/include/hpp/fcl/collision_object.h
index 6dd142e8102435455897aa633336dd316ffbc7bc..1e743dbd08709af80e789ca23e63901c97c0bf45 100644
--- a/include/hpp/fcl/collision_object.h
+++ b/include/hpp/fcl/collision_object.h
@@ -56,6 +56,9 @@ enum OBJECT_TYPE {OT_UNKNOWN, OT_BVH, OT_GEOM, OT_OCTREE, OT_COUNT};
 enum NODE_TYPE {BV_UNKNOWN, BV_AABB, BV_OBB, BV_RSS, BV_kIOS, BV_OBBRSS, BV_KDOP16, BV_KDOP18, BV_KDOP24,
                 GEOM_BOX, GEOM_SPHERE, GEOM_CAPSULE, GEOM_CONE, GEOM_CYLINDER, GEOM_CONVEX, GEOM_PLANE, GEOM_HALFSPACE, GEOM_TRIANGLE, GEOM_OCTREE, NODE_COUNT};
 
+/// @addtogroup Construction_Of_BVH
+/// @{
+
 /// @brief The geometry for the object for collision or distance computation
 class CollisionGeometry
 {
@@ -203,7 +206,7 @@ public:
   /// @brief compute the AABB in world space
   inline void computeAABB()
   {
-    if(isQuatIdentity(t.getQuatRotation()))
+    if(t.getRotation().isIdentity())
     {
       aabb = translate(cgeom->aabb_local, t.getTranslation());
     }
@@ -240,12 +243,6 @@ public:
     return t.getRotation();
   }
 
-  /// @brief get quaternion rotation of the object
-  inline const Quaternion3f& getQuatRotation() const
-  {
-    return t.getQuatRotation();
-  }
-
   /// @brief get object's transform
   inline const Transform3f& getTransform() const
   {
@@ -264,11 +261,7 @@ public:
     t.setTranslation(T);
   }
 
-  /// @brief set object's quatenrion rotation
-  void setQuatRotation(const Quaternion3f& q)
-  {
-    t.setQuatRotation(q);
-  }
+
 
   /// @brief set object's transform
   void setTransform(const Matrix3f& R, const Vec3f& T)
@@ -276,11 +269,7 @@ public:
     t.setTransform(R, T);
   }
 
-  /// @brief set object's transform
-  void setTransform(const Quaternion3f& q, const Vec3f& T)
-  {
-    t.setTransform(q, T);
-  }
+ 
 
   /// @brief set object's transform
   void setTransform(const Transform3f& tf)
diff --git a/include/hpp/fcl/data_types.h b/include/hpp/fcl/data_types.h
index fb234d919bacb5ba90718929719462f91be494c3..3d3c3beab99fbb660b46e55b09fa37d4e47f2616 100644
--- a/include/hpp/fcl/data_types.h
+++ b/include/hpp/fcl/data_types.h
@@ -41,47 +41,75 @@
 #include <cstddef>
 #include <boost/cstdint.hpp>
 
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+
+namespace hpp
+{
+
+#ifdef HPP_FCL_HAVE_OCTOMAP
+  #define OCTOMAP_VERSION_AT_LEAST(x,y,z) \
+    (OCTOMAP_MAJOR_VERSION > x || (OCTOMAP_MAJOR_VERSION >= x && \
+    (OCTOMAP_MINOR_VERSION > y || (OCTOMAP_MINOR_VERSION >= y && \
+    OCTOMAP_PATCH_VERSION >= z))))
+
+  #define OCTOMAP_VERSION_AT_MOST(x,y,z) \
+    (OCTOMAP_MAJOR_VERSION < x || (OCTOMAP_MAJOR_VERSION <= x && \
+    (OCTOMAP_MINOR_VERSION < y || (OCTOMAP_MINOR_VERSION <= y && \
+    OCTOMAP_PATCH_VERSION <= z))))
+#endif // HPP_FCL_HAVE_OCTOMAP
+}
+
 namespace hpp
 {
 namespace fcl
 {
-
 typedef double FCL_REAL;
 typedef boost::uint64_t FCL_INT64;
 typedef boost::int64_t FCL_UINT64;
 typedef boost::uint32_t FCL_UINT32;
 typedef boost::int32_t FCL_INT32;
+typedef Eigen::Matrix<FCL_REAL, 3, 1> Vec3f;
+typedef Eigen::Matrix<FCL_REAL, 3, 3> Matrix3f;
 
 /// @brief Triangle with 3 indices for points
 class Triangle
 {
-  /// @brief indices for each vertex of triangle
-  std::size_t vids[3];
-
 public:
+  typedef std::size_t index_type;
+  typedef int size_type;
+
   /// @brief Default constructor
   Triangle() {}
 
   /// @brief Create a triangle with given vertex indices
-  Triangle(std::size_t p1, std::size_t p2, std::size_t p3)
+  Triangle(index_type p1, index_type p2, index_type p3)
   {
     set(p1, p2, p3);
   }
 
   /// @brief Set the vertex indices of the triangle
-  inline void set(std::size_t p1, std::size_t p2, std::size_t p3)
+  inline void set(index_type p1, index_type p2, index_type p3)
   {
     vids[0] = p1; vids[1] = p2; vids[2] = p3;
   }
 
   /// @access the triangle index
-  inline std::size_t operator[](int i) const { return vids[i]; }
+  inline index_type operator[](int i) const { return vids[i]; }
 
-  inline std::size_t& operator[](int i) { return vids[i]; }
+  inline index_type& operator[](int i) { return vids[i]; }
+
+  static inline size_type size() { return 3; }
+
+private:
+  /// @brief indices for each vertex of triangle
+  index_type vids[3];
 };
 
 }
 
 } // namespace hpp
 
+
 #endif
diff --git a/include/hpp/fcl/distance.h b/include/hpp/fcl/distance.h
index 87216ce6df8a1621f7bf885f94fd243ece3c64e0..45bbcbd736a89d860e759cd1d61b49350584f403 100644
--- a/include/hpp/fcl/distance.h
+++ b/include/hpp/fcl/distance.h
@@ -33,7 +33,7 @@
  *  POSSIBILITY OF SUCH DAMAGE.
  */
 
-/** \author Jia Pan */
+/** @author Jia Pan */
 
 #ifndef HPP_FCL_DISTANCE_H
 #define HPP_FCL_DISTANCE_H
@@ -48,14 +48,12 @@ 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.
+FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const DistanceRequest& request, DistanceResult& result);
 
-FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2,
-                  const DistanceRequest& request, DistanceResult& result);
-
+/// @copydoc distance(const CollisionObject*, const CollisionObject*, const DistanceRequest&, DistanceResult&)
 FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1,
                   const CollisionGeometry* o2, const Transform3f& tf2,
                   const DistanceRequest& request, DistanceResult& result);
-
 }
 
 } // namespace hpp
diff --git a/include/hpp/fcl/distance_func_matrix.h b/include/hpp/fcl/distance_func_matrix.h
index c5a6f44cc622fdfdfd6121641b705d5634a4afb4..1f0ea6d26e573f065a6a97cc6552fff40ba31a20 100644
--- a/include/hpp/fcl/distance_func_matrix.h
+++ b/include/hpp/fcl/distance_func_matrix.h
@@ -40,6 +40,7 @@
 
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/collision_data.h>
+#include <hpp/fcl/narrowphase/narrowphase.h>
 
 namespace hpp
 {
@@ -47,14 +48,13 @@ namespace fcl
 {
 
 /// @brief distance matrix stores the functions for distance between different types of objects and provides a uniform call interface
-template<typename NarrowPhaseSolver>
 struct DistanceFunctionMatrix
 {
   /// @brief the uniform call interface for distance: for distance, we need know
   /// 1. two objects o1 and o2 and their configuration in world coordinate tf1 and tf2;
   /// 2. the solver for narrow phase collision, this is for distance computation between geometric shapes;
   /// 3. the request setting for distance (e.g., whether need to return nearest points);
-  typedef FCL_REAL (*DistanceFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+  typedef FCL_REAL (*DistanceFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                                    const DistanceRequest& request, DistanceResult& result);
   
   /// @brief each item in the distance matrix is a function to handle distance between objects of type1 and type2
diff --git a/include/hpp/fcl/fwd.hh b/include/hpp/fcl/fwd.hh
index 45fc60eceb5bc2e808476d4e72b2843cb045db57..e2fa5302856031621f7dac2ffb0022117b846afc 100644
--- a/include/hpp/fcl/fwd.hh
+++ b/include/hpp/fcl/fwd.hh
@@ -37,6 +37,8 @@
 #ifndef HPP_FCL_FWD_HH
 #define HPP_FCL_FWD_HH
 
+#include <boost/shared_ptr.hpp>
+
 namespace hpp {
 namespace fcl {
   class CollisionObject;
@@ -49,6 +51,9 @@ namespace fcl {
   class Transform3f;
 
   class AABB;
+
+  class BVHModelBase;
+  typedef boost::shared_ptr<BVHModelBase> BVHModelPtr_t;
 }
 } // namespace hpp
 
diff --git a/include/hpp/fcl/BVH/BV_fitter.h b/include/hpp/fcl/internal/BV_fitter.h
similarity index 60%
rename from include/hpp/fcl/BVH/BV_fitter.h
rename to include/hpp/fcl/internal/BV_fitter.h
index 8a1585343e57b2329512c1223073730737dae615..d8070d695129b820c00a979007416b3e8cf5e70e 100644
--- a/include/hpp/fcl/BVH/BV_fitter.h
+++ b/include/hpp/fcl/internal/BV_fitter.h
@@ -41,6 +41,7 @@
 #include <hpp/fcl/BVH/BVH_internal.h>
 #include <hpp/fcl/BV/kIOS.h>
 #include <hpp/fcl/BV/OBBRSS.h>
+#include <hpp/fcl/BV/AABB.h>
 #include <iostream>
 
 namespace hpp
@@ -70,32 +71,16 @@ void fit<kIOS>(Vec3f* ps, int n, kIOS& bv);
 template<>
 void fit<OBBRSS>(Vec3f* ps, int n, OBBRSS& bv);
 
-
-/// @brief Interface for fitting a bv given the triangles or points inside it.
-template<typename BV>
-class BVFitterBase
-{
-public:
-  /// @brief Set the primitives to be processed by the fitter
-  virtual void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) = 0;
-
-  /// @brief Set the primitives to be processed by the fitter, for deformable mesh.
-  virtual void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) = 0;
-
-  /// @brief Compute the fitting BV
-  virtual BV fit(unsigned int* primitive_indices, int num_primitives) = 0;
-
-  /// @brief clear the temporary data generated.
-  virtual void clear() = 0;
-};
+template<>
+void fit<AABB>(Vec3f* ps, int n, AABB& bv);
 
 /// @brief The class for the default algorithm fitting a bounding volume to a set of points
 template<typename BV>
-class BVFitter : public BVFitterBase<BV>
+class BVFitterTpl
 {
 public:
   /// @brief default deconstructor
-  virtual ~BVFitter() {}
+  virtual ~BVFitterTpl() {}
 
   /// @brief Prepare the geometry primitive data for fitting
   void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
@@ -115,6 +100,31 @@ public:
     type = type_;
   }
 
+  /// @brief Compute the fitting BV
+  virtual BV fit(unsigned int* primitive_indices, int num_primitives) = 0;
+
+  /// @brief Clear the geometry primitive data
+  void clear()
+  {
+    vertices = NULL;
+    prev_vertices = NULL;
+    tri_indices = NULL;
+    type = BVH_MODEL_UNKNOWN;
+  }
+
+protected:
+
+  Vec3f* vertices;
+  Vec3f* prev_vertices;
+  Triangle* tri_indices;
+  BVHModelType type;
+};
+
+/// @brief The class for the default algorithm fitting a bounding volume to a set of points
+template<typename BV>
+class BVFitter : public BVFitterTpl<BV>
+{
+public:
   /// @brief Compute a bounding volume that fits a set of primitives (points or triangles).
   /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data
   BV fit(unsigned int* primitive_indices, int num_primitives)
@@ -154,200 +164,61 @@ public:
     return bv;
   }
 
-  /// @brief Clear the geometry primitive data
-  void clear()
-  {
-    vertices = NULL;
-    prev_vertices = NULL;
-    tri_indices = NULL;
-    type = BVH_MODEL_UNKNOWN;
-  }
-
-private:
-
-  Vec3f* vertices;
-  Vec3f* prev_vertices;
-  Triangle* tri_indices;
-  BVHModelType type;
+protected:
+  using BVFitterTpl<BV>::vertices;
+  using BVFitterTpl<BV>::prev_vertices;
+  using BVFitterTpl<BV>::tri_indices;
+  using BVFitterTpl<BV>::type;
 };
 
-
 /// @brief Specification of BVFitter for OBB bounding volume
 template<>
-class BVFitter<OBB> : public BVFitterBase<OBB>
+class BVFitter<OBB> : public BVFitterTpl<OBB>
 {
 public:
-  /// @brief Prepare the geometry primitive data for fitting
-  void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = NULL;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
-  /// @brief Prepare the geometry primitive data for fitting, for deformable mesh
-  void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = prev_vertices_;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
   /// @brief Compute a bounding volume that fits a set of primitives (points or triangles).
   /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data.
   OBB fit(unsigned int* primitive_indices, int num_primitives);
-
-  /// brief Clear the geometry primitive data
-  void clear()
-  {
-    vertices = NULL;
-    prev_vertices = NULL;
-    tri_indices = NULL;
-    type = BVH_MODEL_UNKNOWN;
-  }
-
-private:
-
-  Vec3f* vertices;
-  Vec3f* prev_vertices;
-  Triangle* tri_indices;
-  BVHModelType type;
 };
 
-
 /// @brief Specification of BVFitter for RSS bounding volume
 template<>
-class BVFitter<RSS> : public BVFitterBase<RSS>
+class BVFitter<RSS> : public BVFitterTpl<RSS>
 {
 public:
-  /// brief Prepare the geometry primitive data for fitting
-  void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = NULL;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
-  /// @brief Prepare the geometry primitive data for fitting, for deformable mesh
-  void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = prev_vertices_;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
   /// @brief Compute a bounding volume that fits a set of primitives (points or triangles).
   /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data.
   RSS fit(unsigned int* primitive_indices, int num_primitives);
-
-  /// @brief Clear the geometry primitive data
-  void clear()
-  {
-    vertices = NULL;
-    prev_vertices = NULL;
-    tri_indices = NULL;
-    type = BVH_MODEL_UNKNOWN;
-  }
-
-private:
-
-  Vec3f* vertices;
-  Vec3f* prev_vertices;
-  Triangle* tri_indices;
-  BVHModelType type;
 };
 
-
 /// @brief Specification of BVFitter for kIOS bounding volume
 template<>
-class BVFitter<kIOS> : public BVFitterBase<kIOS>
+class BVFitter<kIOS> : public BVFitterTpl<kIOS>
 {
 public:
-  /// @brief Prepare the geometry primitive data for fitting
-  void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = NULL;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
-  /// @brief Prepare the geometry primitive data for fitting
-  void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = prev_vertices_;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
   /// @brief Compute a bounding volume that fits a set of primitives (points or triangles).
   /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data.
   kIOS fit(unsigned int* primitive_indices, int num_primitives);
-
-  /// @brief Clear the geometry primitive data
-  void clear()
-  {
-    vertices = NULL;
-    prev_vertices = NULL;
-    tri_indices = NULL;
-    type = BVH_MODEL_UNKNOWN;
-  }
-
-private:
-  Vec3f* vertices;
-  Vec3f* prev_vertices;
-  Triangle* tri_indices;
-  BVHModelType type;
 };
 
-
 /// @brief Specification of BVFitter for OBBRSS bounding volume
 template<>
-class BVFitter<OBBRSS> : public BVFitterBase<OBBRSS>
+class BVFitter<OBBRSS> : public BVFitterTpl<OBBRSS>
 {
 public:
-  /// @brief Prepare the geometry primitive data for fitting
-  void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = NULL;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
-  /// @brief Prepare the geometry primitive data for fitting
-  void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_)
-  {
-    vertices = vertices_;
-    prev_vertices = prev_vertices_;
-    tri_indices = tri_indices_;
-    type = type_;
-  }
-
   /// @brief Compute a bounding volume that fits a set of primitives (points or triangles).
   /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data.
   OBBRSS fit(unsigned int* primitive_indices, int num_primitives);
+};
 
-  /// @brief Clear the geometry primitive data
-  void clear()
-  {
-    vertices = NULL;
-    prev_vertices = NULL;
-    tri_indices = NULL;
-    type = BVH_MODEL_UNKNOWN;
-  }
-
-private:
-
-  Vec3f* vertices;
-  Vec3f* prev_vertices;
-  Triangle* tri_indices;
-  BVHModelType type;
+/// @brief Specification of BVFitter for AABB bounding volume
+template<>
+class BVFitter<AABB> : public BVFitterTpl<AABB>
+{
+public:
+  /// @brief Compute a bounding volume that fits a set of primitives (points or triangles).
+  /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data.
+  AABB fit(unsigned int* primitive_indices, int num_primitives);
 };
 
 }
diff --git a/include/hpp/fcl/BVH/BV_splitter.h b/include/hpp/fcl/internal/BV_splitter.h
similarity index 92%
rename from include/hpp/fcl/BVH/BV_splitter.h
rename to include/hpp/fcl/internal/BV_splitter.h
index 7ad7bd996b0d6fef5b96318256579f03f0f6cd1b..7be8ca7490f7ae6fe3e268e4ac3a3c6b8d3e0e52 100644
--- a/include/hpp/fcl/BVH/BV_splitter.h
+++ b/include/hpp/fcl/internal/BV_splitter.h
@@ -49,32 +49,13 @@ namespace hpp
 namespace fcl
 {
 
-/// @brief Base interface for BV splitting algorithm
-template<typename BV>
-class BVSplitterBase
-{
-public:
-  /// @brief Set the geometry data needed by the split rule
-  virtual void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) = 0;
-
-  /// @brief Compute the split rule according to a subset of geometry and the corresponding BV node
-  virtual void computeRule(const BV& bv, unsigned int* primitive_indices, int num_primitives) = 0;
-
-  /// @brief Apply the split rule on a given point
-  virtual bool apply(const Vec3f& q) const = 0;
-
-  /// @brief Clear the geometry data set before
-  virtual void clear() = 0;
-};
-
-
 /// @brief Three types of split algorithms are provided in FCL as default
 enum SplitMethodType {SPLIT_METHOD_MEAN, SPLIT_METHOD_MEDIAN, SPLIT_METHOD_BV_CENTER};
 
 
 /// @brief A class describing the split rule that splits each BV node
 template<typename BV>
-class BVSplitter : public BVSplitterBase<BV>
+class BVSplitter
 {
 public:
 
diff --git a/include/hpp/fcl/intersect.h b/include/hpp/fcl/internal/intersect.h
similarity index 76%
rename from include/hpp/fcl/intersect.h
rename to include/hpp/fcl/internal/intersect.h
index b56a6c626389fd6628ea5ef31b79a9f9a9fff38b..b0b397a3aeb3e4dcf5c4e4a55bdcc5fa331eb346 100644
--- a/include/hpp/fcl/intersect.h
+++ b/include/hpp/fcl/internal/intersect.h
@@ -38,45 +38,24 @@
 #ifndef HPP_FCL_INTERSECT_H
 #define HPP_FCL_INTERSECT_H
 
+/// @cond INTERNAL
+
 #include <hpp/fcl/math/transform.h>
 #include <boost/math/special_functions/erf.hpp>
 
-namespace hpp
-{
+namespace hpp
+{
 namespace fcl
 {
 
-/// @brief A class solves polynomial degree (1,2,3) equations 
-class PolySolver
+/// @brief CCD intersect kernel among primitives
+class Intersect
 {
 public:
-  /// @brief Solve a linear equation with coefficients c, return roots s and number of roots 
-  static int solveLinear(FCL_REAL c[2], FCL_REAL s[1]);
-
-  /// @brief Solve a quadratic function with coefficients c, return roots s and number of roots 
-  static int solveQuadric(FCL_REAL c[3], FCL_REAL s[2]);
-
-  /// @brief Solve a cubic function with coefficients c, return roots s and number of roots 
-  static int solveCubic(FCL_REAL c[4], FCL_REAL s[3]);
-
-private:
-  /// @brief Check whether v is zero 
-  static inline bool isZero(FCL_REAL v);
+  static bool buildTrianglePlane
+    (const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, FCL_REAL* t);
+}; // class Intersect
 
-  /// @brief Compute v^{1/3} 
-  static inline bool cbrt(FCL_REAL v);
-
-  static const FCL_REAL NEAR_ZERO_THRESHOLD;
-};
-
-/// @brief CCD intersect kernel among primitives
-class Intersect
-{
-public:
-  static bool buildTrianglePlane
-    (const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, FCL_REAL* t);
-}; // class Intersect
-
 /// @brief Project functions
 class Project
 {
@@ -130,9 +109,9 @@ public:
                         Vec3f& VEC, Vec3f& X, Vec3f& Y);
 
   /// Compute squared distance between triangles
-  /// \param S and T are two triangles
-  /// \retval P, Q closest points if triangles do not intersect.
-  /// \return squared distance if triangles do not intersect, 0 otherwise.
+  /// @param S and T are two triangles
+  /// @retval P, Q closest points if triangles do not intersect.
+  /// @return squared distance if triangles do not intersect, 0 otherwise.
   /// If the triangles are disjoint, P and Q give the closet points of
   /// S and T respectively. However,
   /// if the triangles overlap, P and Q are basically a random pair of points
@@ -147,10 +126,10 @@ public:
 				  Vec3f& P, Vec3f& Q);
 
   /// Compute squared distance between triangles
-  /// \param S and T are two triangles
-  /// \param R, Tl, rotation and translation applied to T,
-  /// \retval P, Q closest points if triangles do not intersect.
-  /// \return squared distance if triangles do not intersect, 0 otherwise.
+  /// @param S and T are two triangles
+  /// @param R, Tl, rotation and translation applied to T,
+  /// @retval P, Q closest points if triangles do not intersect.
+  /// @return squared distance if triangles do not intersect, 0 otherwise.
   /// If the triangles are disjoint, P and Q give the closet points of
   /// S and T respectively. However,
   /// if the triangles overlap, P and Q are basically a random pair of points
@@ -161,10 +140,10 @@ public:
 				  Vec3f& P, Vec3f& Q);
 
   /// Compute squared distance between triangles
-  /// \param S and T are two triangles
-  /// \param tf, rotation and translation applied to T,
-  /// \retval P, Q closest points if triangles do not intersect.
-  /// \return squared distance if triangles do not intersect, 0 otherwise.
+  /// @param S and T are two triangles
+  /// @param tf, rotation and translation applied to T,
+  /// @retval P, Q closest points if triangles do not intersect.
+  /// @return squared distance if triangles do not intersect, 0 otherwise.
   /// If the triangles are disjoint, P and Q give the closet points of
   /// S and T respectively. However,
   /// if the triangles overlap, P and Q are basically a random pair of points
@@ -176,10 +155,10 @@ public:
 
 
   /// Compute squared distance between triangles
-  /// \param S1, S2, S3 and T1, T2, T3 are triangle vertices
-  /// \param R, Tl, rotation and translation applied to T1, T2, T3,
-  /// \retval P, Q closest points if triangles do not intersect.
-  /// \return squared distance if triangles do not intersect, 0 otherwise.
+  /// @param S1, S2, S3 and T1, T2, T3 are triangle vertices
+  /// @param R, Tl, rotation and translation applied to T1, T2, T3,
+  /// @retval P, Q closest points if triangles do not intersect.
+  /// @return squared distance if triangles do not intersect, 0 otherwise.
   /// If the triangles are disjoint, P and Q give the closet points of
   /// S and T respectively. However,
   /// if the triangles overlap, P and Q are basically a random pair of points
@@ -192,10 +171,10 @@ public:
 				  Vec3f& P, Vec3f& Q);
 
   /// Compute squared distance between triangles
-  /// \param S1, S2, S3 and T1, T2, T3 are triangle vertices
-  /// \param tf, rotation and translation applied to T1, T2, T3,
-  /// \retval P, Q closest points if triangles do not intersect.
-  /// \return squared distance if triangles do not intersect, 0 otherwise.
+  /// @param S1, S2, S3 and T1, T2, T3 are triangle vertices
+  /// @param tf, rotation and translation applied to T1, T2, T3,
+  /// @retval P, Q closest points if triangles do not intersect.
+  /// @return squared distance if triangles do not intersect, 0 otherwise.
   /// If the triangles are disjoint, P and Q give the closet points of
   /// S and T respectively. However,
   /// if the triangles overlap, P and Q are basically a random pair of points
@@ -209,10 +188,10 @@ public:
 
 };
 
-
 }
 
+} // namespace hpp
+
+/// @endcond
 
-} // namespace hpp
-
 #endif
diff --git a/include/hpp/fcl/math/tools.h b/include/hpp/fcl/internal/tools.h
similarity index 84%
rename from include/hpp/fcl/math/tools.h
rename to include/hpp/fcl/internal/tools.h
index cfc19640f5d48b3aeef4c38e3707ee558fb958e1..8ad8a7abc3d1b82df20d475fafdfb2b14057972a 100644
--- a/include/hpp/fcl/math/tools.h
+++ b/include/hpp/fcl/internal/tools.h
@@ -98,14 +98,6 @@ void generateCoordinateSystem(
 }
 
 /* ----- Start Matrices ------ */
-template<typename Derived, typename OtherDerived>
-void hat(const Eigen::MatrixBase<Derived>& mat, const Eigen::MatrixBase<OtherDerived>& vec)
-{
-  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived, 3, 3);
-  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(OtherDerived, 3, 1);
-  const_cast< Eigen::MatrixBase<Derived>& >(mat) << 0, -vec[2], vec[1], vec[2], 0, -vec[0], -vec[1], vec[0], 0;
-}
-
 template<typename Derived, typename OtherDerived>
 void relativeTransform(const Eigen::MatrixBase<Derived>& R1, const Eigen::MatrixBase<OtherDerived>& t1,
                        const Eigen::MatrixBase<Derived>& R2, const Eigen::MatrixBase<OtherDerived>& t2,
@@ -205,38 +197,13 @@ void eigen(const Eigen::MatrixBase<Derived>& m, typename Derived::Scalar dout[3]
   return;
 }
 
-template<typename Derived, typename OtherDerived>
-typename Derived::Scalar quadraticForm(const Eigen::MatrixBase<Derived>& R, const Eigen::MatrixBase<OtherDerived>& v)
-{
-  return v.dot(R * v);
-}
-
 template<typename Derived, typename OtherDerived>
 bool isEqual(const Eigen::MatrixBase<Derived>& lhs, const Eigen::MatrixBase<OtherDerived>& rhs, const FCL_REAL tol = std::numeric_limits<FCL_REAL>::epsilon()*100)
 {
   return ((lhs - rhs).array().abs() < tol).all();
 }
 
-template <typename Derived>
-inline Derived& setEulerZYX(const Eigen::MatrixBase<Derived>& R, FCL_REAL eulerX, FCL_REAL eulerY, FCL_REAL eulerZ)
-{
-  const_cast< Eigen::MatrixBase<Derived>& >(R).noalias() = (
-      Eigen::AngleAxisd (eulerZ, Eigen::Vector3d::UnitZ()) *
-      Eigen::AngleAxisd (eulerY, Eigen::Vector3d::UnitY()) *
-      Eigen::AngleAxisd (eulerX, Eigen::Vector3d::UnitX())
-      ).toRotationMatrix();
-  return const_cast< Eigen::MatrixBase<Derived>& >(R).derived();
-}
-
-template <typename Derived>
-inline Derived& setEulerYPR(const Eigen::MatrixBase<Derived>& R, FCL_REAL yaw, FCL_REAL pitch, FCL_REAL roll)
-{
-  return setEulerZYX(R, roll, pitch, yaw);
 }
-
-}
-
-
 } // namespace hpp
 
-#endif
+#endif
\ No newline at end of file
diff --git a/include/hpp/fcl/traversal/details/traversal.h b/include/hpp/fcl/internal/traversal.h
similarity index 98%
rename from include/hpp/fcl/traversal/details/traversal.h
rename to include/hpp/fcl/internal/traversal.h
index 2979a601f169303b8f3e6cf5b0a010c18d0e43fa..82553dcd6587be92f4279d1fae1f6077f5aa3e4b 100644
--- a/include/hpp/fcl/traversal/details/traversal.h
+++ b/include/hpp/fcl/internal/traversal.h
@@ -34,10 +34,11 @@
 
 /** \author Joseph Mirabel */
 
-
 #ifndef HPP_FCL_TRAVERSAL_DETAILS_TRAVERSAL_H
 #define HPP_FCL_TRAVERSAL_DETAILS_TRAVERSAL_H
 
+/// @cond INTERNAL
+
 namespace hpp
 {
 namespace fcl
@@ -73,4 +74,6 @@ namespace details
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/traversal/traversal_node_base.h b/include/hpp/fcl/internal/traversal_node_base.h
similarity index 86%
rename from include/hpp/fcl/traversal/traversal_node_base.h
rename to include/hpp/fcl/internal/traversal_node_base.h
index 918505de5e55d4f0678e8dad64603c96378559ba..6f6c41e32afcd3ddfbf79a11a32a6fefab5eab15 100644
--- a/include/hpp/fcl/traversal/traversal_node_base.h
+++ b/include/hpp/fcl/internal/traversal_node_base.h
@@ -38,6 +38,8 @@
 #ifndef HPP_FCL_TRAVERSAL_NODE_BASE_H
 #define HPP_FCL_TRAVERSAL_NODE_BASE_H
 
+/// @cond INTERNAL
+
 #include <hpp/fcl/data_types.h>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/collision_data.h>
@@ -48,6 +50,7 @@ namespace fcl
 {
 
 /// @brief Node structure encoding the information required for traversal.
+
 class TraversalNodeBase
 {
 public:
@@ -88,6 +91,10 @@ public:
   Transform3f tf2;
 };
 
+/// @defgroup Traversal_For_Collision
+/// regroup class about traversal for distance.
+/// @{
+
 /// @brief Node structure encoding the information required for collision traversal.
 class CollisionTraversalNodeBase : public TraversalNodeBase
 {
@@ -98,16 +105,16 @@ public:
   virtual ~CollisionTraversalNodeBase();
 
   /// @brief BV test between b1 and b2
-  virtual bool BVTesting(int b1, int b2) const = 0;
+  virtual bool BVDisjoints(int b1, int b2) const = 0;
 
   /// BV test between b1 and b2
-  /// \param b1, b2 Bounding volumes to test,
-  /// \retval sqrDistLowerBound square of a lower bound of the minimal
+  /// @param b1, b2 Bounding volumes to test,
+  /// @retval sqrDistLowerBound square of a lower bound of the minimal
   ///         distance between bounding volumes.
-  virtual bool BVTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const = 0;
+  virtual bool BVDisjoints(int b1, int b2, FCL_REAL& sqrDistLowerBound) const = 0;
 
   /// @brief Leaf test between node b1 and b2, if they are both leafs
-  virtual void leafTesting(int /*b1*/, int /*b2*/, FCL_REAL& /*sqrDistLowerBound*/) const
+  virtual void leafCollides(int /*b1*/, int /*b2*/, FCL_REAL& /*sqrDistLowerBound*/) const
   {
     throw std::runtime_error ("Not implemented");
   }
@@ -128,6 +135,12 @@ public:
   bool enable_statistics;
 };
 
+/// @}
+
+/// @defgroup Traversal_For_Distance
+/// regroup class about traversal for distance.
+/// @{
+
 /// @brief Node structure encoding the information required for distance traversal.
 class DistanceTraversalNodeBase : public TraversalNodeBase
 {
@@ -137,12 +150,12 @@ public:
   virtual ~DistanceTraversalNodeBase();
 
   /// @brief BV test between b1 and b2
-  /// \return a lower bound of the distance between the two BV.
-  /// \note except for OBB, this method returns the distance.
-  virtual FCL_REAL BVTesting(int b1, int b2) const;
+  /// @return a lower bound of the distance between the two BV.
+  /// @note except for OBB, this method returns the distance.
+  virtual FCL_REAL BVDistanceLowerBound(int b1, int b2) const;
 
   /// @brief Leaf test between node b1 and b2, if they are both leafs
-  virtual void leafTesting(int b1, int b2) const = 0;
+  virtual void leafComputeDistance(int b1, int b2) const = 0;
 
   /// @brief Check whether the traversal can stop
   virtual bool canStop(FCL_REAL c) const;
@@ -159,8 +172,13 @@ public:
   /// @brief Whether stores statistics 
   bool enable_statistics;
 };
+
+///@}
+
 }
 
 } // namespace hpp
 
-#endif
+/// @endcond
+
+#endif
\ No newline at end of file
diff --git a/include/hpp/fcl/traversal/traversal_node_bvh_shape.h b/include/hpp/fcl/internal/traversal_node_bvh_shape.h
similarity index 83%
rename from include/hpp/fcl/traversal/traversal_node_bvh_shape.h
rename to include/hpp/fcl/internal/traversal_node_bvh_shape.h
index 27ec3f9afed15285cdb311fff127bab9028e824e..37162e5cadfe3837e7f8a2020580a2406b0b3beb 100644
--- a/include/hpp/fcl/traversal/traversal_node_bvh_shape.h
+++ b/include/hpp/fcl/internal/traversal_node_bvh_shape.h
@@ -39,11 +39,14 @@
 #ifndef HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H
 #define HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H
 
+/// @cond INTERNAL
+
 #include <hpp/fcl/collision_data.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
+#include <hpp/fcl/narrowphase/narrowphase.h>
 #include <hpp/fcl/shape/geometric_shapes_utility.h>
-#include <hpp/fcl/traversal/traversal_node_base.h>
-#include <hpp/fcl/traversal/details/traversal.h>
+#include <hpp/fcl/internal/traversal_node_base.h>
+#include <hpp/fcl/internal/traversal.h>
 #include <hpp/fcl/BVH/BVH_model.h>
 
 
@@ -52,6 +55,9 @@ namespace hpp
 namespace fcl
 {
 
+/// @addtogroup Traversal_For_Collision
+/// @{
+
 /// @brief Traversal node for collision between BVH and shape
 template<typename BV, typename S>
 class BVHShapeCollisionTraversalNode : public CollisionTraversalNodeBase
@@ -146,7 +152,7 @@ public:
 
 
 /// @brief Traversal node for collision between mesh and shape
-template<typename BV, typename S, typename NarrowPhaseSolver,
+template<typename BV, typename S,
   int _Options = RelativeTransformationIsIdentity>
 class MeshShapeCollisionTraversalNode : public BVHShapeCollisionTraversalNode<BV, S>
 {
@@ -166,7 +172,7 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  bool BVTesting(int b1, int /*b2*/) const
+  bool BVDisjoints(int b1, int /*b2*/) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     if (RTIsIdentity)
@@ -176,11 +182,11 @@ public:
   }
 
   /// test between BV b1 and shape
-  /// \param b1 BV to test,
-  /// \retval sqrDistLowerBound square of a lower bound of the minimal
+  /// @param b1 BV to test,
+  /// @retval sqrDistLowerBound square of a lower bound of the minimal
   ///         distance between bounding volumes.
   /// @brief BV culling test in one BVTT node
-  bool BVTesting(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const
+  bool BVDisjoints(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     bool res;
@@ -195,7 +201,7 @@ public:
   }
 
   /// @brief Intersection testing between leaves (one triangle and one shape)
-  void leafTesting(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const
+  void leafCollides(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const
   {
     if(this->enable_statistics) this->num_leaf_tests++;
     const BVNode<BV>& node = this->model1->getBV(b1);
@@ -256,50 +262,50 @@ public:
   Vec3f* vertices;
   Triangle* tri_indices;
 
-  const NarrowPhaseSolver* nsolver;
+  const GJKSolver* nsolver;
 };
 
 /// @brief Traversal node for mesh and shape, when mesh BVH is one of the oriented node (OBB, RSS, OBBRSS, kIOS)
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeCollisionTraversalNodeOBB : public MeshShapeCollisionTraversalNode<OBB, S, NarrowPhaseSolver, 0>
+template<typename S>
+class MeshShapeCollisionTraversalNodeOBB : public MeshShapeCollisionTraversalNode<OBB, S, 0>
 {
 public:
   MeshShapeCollisionTraversalNodeOBB(const CollisionRequest& request) :
-  MeshShapeCollisionTraversalNode<OBB, S, NarrowPhaseSolver, 0>
+  MeshShapeCollisionTraversalNode<OBB, S, 0>
     (request)
   {
   }
 
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeCollisionTraversalNodeRSS : public MeshShapeCollisionTraversalNode<RSS, S, NarrowPhaseSolver, 0>
+template<typename S>
+class MeshShapeCollisionTraversalNodeRSS : public MeshShapeCollisionTraversalNode<RSS, S, 0>
 {
 public:
   MeshShapeCollisionTraversalNodeRSS (const CollisionRequest& request):
-  MeshShapeCollisionTraversalNode<RSS, S, NarrowPhaseSolver, 0>
+  MeshShapeCollisionTraversalNode<RSS, S, 0>
     (request)
   {
   }
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeCollisionTraversalNodekIOS : public MeshShapeCollisionTraversalNode<kIOS, S, NarrowPhaseSolver, 0>
+template<typename S>
+class MeshShapeCollisionTraversalNodekIOS : public MeshShapeCollisionTraversalNode<kIOS, S, 0>
 {
 public:
   MeshShapeCollisionTraversalNodekIOS(const CollisionRequest& request):
-  MeshShapeCollisionTraversalNode<kIOS, S, NarrowPhaseSolver, 0>
+  MeshShapeCollisionTraversalNode<kIOS, S, 0>
     (request)
   {
   }
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeCollisionTraversalNodeOBBRSS : public MeshShapeCollisionTraversalNode<OBBRSS, S, NarrowPhaseSolver, 0>
+template<typename S>
+class MeshShapeCollisionTraversalNodeOBBRSS : public MeshShapeCollisionTraversalNode<OBBRSS, S, 0>
 {
 public:
   MeshShapeCollisionTraversalNodeOBBRSS (const CollisionRequest& request) :
-  MeshShapeCollisionTraversalNode <OBBRSS, S, NarrowPhaseSolver, 0>
+  MeshShapeCollisionTraversalNode <OBBRSS, S, 0>
     (request)
   {
   }
@@ -307,7 +313,7 @@ public:
 
 
 /// @brief Traversal node for collision between shape and mesh
-template<typename S, typename BV, typename NarrowPhaseSolver,
+template<typename S, typename BV,
   int _Options = RelativeTransformationIsIdentity>
 class ShapeMeshCollisionTraversalNode : public ShapeBVHCollisionTraversalNode<S, BV>
 {
@@ -326,8 +332,8 @@ public:
   }
 
   /// BV test between b1 and b2
-  /// \param b2 Bounding volumes to test,
-  bool BVTesting(int /*b1*/, int b2) const
+  /// @param b2 Bounding volumes to test,
+  bool BVDisjoints(int /*b1*/, int b2) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     if (RTIsIdentity)
@@ -337,10 +343,10 @@ public:
   }
 
   /// BV test between b1 and b2
-  /// \param b2 Bounding volumes to test,
-  /// \retval sqrDistLowerBound square of a lower bound of the minimal
+  /// @param b2 Bounding volumes to test,
+  /// @retval sqrDistLowerBound square of a lower bound of the minimal
   ///         distance between bounding volumes.
-  bool BVTesting(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const
+  bool BVDisjoints(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     bool res;
@@ -355,7 +361,7 @@ public:
   }
 
   /// @brief Intersection testing between leaves (one shape and one triangle)
-  void leafTesting(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const
+  void leafCollides(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const
   {
     if(this->enable_statistics) this->num_leaf_tests++;
     const BVNode<BV>& node = this->model2->getBV(b2);
@@ -416,49 +422,54 @@ public:
   Vec3f* vertices;
   Triangle* tri_indices;
 
-  const NarrowPhaseSolver* nsolver;
+  const GJKSolver* nsolver;
 };
 
 /// @brief Traversal node for shape and mesh, when mesh BVH is one of the oriented node (OBB, RSS, OBBRSS, kIOS)
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshCollisionTraversalNodeOBB : public ShapeMeshCollisionTraversalNode<S, OBB, NarrowPhaseSolver, 0>
+template<typename S>
+class ShapeMeshCollisionTraversalNodeOBB : public ShapeMeshCollisionTraversalNode<S, OBB, 0>
 {
 public:
-  ShapeMeshCollisionTraversalNodeOBB() : ShapeMeshCollisionTraversalNode<S, OBB, NarrowPhaseSolver>()
+  ShapeMeshCollisionTraversalNodeOBB() : ShapeMeshCollisionTraversalNode<S, OBB>()
   {
   }
 };
 
 
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshCollisionTraversalNodeRSS : public ShapeMeshCollisionTraversalNode<S, RSS, NarrowPhaseSolver, 0>
+template<typename S>
+class ShapeMeshCollisionTraversalNodeRSS : public ShapeMeshCollisionTraversalNode<S, RSS, 0>
 {
 public:
-  ShapeMeshCollisionTraversalNodeRSS() : ShapeMeshCollisionTraversalNode<S, RSS, NarrowPhaseSolver>()
+  ShapeMeshCollisionTraversalNodeRSS() : ShapeMeshCollisionTraversalNode<S, RSS>()
   {
   }
 };
 
 
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshCollisionTraversalNodekIOS : public ShapeMeshCollisionTraversalNode<S, kIOS, NarrowPhaseSolver, 0>
+template<typename S>
+class ShapeMeshCollisionTraversalNodekIOS : public ShapeMeshCollisionTraversalNode<S, kIOS, 0>
 {
 public:
-  ShapeMeshCollisionTraversalNodekIOS() : ShapeMeshCollisionTraversalNode<S, kIOS, NarrowPhaseSolver>()
+  ShapeMeshCollisionTraversalNodekIOS() : ShapeMeshCollisionTraversalNode<S, kIOS>()
   {
   }
 };
 
 
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshCollisionTraversalNodeOBBRSS : public ShapeMeshCollisionTraversalNode<S, OBBRSS, NarrowPhaseSolver, 0>
+template<typename S>
+class ShapeMeshCollisionTraversalNodeOBBRSS : public ShapeMeshCollisionTraversalNode<S, OBBRSS, 0>
 {
 public:
-  ShapeMeshCollisionTraversalNodeOBBRSS() : ShapeMeshCollisionTraversalNode<S, OBBRSS, NarrowPhaseSolver>()
+  ShapeMeshCollisionTraversalNodeOBBRSS() : ShapeMeshCollisionTraversalNode<S, OBBRSS>()
   {
   }
 };
 
+/// @}
+
+/// @addtogroup Traversal_For_Distance
+/// @{
+
 /// @brief Traversal node for distance computation between BVH and shape
 template<typename BV, typename S>
 class BVHShapeDistanceTraversalNode : public DistanceTraversalNodeBase
@@ -493,7 +504,7 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  FCL_REAL BVTesting(int b1, int /*b2*/) const
+  FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const
   {
     return model1->getBV(b1).bv.distance(model2_bv);
   }
@@ -541,7 +552,7 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  FCL_REAL BVTesting(int b1, int b2) const
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const
   {
     return model1_bv.distance(model2->getBV(b2).bv);
   }
@@ -557,7 +568,7 @@ public:
                                   
 
 /// @brief Traversal node for distance between mesh and shape
-template<typename BV, typename S, typename NarrowPhaseSolver>
+template<typename BV, typename S>
 class MeshShapeDistanceTraversalNode : public BVHShapeDistanceTraversalNode<BV, S>
 { 
 public:
@@ -573,7 +584,7 @@ public:
   }
 
   /// @brief Distance testing between leaves (one triangle and one shape)
-  void leafTesting(int b1, int /*b2*/) const
+  void leafComputeDistance(int b1, int /*b2*/) const
   {
     if(this->enable_statistics) this->num_leaf_tests++;
     
@@ -612,20 +623,20 @@ public:
   FCL_REAL rel_err;
   FCL_REAL abs_err;
     
-  const NarrowPhaseSolver* nsolver;
+  const GJKSolver* nsolver;
 };
 
 /// @cond IGNORE
 namespace details
 {
 
-template<typename BV, typename S, typename NarrowPhaseSolver>
-void meshShapeDistanceOrientedNodeLeafTesting(int b1, int /* b2 */,
+template<typename BV, typename S>
+void meshShapeDistanceOrientedNodeleafComputeDistance(int b1, int /* b2 */,
                                               const BVHModel<BV>* model1, const S& model2,
                                               Vec3f* vertices, Triangle* tri_indices,
                                               const Transform3f& tf1,
                                               const Transform3f& tf2,
-                                              const NarrowPhaseSolver* nsolver,
+                                              const GJKSolver* nsolver,
                                               bool enable_statistics,
                                               int & num_leaf_tests,
                                               const DistanceRequest& /* request */,
@@ -651,11 +662,11 @@ void meshShapeDistanceOrientedNodeLeafTesting(int b1, int /* b2 */,
 }
 
 
-template<typename BV, typename S, typename NarrowPhaseSolver>
+template<typename BV, typename S>
 static inline void distancePreprocessOrientedNode(const BVHModel<BV>* model1,
                                                   Vec3f* vertices, Triangle* tri_indices, int init_tri_id,
                                                   const S& model2, const Transform3f& tf1, const Transform3f& tf2,
-                                                  const NarrowPhaseSolver* nsolver,
+                                                  const GJKSolver* nsolver,
                                                   const DistanceRequest& /* request */,
                                                   DistanceResult& result)
 {
@@ -681,12 +692,12 @@ static inline void distancePreprocessOrientedNode(const BVHModel<BV>* model1,
 
 
 
-/// @brief Traversal node for distance between mesh and shape, when mesh BVH is one of the oriented node (RSS, OBBRSS, kIOS)
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeDistanceTraversalNodeRSS : public MeshShapeDistanceTraversalNode<RSS, S, NarrowPhaseSolver>
+/// @brief Traversal node for distance between mesh and shape, when mesh BVH is one of the oriented node (RSS, kIOS, OBBRSS)
+template<typename S>
+class MeshShapeDistanceTraversalNodeRSS : public MeshShapeDistanceTraversalNode<RSS, S>
 {
 public:
-  MeshShapeDistanceTraversalNodeRSS() : MeshShapeDistanceTraversalNode<RSS, S, NarrowPhaseSolver>()
+  MeshShapeDistanceTraversalNodeRSS() : MeshShapeDistanceTraversalNode<RSS, S>()
   {
   }
 
@@ -700,25 +711,25 @@ public:
   {
   }
 
-  FCL_REAL BVTesting(int b1, int /*b2*/) const
+  FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     return distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model2_bv, this->model1->getBV(b1).bv);
   }
 
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
-    details::meshShapeDistanceOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices,
+    details::meshShapeDistanceOrientedNodeleafComputeDistance(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices,
                                                       this->tf1, this->tf2, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result));
   }
 };
 
 
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeDistanceTraversalNodekIOS : public MeshShapeDistanceTraversalNode<kIOS, S, NarrowPhaseSolver>
+template<typename S>
+class MeshShapeDistanceTraversalNodekIOS : public MeshShapeDistanceTraversalNode<kIOS, S>
 {
 public:
-  MeshShapeDistanceTraversalNodekIOS() : MeshShapeDistanceTraversalNode<kIOS, S, NarrowPhaseSolver>()
+  MeshShapeDistanceTraversalNodekIOS() : MeshShapeDistanceTraversalNode<kIOS, S>()
   {
   }
 
@@ -732,25 +743,25 @@ public:
   {    
   }
 
-  FCL_REAL BVTesting(int b1, int /*b2*/) const
+  FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     return distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model2_bv, this->model1->getBV(b1).bv);
   }
 
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
-    details::meshShapeDistanceOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices,
+    details::meshShapeDistanceOrientedNodeleafComputeDistance(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices,
                                                       this->tf1, this->tf2, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result));
   }
 
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class MeshShapeDistanceTraversalNodeOBBRSS : public MeshShapeDistanceTraversalNode<OBBRSS, S, NarrowPhaseSolver>
+template<typename S>
+class MeshShapeDistanceTraversalNodeOBBRSS : public MeshShapeDistanceTraversalNode<OBBRSS, S>
 {
 public:
-  MeshShapeDistanceTraversalNodeOBBRSS() : MeshShapeDistanceTraversalNode<OBBRSS, S, NarrowPhaseSolver>()
+  MeshShapeDistanceTraversalNodeOBBRSS() : MeshShapeDistanceTraversalNode<OBBRSS, S>()
   {
   }
 
@@ -765,22 +776,22 @@ public:
     
   }
 
-  FCL_REAL BVTesting(int b1, int /*b2*/) const
+  FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     return distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model2_bv, this->model1->getBV(b1).bv);
   }
 
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
-    details::meshShapeDistanceOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices,
+    details::meshShapeDistanceOrientedNodeleafComputeDistance(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices,
                                                       this->tf1, this->tf2, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result));
   }
   
 };
 
 /// @brief Traversal node for distance between shape and mesh
-template<typename S, typename BV, typename NarrowPhaseSolver>
+template<typename S, typename BV>
 class ShapeMeshDistanceTraversalNode : public ShapeBVHDistanceTraversalNode<S, BV>
 { 
 public:
@@ -796,7 +807,7 @@ public:
   }
 
   /// @brief Distance testing between leaves (one shape and one triangle)
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
     if(this->enable_statistics) this->num_leaf_tests++;
     
@@ -835,14 +846,15 @@ public:
   FCL_REAL rel_err;
   FCL_REAL abs_err;
     
-  const NarrowPhaseSolver* nsolver;
+  const GJKSolver* nsolver;
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshDistanceTraversalNodeRSS : public ShapeMeshDistanceTraversalNode<S, RSS, NarrowPhaseSolver>
+/// @brief Traversal node for distance between shape and mesh, when mesh BVH is one of the oriented node (RSS, kIOS, OBBRSS)
+template<typename S>
+class ShapeMeshDistanceTraversalNodeRSS : public ShapeMeshDistanceTraversalNode<S, RSS>
 {
 public:
-  ShapeMeshDistanceTraversalNodeRSS() : ShapeMeshDistanceTraversalNode<S, RSS, NarrowPhaseSolver>()
+  ShapeMeshDistanceTraversalNodeRSS() : ShapeMeshDistanceTraversalNode<S, RSS>()
   {
   }
 
@@ -856,25 +868,25 @@ public:
   {
   }
 
-  FCL_REAL BVTesting(int b1, int b2) const
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     return distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model1_bv, this->model2->getBV(b2).bv);
   }
 
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
-    details::meshShapeDistanceOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices,
+    details::meshShapeDistanceOrientedNodeleafComputeDistance(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices,
                                                       this->tf2, this->tf1, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result));
   }
 
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshDistanceTraversalNodekIOS : public ShapeMeshDistanceTraversalNode<S, kIOS, NarrowPhaseSolver>
+template<typename S>
+class ShapeMeshDistanceTraversalNodekIOS : public ShapeMeshDistanceTraversalNode<S, kIOS>
 {
 public:
-  ShapeMeshDistanceTraversalNodekIOS() : ShapeMeshDistanceTraversalNode<S, kIOS, NarrowPhaseSolver>()
+  ShapeMeshDistanceTraversalNodekIOS() : ShapeMeshDistanceTraversalNode<S, kIOS>()
   {
   }
 
@@ -888,25 +900,25 @@ public:
   {
   }
 
-  FCL_REAL BVTesting(int b1, int b2) const
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     return distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model1_bv, this->model2->getBV(b2).bv);
   }
 
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
-    details::meshShapeDistanceOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices,
+    details::meshShapeDistanceOrientedNodeleafComputeDistance(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices,
                                                       this->tf2, this->tf1, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result));
   }
   
 };
 
-template<typename S, typename NarrowPhaseSolver>
-class ShapeMeshDistanceTraversalNodeOBBRSS : public ShapeMeshDistanceTraversalNode<S, OBBRSS, NarrowPhaseSolver>
+template<typename S>
+class ShapeMeshDistanceTraversalNodeOBBRSS : public ShapeMeshDistanceTraversalNode<S, OBBRSS>
 {
 public:
-  ShapeMeshDistanceTraversalNodeOBBRSS() : ShapeMeshDistanceTraversalNode<S, OBBRSS, NarrowPhaseSolver>()
+  ShapeMeshDistanceTraversalNodeOBBRSS() : ShapeMeshDistanceTraversalNode<S, OBBRSS>()
   {
   }
 
@@ -920,21 +932,26 @@ public:
   {    
   }
 
-  FCL_REAL BVTesting(int b1, int b2) const
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     return distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model1_bv, this->model2->getBV(b2).bv);
   }
 
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
-    details::meshShapeDistanceOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices,
+    details::meshShapeDistanceOrientedNodeleafComputeDistance(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices,
                                                       this->tf2, this->tf1, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result));
   }
   
 };
+
+/// @}
+
 }
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/traversal/traversal_node_bvhs.h b/include/hpp/fcl/internal/traversal_node_bvhs.h
similarity index 90%
rename from include/hpp/fcl/traversal/traversal_node_bvhs.h
rename to include/hpp/fcl/internal/traversal_node_bvhs.h
index 985aa90d3f7c9e84fcec17d0d121d4b657f6379b..ed251b832357a59cc260229c818f2130101286b7 100644
--- a/include/hpp/fcl/traversal/traversal_node_bvhs.h
+++ b/include/hpp/fcl/internal/traversal_node_bvhs.h
@@ -35,19 +35,20 @@
 
 /** \author Jia Pan */
 
-
 #ifndef HPP_FCL_TRAVERSAL_NODE_MESHES_H
 #define HPP_FCL_TRAVERSAL_NODE_MESHES_H
 
+/// @cond INTERNAL
+
 #include <hpp/fcl/collision_data.h>
-#include <hpp/fcl/traversal/traversal_node_base.h>
+#include <hpp/fcl/internal/traversal_node_base.h>
 #include <hpp/fcl/BV/BV_node.h>
 #include <hpp/fcl/BV/BV.h>
 #include <hpp/fcl/BVH/BVH_model.h>
-#include <hpp/fcl/intersect.h>
+#include <hpp/fcl/internal/intersect.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
 #include <hpp/fcl/narrowphase/narrowphase.h>
-#include <hpp/fcl/traversal/details/traversal.h>
+#include <hpp/fcl/internal/traversal.h>
 
 #include <boost/shared_array.hpp>
 #include <boost/shared_ptr.hpp>
@@ -55,11 +56,14 @@
 #include <vector>
 #include <cassert>
 
-
 namespace hpp
 {
 namespace fcl
 {
+
+/// @addtogroup Traversal_For_Collision
+/// @{
+
 /// @brief Traversal node for collision between BVH models
 template<typename BV>
 class BVHCollisionTraversalNode : public CollisionTraversalNodeBase
@@ -157,7 +161,7 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  bool BVTesting(int b1, int b2) const
+  bool BVDisjoints(int b1, int b2) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     if (RTIsIdentity)
@@ -168,10 +172,10 @@ public:
   }
   
   /// BV test between b1 and b2
-  /// \param b1, b2 Bounding volumes to test,
-  /// \retval sqrDistLowerBound square of a lower bound of the minimal
+  /// @param b1, b2 Bounding volumes to test,
+  /// @retval sqrDistLowerBound square of a lower bound of the minimal
   ///         distance between bounding volumes.
-  bool BVTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const
+  bool BVDisjoints(int b1, int b2, FCL_REAL& sqrDistLowerBound) const
   {
     if(this->enable_statistics) this->num_bv_tests++;
     if (RTIsIdentity)
@@ -188,8 +192,8 @@ public:
 
   /// Intersection testing between leaves (two triangles)
   ///
-  /// \param b1, b2 id of primitive in bounding volume hierarchy
-  /// \retval sqrDistLowerBound squared lower bound of distance between
+  /// @param b1, b2 id of primitive in bounding volume hierarchy
+  /// @retval sqrDistLowerBound squared lower bound of distance between
   ///         primitives if they are not in collision.
   ///
   /// This method supports a security margin. If the distance between
@@ -197,10 +201,10 @@ public:
   /// considered as in collision. in this case a contact point is
   /// returned in the CollisionResult.
   ///
-  /// \note If the distance between objects is less than the security margin,
+  /// @note If the distance between objects is less than the security margin,
   ///       and the object are not colliding, the penetration depth is
   ///       negative.
-  void leafTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const
+  void leafCollides(int b1, int b2, FCL_REAL& sqrDistLowerBound) const
   {
     if(this->enable_statistics) this->num_leaf_tests++;
 
@@ -222,7 +226,7 @@ public:
 
     TriangleP tri1 (P1, P2, P3);
     TriangleP tri2 (Q1, Q2, Q3);
-    GJKSolver_indep solver;
+    GJKSolver solver;
     Vec3f p1, p2; // closest points if no collision contact points if collision.
     Vec3f normal;
     FCL_REAL distance;
@@ -269,9 +273,11 @@ typedef MeshCollisionTraversalNode<RSS   , 0> MeshCollisionTraversalNodeRSS   ;
 typedef MeshCollisionTraversalNode<kIOS  , 0> MeshCollisionTraversalNodekIOS  ;
 typedef MeshCollisionTraversalNode<OBBRSS, 0> MeshCollisionTraversalNodeOBBRSS;
 
+/// @}
+
 namespace details
 {
-  template<typename BV> struct DistanceTraversalBVTesting_impl
+  template<typename BV> struct DistanceTraversalBVDistanceLowerBound_impl
   {
     static FCL_REAL run(const BVNode<BV>& b1, const BVNode<BV>& b2)
     {
@@ -279,7 +285,7 @@ namespace details
     }
   };
 
-  template<> struct DistanceTraversalBVTesting_impl<OBB>
+  template<> struct DistanceTraversalBVDistanceLowerBound_impl<OBB>
   {
     static FCL_REAL run(const BVNode<OBB>& b1, const BVNode<OBB>& b2)
     {
@@ -295,6 +301,9 @@ namespace details
   };
 } // namespace details
 
+/// @addtogroup Traversal_For_Distance
+/// @{
+
 /// @brief Traversal node for distance computation between BVH models
 template<typename BV>
 class BVHDistanceTraversalNode : public DistanceTraversalNodeBase
@@ -361,10 +370,10 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  FCL_REAL BVTesting(int b1, int b2) const
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const
   {
     if(enable_statistics) num_bv_tests++;
-    return details::DistanceTraversalBVTesting_impl<BV>
+    return details::DistanceTraversalBVDistanceLowerBound_impl<BV>
       ::run (model1->getBV(b1), model2->getBV(b2));
   }
 
@@ -397,7 +406,7 @@ public:
   }
 
   /// @brief Distance testing between leaves (two triangles)
-  void leafTesting(int b1, int b2) const
+  void leafComputeDistance(int b1, int b2) const
   {
     if(this->enable_statistics) this->num_leaf_tests++;
 
@@ -457,9 +466,9 @@ public:
 
   void postprocess();
 
-  FCL_REAL BVTesting(int b1, int b2) const;
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const;
 
-  void leafTesting(int b1, int b2) const;
+  void leafComputeDistance(int b1, int b2) const;
 
   Matrix3f R;
   Vec3f T;
@@ -475,9 +484,9 @@ public:
   
   void postprocess();
 
-  FCL_REAL BVTesting(int b1, int b2) const;
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const;
 
-  void leafTesting(int b1, int b2) const;
+  void leafComputeDistance(int b1, int b2) const;
 
   Matrix3f R;
   Vec3f T;
@@ -492,16 +501,18 @@ public:
 
   void postprocess();
 
-  FCL_REAL BVTesting(int b1, int b2) const;
+  FCL_REAL BVDistanceLowerBound(int b1, int b2) const;
 
-  FCL_REAL BVTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const;
+  FCL_REAL BVDistanceLowerBound(int b1, int b2, FCL_REAL& sqrDistLowerBound) const;
 
-  void leafTesting(int b1, int b2) const;
+  void leafComputeDistance(int b1, int b2) const;
 
   Matrix3f R;
   Vec3f T;
 };
 
+/// @}
+
 /// @brief for OBB and RSS, there is local coordinate of BV, so normal need to be transformed
 namespace details
 {
@@ -518,11 +529,12 @@ inline const Matrix3f& getBVAxes<OBBRSS>(const OBBRSS& bv)
   return bv.obb.axes;
 }
 
-
 }
 
 }
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/traversal/traversal_node_octree.h b/include/hpp/fcl/internal/traversal_node_octree.h
similarity index 93%
rename from include/hpp/fcl/traversal/traversal_node_octree.h
rename to include/hpp/fcl/internal/traversal_node_octree.h
index b9c47c07afb8f37ac7a8be75cb4a53e95e33a7e8..e2857da225d33f3a4c1e843d84914ac518a30539 100644
--- a/include/hpp/fcl/traversal/traversal_node_octree.h
+++ b/include/hpp/fcl/internal/traversal_node_octree.h
@@ -38,12 +38,14 @@
 #ifndef HPP_FCL_TRAVERSAL_NODE_OCTREE_H
 #define HPP_FCL_TRAVERSAL_NODE_OCTREE_H
 
+/// @cond INTERNAL
+
 #include <hpp/fcl/collision_data.h>
-#include <hpp/fcl/traversal/traversal_node_base.h>
+#include <hpp/fcl/internal/traversal_node_base.h>
 #include <hpp/fcl/narrowphase/narrowphase.h>
-#include <hpp/fcl/shape/geometric_shapes_utility.h>
 #include <hpp/fcl/octree.h>
 #include <hpp/fcl/BVH/BVH_model.h>
+#include <hpp/fcl/shape/geometric_shapes_utility.h>
 
 namespace hpp
 {
@@ -51,11 +53,10 @@ namespace fcl
 {
 
 /// @brief Algorithms for collision related with octree
-template<typename NarrowPhaseSolver>
 class OcTreeSolver
 {
 private:
-  const NarrowPhaseSolver* solver;
+  const GJKSolver* solver;
 
   mutable const CollisionRequest* crequest;
   mutable const DistanceRequest* drequest;
@@ -64,7 +65,7 @@ private:
   mutable DistanceResult* dresult;
 
 public:
-  OcTreeSolver(const NarrowPhaseSolver* solver_) : solver(solver_),
+  OcTreeSolver(const GJKSolver* solver_) : solver(solver_),
                                                    crequest(NULL),
                                                    drequest(NULL),
                                                    cresult(NULL),
@@ -886,11 +887,10 @@ private:
   }
 };
 
-
-
+/// @addtogroup Traversal_For_Collision
+/// @{
 
 /// @brief Traversal node for octree collision
-template<typename NarrowPhaseSolver>
 class OcTreeCollisionTraversalNode : public CollisionTraversalNodeBase
 {
 public:
@@ -903,17 +903,17 @@ public:
     otsolver = NULL;
   }
 
-  bool BVTesting(int, int) const
+  bool BVDisjoints(int, int) const
   {
     return false;
   }
 
-  bool BVTesting(int, int, FCL_REAL&) const
+  bool BVDisjoints(int, int, FCL_REAL&) const
   {
     return false;
   }
 
-  void leafTesting(int, int, FCL_REAL&) const
+  void leafCollides(int, int, FCL_REAL&) const
   {
     otsolver->OcTreeIntersect(model1, model2, tf1, tf2, request, *result);
   }
@@ -923,15 +923,16 @@ public:
 
   Transform3f tf1, tf2;
 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  const OcTreeSolver* otsolver;
 };
 
-/// @brief Traversal node for octree distance
-template<typename NarrowPhaseSolver>
-class OcTreeDistanceTraversalNode : public DistanceTraversalNodeBase
+/// @brief Traversal node for shape-octree collision
+template<typename S>
+class ShapeOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase
 {
 public:
-  OcTreeDistanceTraversalNode()
+ ShapeOcTreeCollisionTraversalNode(const CollisionRequest& request) :
+  CollisionTraversalNodeBase (request)
   {
     model1 = NULL;
     model2 = NULL;
@@ -939,34 +940,36 @@ public:
     otsolver = NULL;
   }
 
-
-  FCL_REAL BVTesting(int, int) const
+  bool BVDisjoints(int, int) const
   {
-    return -1;
+    return false;
   }
 
-  bool BVTesting(int, int, FCL_REAL&) const
+  bool BVDisjoints(int, int, FCL_REAL&) const
   {
     return false;
   }
 
-  void leafTesting(int, int) const
+  void leafCollides(int, int, FCL_REAL&) const
   {
-    otsolver->OcTreeDistance(model1, model2, tf1, tf2, request, *result);
+    otsolver->OcTreeShapeIntersect(model2, *model1, tf2, tf1, request, *result);
   }
 
-  const OcTree* model1;
+  const S* model1;
   const OcTree* model2;
 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  Transform3f tf1, tf2;
+
+  const OcTreeSolver* otsolver;
 };
 
-/// @brief Traversal node for shape-octree collision
-template<typename S, typename NarrowPhaseSolver>
-class ShapeOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase
+/// @brief Traversal node for octree-shape collision
+
+template<typename S>
+class OcTreeShapeCollisionTraversalNode : public CollisionTraversalNodeBase
 {
 public:
- ShapeOcTreeCollisionTraversalNode(const CollisionRequest& request) :
+ OcTreeShapeCollisionTraversalNode(const CollisionRequest& request) :
   CollisionTraversalNodeBase (request)
   {
     model1 = NULL;
@@ -975,35 +978,35 @@ public:
     otsolver = NULL;
   }
 
-  bool BVTesting(int, int) const
+  bool BVDisjoints(int, int) const
   {
     return false;
   }
 
-  bool BVTesting(int, int, FCL_REAL&) const
+  bool BVDisjoints(int, int, fcl::FCL_REAL&) const
   {
     return false;
   }
 
-  void leafTesting(int, int, FCL_REAL&) const
+  void leafCollides(int, int, FCL_REAL&) const
   {
-    otsolver->OcTreeShapeIntersect(model2, *model1, tf2, tf1, request, *result);
+    otsolver->OcTreeShapeIntersect(model1, *model2, tf1, tf2, request, *result);
   }
 
-  const S* model1;
-  const OcTree* model2;
+  const OcTree* model1;
+  const S* model2;
 
   Transform3f tf1, tf2;
-
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+ 
+  const OcTreeSolver* otsolver;  
 };
 
-/// @brief Traversal node for octree-shape collision
-template<typename S, typename NarrowPhaseSolver>
-class OcTreeShapeCollisionTraversalNode : public CollisionTraversalNodeBase
+/// @brief Traversal node for mesh-octree collision
+template<typename BV>
+class MeshOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase
 {
 public:
- OcTreeShapeCollisionTraversalNode(const CollisionRequest& request) :
+ MeshOcTreeCollisionTraversalNode(const CollisionRequest& request) :
   CollisionTraversalNodeBase (request)
   {
     model1 = NULL;
@@ -1012,163 +1015,167 @@ public:
     otsolver = NULL;
   }
 
-  bool BVTesting(int, int) const
+  bool BVDisjoints(int, int) const
   {
     return false;
   }
 
-  bool BVTesting(int, int, fcl::FCL_REAL&) const
+  bool BVDisjoints(int, int, FCL_REAL&) const
   {
     return false;
   }
 
-  void leafTesting(int, int, FCL_REAL&) const
+  void leafCollides(int, int, FCL_REAL&) const
   {
-    otsolver->OcTreeShapeIntersect(model1, *model2, tf1, tf2, request, *result);
+    otsolver->OcTreeMeshIntersect(model2, model1, tf2, tf1, request, *result);
   }
 
-  const OcTree* model1;
-  const S* model2;
+  const BVHModel<BV>* model1;
+  const OcTree* model2;
 
   Transform3f tf1, tf2;
- 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;  
+    
+  const OcTreeSolver* otsolver;
 };
 
-/// @brief Traversal node for shape-octree distance
-template<typename S, typename NarrowPhaseSolver>
-class ShapeOcTreeDistanceTraversalNode : public DistanceTraversalNodeBase
+/// @brief Traversal node for octree-mesh collision
+template<typename BV>
+class OcTreeMeshCollisionTraversalNode : public CollisionTraversalNodeBase
 {
 public:
-  ShapeOcTreeDistanceTraversalNode()
+ OcTreeMeshCollisionTraversalNode(const CollisionRequest& request) :
+  CollisionTraversalNodeBase (request)
   {
     model1 = NULL;
     model2 = NULL;
-    
+
     otsolver = NULL;
   }
 
-  FCL_REAL BVTesting(int, int) const
+  bool BVDisjoints(int, int) const
   {
-    return -1;
+    return false;
   }
 
-  void leafTesting(int, int) const
+  bool BVDisjoints(int, int, FCL_REAL&) const
   {
-    otsolver->OcTreeShapeDistance(model2, *model1, tf2, tf1, request, *result);
+    return false;
   }
 
-  const S* model1;
-  const OcTree* model2;
+  void leafCollides(int, int, FCL_REAL&) const
+  {
+    otsolver->OcTreeMeshIntersect(model1, model2, tf1, tf2, request, *result);
+  }
+
+  const OcTree* model1;
+  const BVHModel<BV>* model2;
 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  Transform3f tf1, tf2;
+    
+  const OcTreeSolver* otsolver;
 };
 
-/// @brief Traversal node for octree-shape distance
-template<typename S, typename NarrowPhaseSolver>
-class OcTreeShapeDistanceTraversalNode : public DistanceTraversalNodeBase
+/// @}
+
+/// @addtogroup Traversal_For_Distance
+/// @{
+
+/// @brief Traversal node for octree distance
+class OcTreeDistanceTraversalNode : public DistanceTraversalNodeBase
 {
 public:
-  OcTreeShapeDistanceTraversalNode()
+  OcTreeDistanceTraversalNode()
   {
     model1 = NULL;
     model2 = NULL;
-    
+
     otsolver = NULL;
   }
 
-  FCL_REAL BVTesting(int, int) const
+
+  FCL_REAL BVDistanceLowerBound(int, int) const
   {
     return -1;
   }
 
-  void leafTesting(int, int) const
+  bool BVDistanceLowerBound(int, int, FCL_REAL&) const
   {
-    otsolver->OcTreeShapeDistance(model1, *model2, tf1, tf2, request, *result);
+    return false;
+  }
+
+  void leafComputeDistance(int, int) const
+  {
+    otsolver->OcTreeDistance(model1, model2, tf1, tf2, request, *result);
   }
 
   const OcTree* model1;
-  const S* model2;
+  const OcTree* model2;
 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  const OcTreeSolver* otsolver;
 };
 
-/// @brief Traversal node for mesh-octree collision
-template<typename BV, typename NarrowPhaseSolver>
-class MeshOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase
+
+
+/// @brief Traversal node for shape-octree distance
+template<typename S>
+class ShapeOcTreeDistanceTraversalNode : public DistanceTraversalNodeBase
 {
 public:
- MeshOcTreeCollisionTraversalNode(const CollisionRequest& request) :
-  CollisionTraversalNodeBase (request)
+  ShapeOcTreeDistanceTraversalNode()
   {
     model1 = NULL;
     model2 = NULL;
-
+    
     otsolver = NULL;
   }
 
-  bool BVTesting(int, int) const
+  FCL_REAL BVDistanceLowerBound(int, int) const
   {
-    return false;
-  }
-
-  bool BVTesting(int, int, FCL_REAL&) const
-  {
-    return false;
+    return -1;
   }
 
-  void leafTesting(int, int, FCL_REAL&) const
+  void leafComputeDistance(int, int) const
   {
-    otsolver->OcTreeMeshIntersect(model2, model1, tf2, tf1, request, *result);
+    otsolver->OcTreeShapeDistance(model2, *model1, tf2, tf1, request, *result);
   }
 
-  const BVHModel<BV>* model1;
+  const S* model1;
   const OcTree* model2;
 
-  Transform3f tf1, tf2;
-    
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  const OcTreeSolver* otsolver;
 };
 
-/// @brief Traversal node for octree-mesh collision
-template<typename BV, typename NarrowPhaseSolver>
-class OcTreeMeshCollisionTraversalNode : public CollisionTraversalNodeBase
+/// @brief Traversal node for octree-shape distance
+template<typename S>
+class OcTreeShapeDistanceTraversalNode : public DistanceTraversalNodeBase
 {
 public:
- OcTreeMeshCollisionTraversalNode(const CollisionRequest& request) :
-  CollisionTraversalNodeBase (request)
+  OcTreeShapeDistanceTraversalNode()
   {
     model1 = NULL;
     model2 = NULL;
-
+    
     otsolver = NULL;
   }
 
-  bool BVTesting(int, int) const
+  FCL_REAL BVDistanceLowerBound(int, int) const
   {
-    return false;
-  }
-
-  bool BVTesting(int, int, FCL_REAL&) const
-  {
-    return false;
+    return -1;
   }
 
-  void leafTesting(int, int, FCL_REAL&) const
+  void leafComputeDistance(int, int) const
   {
-    otsolver->OcTreeMeshIntersect(model1, model2, tf1, tf2, request, *result);
+    otsolver->OcTreeShapeDistance(model1, *model2, tf1, tf2, request, *result);
   }
 
   const OcTree* model1;
-  const BVHModel<BV>* model2;
+  const S* model2;
 
-  Transform3f tf1, tf2;
-    
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  const OcTreeSolver* otsolver;
 };
 
 /// @brief Traversal node for mesh-octree distance
-template<typename BV, typename NarrowPhaseSolver>
+template<typename BV>
 class MeshOcTreeDistanceTraversalNode : public DistanceTraversalNodeBase
 {
 public:
@@ -1180,12 +1187,12 @@ public:
     otsolver = NULL;
   }
 
-  FCL_REAL BVTesting(int, int) const
+  FCL_REAL BVDistanceLowerBound(int, int) const
   {
     return -1;
   }
 
-  void leafTesting(int, int) const
+  void leafComputeDistance(int, int) const
   {
     otsolver->OcTreeMeshDistance(model2, model1, tf2, tf1, request, *result);
   }
@@ -1193,12 +1200,12 @@ public:
   const BVHModel<BV>* model1;
   const OcTree* model2;
 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  const OcTreeSolver* otsolver;
 
 };
 
 /// @brief Traversal node for octree-mesh distance
-template<typename BV, typename NarrowPhaseSolver>
+template<typename BV>
 class OcTreeMeshDistanceTraversalNode : public DistanceTraversalNodeBase
 {
 public:
@@ -1210,12 +1217,12 @@ public:
     otsolver = NULL;
   }
 
-  FCL_REAL BVTesting(int, int) const
+  FCL_REAL BVDistanceLowerBound(int, int) const
   {
     return -1;
   }
 
-  void leafTesting(int, int) const
+  void leafComputeDistance(int, int) const
   {
     otsolver->OcTreeMeshDistance(model1, model2, tf1, tf2, request, *result);
   }
@@ -1223,14 +1230,16 @@ public:
   const OcTree* model1;
   const BVHModel<BV>* model2;
 
-  const OcTreeSolver<NarrowPhaseSolver>* otsolver;
+  const OcTreeSolver* otsolver;
 
 };
 
-
+/// @}
 
 }
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/traversal/traversal_node_setup.h b/include/hpp/fcl/internal/traversal_node_setup.h
similarity index 67%
rename from include/hpp/fcl/traversal/traversal_node_setup.h
rename to include/hpp/fcl/internal/traversal_node_setup.h
index 041b3fa68731525070797d48661ee7cde48d35b5..7a5006d134177e29c8c9b762615d2285eff97186 100644
--- a/include/hpp/fcl/traversal/traversal_node_setup.h
+++ b/include/hpp/fcl/internal/traversal_node_setup.h
@@ -35,16 +35,17 @@
 
 /** \author Jia Pan */
 
-
 #ifndef HPP_FCL_TRAVERSAL_NODE_SETUP_H
 #define HPP_FCL_TRAVERSAL_NODE_SETUP_H
 
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
-#include <hpp/fcl/traversal/traversal_node_shapes.h>
-#include <hpp/fcl/traversal/traversal_node_bvh_shape.h>
+/// @cond INTERNAL
+
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
+#include <hpp/fcl/internal/traversal_node_shapes.h>
+#include <hpp/fcl/internal/traversal_node_bvh_shape.h>
 
 #ifdef HPP_FCL_HAVE_OCTOMAP
-#include <hpp/fcl/traversal/traversal_node_octree.h>
+#include <hpp/fcl/internal/traversal_node_octree.h>
 #endif
 
 #include <hpp/fcl/BVH/BVH_utility.h>
@@ -56,12 +57,11 @@ namespace fcl
 
 #ifdef HPP_FCL_HAVE_OCTOMAP
 /// @brief Initialize traversal node for collision between two octrees, given current object transform
-template<typename NarrowPhaseSolver>
-bool initialize(OcTreeCollisionTraversalNode<NarrowPhaseSolver>& node,
-                const OcTree& model1, const Transform3f& tf1,
-                const OcTree& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
-                CollisionResult& result)
+inline bool initialize(OcTreeCollisionTraversalNode& node,
+                       const OcTree& model1, const Transform3f& tf1,
+                       const OcTree& model2, const Transform3f& tf2,
+                       const OcTreeSolver* otsolver,
+                       CollisionResult& result)
 {
   node.result = &result;
 
@@ -77,13 +77,13 @@ bool initialize(OcTreeCollisionTraversalNode<NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance between two octrees, given current object transform
-template<typename NarrowPhaseSolver>
-bool initialize(OcTreeDistanceTraversalNode<NarrowPhaseSolver>& node,
-                const OcTree& model1, const Transform3f& tf1,
-                const OcTree& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
-                const DistanceRequest& request,
-                DistanceResult& result)
+inline bool initialize(OcTreeDistanceTraversalNode& node,
+                       const OcTree& model1, const Transform3f& tf1,
+                       const OcTree& model2, const Transform3f& tf2,
+                       const OcTreeSolver* otsolver,
+                       const DistanceRequest& request,
+                       DistanceResult& result)
+
 {
   node.request = request;
   node.result = &result;
@@ -100,11 +100,11 @@ bool initialize(OcTreeDistanceTraversalNode<NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for collision between one shape and one octree, given current object transform
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeOcTreeCollisionTraversalNode<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(ShapeOcTreeCollisionTraversalNode<S>& node,
                 const S& model1, const Transform3f& tf1,
                 const OcTree& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 CollisionResult& result)
 {
   node.result = &result;
@@ -121,11 +121,11 @@ bool initialize(ShapeOcTreeCollisionTraversalNode<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for collision between one octree and one shape, given current object transform
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(OcTreeShapeCollisionTraversalNode<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(OcTreeShapeCollisionTraversalNode<S>& node,
                 const OcTree& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 CollisionResult& result)
 {
   node.result = &result;
@@ -142,11 +142,11 @@ bool initialize(OcTreeShapeCollisionTraversalNode<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance between one shape and one octree, given current object transform
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeOcTreeDistanceTraversalNode<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(ShapeOcTreeDistanceTraversalNode<S>& node,
                 const S& model1, const Transform3f& tf1,
                 const OcTree& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -165,11 +165,11 @@ bool initialize(ShapeOcTreeDistanceTraversalNode<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance between one octree and one shape, given current object transform
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(OcTreeShapeDistanceTraversalNode<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(OcTreeShapeDistanceTraversalNode<S>& node,
                 const OcTree& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -188,11 +188,11 @@ bool initialize(OcTreeShapeDistanceTraversalNode<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for collision between one mesh and one octree, given current object transform
-template<typename BV, typename NarrowPhaseSolver>
-bool initialize(MeshOcTreeCollisionTraversalNode<BV, NarrowPhaseSolver>& node,
+template<typename BV>
+bool initialize(MeshOcTreeCollisionTraversalNode<BV>& node,
                 const BVHModel<BV>& model1, const Transform3f& tf1,
                 const OcTree& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 CollisionResult& result)
 {
   node.result = &result;
@@ -209,11 +209,11 @@ bool initialize(MeshOcTreeCollisionTraversalNode<BV, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for collision between one octree and one mesh, given current object transform
-template<typename BV, typename NarrowPhaseSolver>
-bool initialize(OcTreeMeshCollisionTraversalNode<BV, NarrowPhaseSolver>& node,
+template<typename BV>
+bool initialize(OcTreeMeshCollisionTraversalNode<BV>& node,
                 const OcTree& model1, const Transform3f& tf1,
                 const BVHModel<BV>& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 CollisionResult& result)
 {
   node.result = &result;
@@ -230,11 +230,11 @@ bool initialize(OcTreeMeshCollisionTraversalNode<BV, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance between one mesh and one octree, given current object transform
-template<typename BV, typename NarrowPhaseSolver>
-bool initialize(MeshOcTreeDistanceTraversalNode<BV, NarrowPhaseSolver>& node,
+template<typename BV>
+bool initialize(MeshOcTreeDistanceTraversalNode<BV>& node,
                 const BVHModel<BV>& model1, const Transform3f& tf1,
                 const OcTree& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -253,11 +253,11 @@ bool initialize(MeshOcTreeDistanceTraversalNode<BV, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for collision between one octree and one mesh, given current object transform
-template<typename BV, typename NarrowPhaseSolver>
-bool initialize(OcTreeMeshDistanceTraversalNode<BV, NarrowPhaseSolver>& node,
+template<typename BV>
+bool initialize(OcTreeMeshDistanceTraversalNode<BV>& node,
                 const OcTree& model1, const Transform3f& tf1,
                 const BVHModel<BV>& model2, const Transform3f& tf2,
-                const OcTreeSolver<NarrowPhaseSolver>* otsolver,
+                const OcTreeSolver* otsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -279,11 +279,11 @@ bool initialize(OcTreeMeshDistanceTraversalNode<BV, NarrowPhaseSolver>& node,
 
 
 /// @brief Initialize traversal node for collision between two geometric shapes, given current object transform
-template<typename S1, typename S2, typename NarrowPhaseSolver>
-bool initialize(ShapeCollisionTraversalNode<S1, S2, NarrowPhaseSolver>& node,
+template<typename S1, typename S2>
+bool initialize(ShapeCollisionTraversalNode<S1, S2>& node,
                 const S1& shape1, const Transform3f& tf1,
                 const S2& shape2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 CollisionResult& result)
 {
   node.model1 = &shape1;
@@ -298,11 +298,11 @@ bool initialize(ShapeCollisionTraversalNode<S1, S2, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for collision between one mesh and one shape, given current object transform
-template<typename BV, typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeCollisionTraversalNode<BV, S, NarrowPhaseSolver>& node,
+template<typename BV, typename S>
+bool initialize(MeshShapeCollisionTraversalNode<BV, S>& node,
                 BVHModel<BV>& model1, Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 CollisionResult& result,
                 bool use_refit = false, bool refit_bottomup = false)
 {
@@ -342,61 +342,15 @@ bool initialize(MeshShapeCollisionTraversalNode<BV, S, NarrowPhaseSolver>& node,
   return true;
 }
 
-
-/// @brief Initialize traversal node for collision between one mesh and one shape, given current object transform
-template<typename S, typename BV, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshCollisionTraversalNode<S, BV, NarrowPhaseSolver>& node,
-                const S& model1, const Transform3f& tf1,
-                BVHModel<BV>& model2, Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
-                CollisionResult& result,
-                bool use_refit = false, bool refit_bottomup = false)
-{
-  if(model2.getModelType() != BVH_MODEL_TRIANGLES)
-    return false;
-
-  if(!tf2.isIdentity())
-  {
-    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);
-
-    tf2.setIdentity();
-  }
-
-  node.model1 = &model1;
-  node.tf1 = tf1;
-  node.model2 = &model2;
-  node.tf2 = tf2;
-  node.nsolver = nsolver;
-
-  computeBV(model1, tf1, node.model1_bv);
-
-  node.vertices = model2.vertices;
-  node.tri_indices = model2.tri_indices;
-
-  node.result = &result;
-
-  return true;
-}
-
 /// @cond IGNORE
 namespace details
 {
 
-template<typename BV, typename S, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode>
-static inline bool setupMeshShapeCollisionOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, 
+template<typename BV, typename S, template<typename> class OrientedNode>
+static inline bool setupMeshShapeCollisionOrientedNode(OrientedNode<S>& node, 
                                                        const BVHModel<BV>& model1, const Transform3f& tf1,
                                                        const S& model2, const Transform3f& tf2,
-                                                       const NarrowPhaseSolver* nsolver,
+                                                       const GJKSolver* nsolver,
                                                        CollisionResult& result)
 {
   if(model1.getModelType() != BVH_MODEL_TRIANGLES)
@@ -424,44 +378,44 @@ static inline bool setupMeshShapeCollisionOrientedNode(OrientedNode<S, NarrowPha
 
 
 /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBB type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeCollisionTraversalNodeOBB<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeCollisionTraversalNodeOBB<S>& node,
                 const BVHModel<OBB>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 CollisionResult& result)
 {
   return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
 }
 
 /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for RSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeCollisionTraversalNodeRSS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeCollisionTraversalNodeRSS<S>& node,
                 const BVHModel<RSS>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 CollisionResult& result)
 {
   return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
 }
 
 /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for kIOS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeCollisionTraversalNodekIOS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeCollisionTraversalNodekIOS<S>& node,
                 const BVHModel<kIOS>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 CollisionResult& result)
 {
   return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
 }
 
 /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBBRSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeCollisionTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeCollisionTraversalNodeOBBRSS<S>& node,
                 const BVHModel<OBBRSS>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 CollisionResult& result)
 {
   return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
@@ -471,11 +425,11 @@ bool initialize(MeshShapeCollisionTraversalNodeOBBRSS<S, NarrowPhaseSolver>& nod
 /// @cond IGNORE
 namespace details
 {
-template<typename S, typename BV, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode>
-static inline bool setupShapeMeshCollisionOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, 
+template<typename S, typename BV, template<typename> class OrientedNode>
+static inline bool setupShapeMeshCollisionOrientedNode(OrientedNode<S>& node, 
                                                        const S& model1, const Transform3f& tf1,
                                                        const BVHModel<BV>& model2, const Transform3f& tf2,
-                                                       const NarrowPhaseSolver* nsolver,
+                                                       const GJKSolver* nsolver,
                                                        CollisionResult& result)
 {
   if(model2.getModelType() != BVH_MODEL_TRIANGLES)
@@ -499,56 +453,10 @@ static inline bool setupShapeMeshCollisionOrientedNode(OrientedNode<S, NarrowPha
 }
 /// @endcond
 
-/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBB type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshCollisionTraversalNodeOBB<S, NarrowPhaseSolver>& node,
-                const S& model1, const Transform3f& tf1,
-                const BVHModel<OBB>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
-                CollisionResult& result)
-{
-  return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
-}
-
-/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for RSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshCollisionTraversalNodeRSS<S, NarrowPhaseSolver>& node,
-                const S& model1, const Transform3f& tf1,
-                const BVHModel<RSS>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
-                CollisionResult& result)
-{
-  return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
-}
-
-/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for kIOS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshCollisionTraversalNodekIOS<S, NarrowPhaseSolver>& node,
-                const S& model1, const Transform3f& tf1,
-                const BVHModel<kIOS>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
-                CollisionResult& result)
-{
-  return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
-}
-
-/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBBRSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshCollisionTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node,
-                const S& model1, const Transform3f& tf1,
-                const BVHModel<OBBRSS>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
-                CollisionResult& result)
-{
-  return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result);
-}
-
-
-
 
 /// @brief Initialize traversal node for collision between two meshes, given the current transforms
 template<typename BV>
-bool initialize(MeshCollisionTraversalNode<BV>& node,
+bool initialize(MeshCollisionTraversalNode<BV, RelativeTransformationIsIdentity>& node,
                 BVHModel<BV>& model1, Transform3f& tf1,
                 BVHModel<BV>& model2, Transform3f& tf2,
                 CollisionResult& result,
@@ -607,38 +515,40 @@ bool initialize(MeshCollisionTraversalNode<BV>& node,
   return true;
 }
 
+template<typename BV>
+bool initialize(MeshCollisionTraversalNode<BV, 0>& node,
+                const BVHModel<BV>& model1, const Transform3f& tf1,
+                const BVHModel<BV>& model2, const Transform3f& tf2,
+                CollisionResult& result)
+{
+  if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
+    return false;
 
-/// @brief Initialize traversal node for collision between two meshes, specialized for OBB type
-bool initialize(MeshCollisionTraversalNodeOBB& node,
-                const BVHModel<OBB>& model1, const Transform3f& tf1,
-                const BVHModel<OBB>& model2, const Transform3f& tf2,
-                CollisionResult& result);
+  node.vertices1 = model1.vertices;
+  node.vertices2 = model2.vertices;
 
-/// @brief Initialize traversal node for collision between two meshes, specialized for RSS type
-bool initialize(MeshCollisionTraversalNodeRSS& node,
-                const BVHModel<RSS>& model1, const Transform3f& tf1,
-                const BVHModel<RSS>& model2, const Transform3f& tf2,
-                CollisionResult& result);
+  node.tri_indices1 = model1.tri_indices;
+  node.tri_indices2 = model2.tri_indices;
 
-/// @brief Initialize traversal node for collision between two meshes, specialized for OBBRSS type
-bool initialize(MeshCollisionTraversalNodeOBBRSS& node,
-                const BVHModel<OBBRSS>& model1, const Transform3f& tf1,
-                const BVHModel<OBBRSS>& model2, const Transform3f& tf2,
-                CollisionResult& result);
+  node.model1 = &model1;
+  node.tf1 = tf1;
+  node.model2 = &model2;
+  node.tf2 = tf2;
 
-/// @brief Initialize traversal node for collision between two meshes, specialized for kIOS type
-bool initialize(MeshCollisionTraversalNodekIOS& node,
-                const BVHModel<kIOS>& model1, const Transform3f& tf1,
-                const BVHModel<kIOS>& model2, const Transform3f& tf2,
-                CollisionResult& result);
+  node.result = &result;
 
+  node.RT.R = tf1.getRotation().transpose() * tf2.getRotation();
+  node.RT.T = tf1.getRotation().transpose() * (tf2.getTranslation() - tf1.getTranslation());
+
+  return true;
+}
 
 /// @brief Initialize traversal node for distance between two geometric shapes
-template<typename S1, typename S2, typename NarrowPhaseSolver>
-bool initialize(ShapeDistanceTraversalNode<S1, S2, NarrowPhaseSolver>& node,
+template<typename S1, typename S2>
+bool initialize(ShapeDistanceTraversalNode<S1, S2>& node,
                 const S1& shape1, const Transform3f& tf1,
                 const S2& shape2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -740,11 +650,11 @@ bool initialize(MeshDistanceTraversalNodeOBBRSS& node,
                 DistanceResult& result);
 
 /// @brief Initialize traversal node for distance computation between one mesh and one shape, given the current transforms
-template<typename BV, typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeDistanceTraversalNode<BV, S, NarrowPhaseSolver>& node,
+template<typename BV, typename S>
+bool initialize(MeshShapeDistanceTraversalNode<BV, S>& node,
                 BVHModel<BV>& model1, Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result,
                 bool use_refit = false, bool refit_bottomup = false)
@@ -787,11 +697,11 @@ bool initialize(MeshShapeDistanceTraversalNode<BV, S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance computation between one shape and one mesh, given the current transforms
-template<typename S, typename BV, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshDistanceTraversalNode<S, BV, NarrowPhaseSolver>& node,
+template<typename S, typename BV>
+bool initialize(ShapeMeshDistanceTraversalNode<S, BV>& node,
                 const S& model1, const Transform3f& tf1,
                 BVHModel<BV>& model2, Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result,
                 bool use_refit = false, bool refit_bottomup = false)
@@ -837,11 +747,11 @@ bool initialize(ShapeMeshDistanceTraversalNode<S, BV, NarrowPhaseSolver>& node,
 namespace details
 {
 
-template<typename BV, typename S, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode>
-static inline bool setupMeshShapeDistanceOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, 
+template<typename BV, typename S, template<typename> class OrientedNode>
+static inline bool setupMeshShapeDistanceOrientedNode(OrientedNode<S>& node, 
                                                       const BVHModel<BV>& model1, const Transform3f& tf1,
                                                       const S& model2, const Transform3f& tf2,
-                                                      const NarrowPhaseSolver* nsolver,
+                                                      const GJKSolver* nsolver,
                                                       const DistanceRequest& request,
                                                       DistanceResult& result)
 {
@@ -868,11 +778,11 @@ static inline bool setupMeshShapeDistanceOrientedNode(OrientedNode<S, NarrowPhas
 /// @endcond
 
 /// @brief Initialize traversal node for distance computation between one mesh and one shape, specialized for RSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeDistanceTraversalNodeRSS<S>& node,
                 const BVHModel<RSS>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request, 
                 DistanceResult& result)
 {
@@ -880,11 +790,11 @@ bool initialize(MeshShapeDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance computation between one mesh and one shape, specialized for kIOS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeDistanceTraversalNodekIOS<S>& node,
                 const BVHModel<kIOS>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -892,11 +802,11 @@ bool initialize(MeshShapeDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance computation between one mesh and one shape, specialized for OBBRSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(MeshShapeDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(MeshShapeDistanceTraversalNodeOBBRSS<S>& node,
                 const BVHModel<OBBRSS>& model1, const Transform3f& tf1,
                 const S& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -906,11 +816,11 @@ bool initialize(MeshShapeDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node
 
 namespace details
 {
-template<typename S, typename BV, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode>
-static inline bool setupShapeMeshDistanceOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node,
+template<typename S, typename BV, template<typename> class OrientedNode>
+static inline bool setupShapeMeshDistanceOrientedNode(OrientedNode<S>& node,
                                                       const S& model1, const Transform3f& tf1,
                                                       const BVHModel<BV>& model2, const Transform3f& tf2,
-                                                      const NarrowPhaseSolver* nsolver,
+                                                      const GJKSolver* nsolver,
                                                       const DistanceRequest& request,
                                                       DistanceResult& result)
 {
@@ -939,11 +849,11 @@ static inline bool setupShapeMeshDistanceOrientedNode(OrientedNode<S, NarrowPhas
 
 
 /// @brief Initialize traversal node for distance computation between one shape and one mesh, specialized for RSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(ShapeMeshDistanceTraversalNodeRSS<S>& node,
                 const S& model1, const Transform3f& tf1,
                 const BVHModel<RSS>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -951,11 +861,11 @@ bool initialize(ShapeMeshDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance computation between one shape and one mesh, specialized for kIOS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(ShapeMeshDistanceTraversalNodekIOS<S>& node,
                 const S& model1, const Transform3f& tf1,
                 const BVHModel<kIOS>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -963,11 +873,11 @@ bool initialize(ShapeMeshDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node,
 }
 
 /// @brief Initialize traversal node for distance computation between one shape and one mesh, specialized for OBBRSS type
-template<typename S, typename NarrowPhaseSolver>
-bool initialize(ShapeMeshDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node,
+template<typename S>
+bool initialize(ShapeMeshDistanceTraversalNodeOBBRSS<S>& node,
                 const S& model1, const Transform3f& tf1,
                 const BVHModel<OBBRSS>& model2, const Transform3f& tf2,
-                const NarrowPhaseSolver* nsolver,
+                const GJKSolver* nsolver,
                 const DistanceRequest& request,
                 DistanceResult& result)
 {
@@ -978,4 +888,6 @@ bool initialize(ShapeMeshDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/traversal/traversal_node_shapes.h b/include/hpp/fcl/internal/traversal_node_shapes.h
similarity index 89%
rename from include/hpp/fcl/traversal/traversal_node_shapes.h
rename to include/hpp/fcl/internal/traversal_node_shapes.h
index 5180e9dcb43fe097e3be7730be259ee6e2feea8a..eff6de320de79356b5ffd09954a8525741f6e5a0 100644
--- a/include/hpp/fcl/traversal/traversal_node_shapes.h
+++ b/include/hpp/fcl/internal/traversal_node_shapes.h
@@ -35,25 +35,27 @@
 
 /** \author Jia Pan */
 
-
 #ifndef HPP_FCL_TRAVERSAL_NODE_SHAPES_H
 #define HPP_FCL_TRAVERSAL_NODE_SHAPES_H
 
+/// @cond INTERNAL
+
 #include <hpp/fcl/collision_data.h>
-#include <hpp/fcl/traversal/traversal_node_base.h>
 #include <hpp/fcl/narrowphase/narrowphase.h>
-#include <hpp/fcl/shape/geometric_shapes_utility.h>
 #include <hpp/fcl/BV/BV.h>
 #include <hpp/fcl/shape/geometric_shapes_utility.h>
+#include <hpp/fcl/internal/traversal_node_base.h>
 
 namespace hpp
 {
 namespace fcl
 {
 
+/// @addtogroup Traversal_For_Collision
+/// @{
 
 /// @brief Traversal node for collision between two shapes
-template<typename S1, typename S2, typename NarrowPhaseSolver>
+template<typename S1, typename S2>
 class ShapeCollisionTraversalNode : public CollisionTraversalNodeBase
 {
 public:
@@ -67,19 +69,19 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  bool BVTesting(int, int) const
+  bool BVDisjoints(int, int) const
   {
     return false;
   }
 
   /// @brief BV culling test in one BVTT node
-  bool BVTesting(int, int, FCL_REAL&) const
+  bool BVDisjoints(int, int, FCL_REAL&) const
   {
     throw std::runtime_error ("Not implemented");
   }
 
   /// @brief Intersection testing between leaves (two shapes)
-  void leafTesting(int, int, FCL_REAL&) const
+  void leafCollides(int, int, FCL_REAL&) const
   {
     bool is_collision = false;
     if(request.enable_contact)
@@ -111,11 +113,16 @@ public:
   const S1* model1;
   const S2* model2;
 
-  const NarrowPhaseSolver* nsolver;
+  const GJKSolver* nsolver;
 };
 
+/// @}
+
+/// @addtogroup Traversal_For_Distance
+/// @{
+
 /// @brief Traversal node for distance between two shapes
-template<typename S1, typename S2, typename NarrowPhaseSolver>
+template<typename S1, typename S2>
 class ShapeDistanceTraversalNode : public DistanceTraversalNodeBase
 {
 public:
@@ -128,13 +135,13 @@ public:
   }
 
   /// @brief BV culling test in one BVTT node
-  FCL_REAL BVTesting(int, int) const
+  FCL_REAL BVDistanceLowerBound(int, int) const
   {
     return -1; // should not be used 
   }
 
   /// @brief Distance testing between leaves (two shapes)
-  void leafTesting(int, int) const
+  void leafComputeDistance(int, int) const
   {
     FCL_REAL distance;
     Vec3f closest_p1, closest_p2, normal;
@@ -147,10 +154,15 @@ public:
   const S1* model1;
   const S2* model2;
 
-  const NarrowPhaseSolver* nsolver;
+  const GJKSolver* nsolver;
 };
+
+/// @}
+
 }
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/traversal/traversal_recurse.h b/include/hpp/fcl/internal/traversal_recurse.h
similarity index 80%
rename from include/hpp/fcl/traversal/traversal_recurse.h
rename to include/hpp/fcl/internal/traversal_recurse.h
index f50bd75e2bbb05a5b214f6edefd50e614556d8ea..f5dbe283222f49c0025bf6c1f30a990641b1ff6b 100644
--- a/include/hpp/fcl/traversal/traversal_recurse.h
+++ b/include/hpp/fcl/internal/traversal_recurse.h
@@ -35,14 +35,15 @@
 
 /** \author Jia Pan */
 
-
 #ifndef HPP_FCL_TRAVERSAL_RECURSE_H
 #define HPP_FCL_TRAVERSAL_RECURSE_H
 
-#include <hpp/fcl/traversal/traversal_node_base.h>
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
+/// @cond INTERNAL
+
 #include <hpp/fcl/BVH/BVH_front.h>
 #include <queue>
+#include <hpp/fcl/internal/traversal_node_base.h>
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
 
 namespace hpp
 {
@@ -50,17 +51,14 @@ namespace fcl
 {
 
 /// Recurse function for collision
-/// \param node collision node,
-/// \param b1, b2 ids of bounding volume nodes for object 1 and object 2
-/// \retval sqrDistLowerBound squared lower bound on distance between objects.
+/// @param node collision node,
+/// @param b1, b2 ids of bounding volume nodes for object 1 and object 2
+/// @retval sqrDistLowerBound squared lower bound on distance between objects.
 void collisionRecurse(CollisionTraversalNodeBase* node, int b1, int b2,
 		      BVHFrontList* front_list, FCL_REAL& sqrDistLowerBound);
 
-/// @brief Recurse function for collision, specialized for OBB type
-void collisionRecurse(MeshCollisionTraversalNodeOBB* node, int b1, int b2, const Matrix3f& R, const Vec3f& T, BVHFrontList* front_list);
-
-/// @brief Recurse function for collision, specialized for RSS type
-void collisionRecurse(MeshCollisionTraversalNodeRSS* node, int b1, int b2, const Matrix3f& R, const Vec3f& T, BVHFrontList* front_list);
+void collisionNonRecurse(CollisionTraversalNodeBase* node,
+		         BVHFrontList* front_list, FCL_REAL& sqrDistLowerBound);
 
 /// @brief Recurse function for distance
 void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontList* front_list);
@@ -73,9 +71,10 @@ void propagateBVHFrontListCollisionRecurse
   (CollisionTraversalNodeBase* node, const CollisionRequest& request,
    CollisionResult& result, BVHFrontList* front_list);
 
-
 }
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/include/hpp/fcl/math/matrix_3f.h b/include/hpp/fcl/math/matrix_3f.h
index 122f329109d49150a81edda376ca3144ee9ebccd..3c60bb44b1f3c6c4f2b080be1791ba0eb59b03ed 100644
--- a/include/hpp/fcl/math/matrix_3f.h
+++ b/include/hpp/fcl/math/matrix_3f.h
@@ -38,70 +38,9 @@
 #ifndef HPP_FCL_MATRIX_3F_H
 #define HPP_FCL_MATRIX_3F_H
 
-#include <hpp/fcl/math/vec_3f.h>
+# warning "This file is deprecated. Include <hpp/fcl/math/types.h> instead."
 
-namespace hpp
-{
-namespace fcl
-{
+// List of equivalent includes.
+# include <hpp/fcl/math/types.h>
 
-  typedef Eigen::Matrix<FCL_REAL, 3, 3> Matrix3f;
-
-/// @brief Class for variance matrix in 3d
-class Variance3f
-{
-public:
-  /// @brief Variation matrix
-  Matrix3f Sigma;
-
-  /// @brief Variations along the eign axes
-  Matrix3f::Scalar sigma[3];
-
-  /// @brief Eigen axes of the variation matrix
-  Vec3f axis[3];
-
-  Variance3f() {}
-
-  Variance3f(const Matrix3f& S) : Sigma(S)
-  {
-    init();
-  }
-
-  /// @brief init the Variance
-  void init() 
-  {
-    eigen(Sigma, sigma, axis);
-  }
-
-  /// @brief Compute the sqrt of Sigma matrix based on the eigen decomposition result, this is useful when the uncertainty matrix is initialized as a square variation matrix
-  Variance3f& sqrt()
-  {
-    for(std::size_t i = 0; i < 3; ++i)
-    {
-      if(sigma[i] < 0) sigma[i] = 0;
-      sigma[i] = std::sqrt(sigma[i]);
-    }
-
-
-    Sigma.setZero();
-    for(std::size_t i = 0; i < 3; ++i)
-    {
-      for(std::size_t j = 0; j < 3; ++j)
-      {
-        Sigma(i, j) += sigma[0] * axis[0][i] * axis[0][j];
-        Sigma(i, j) += sigma[1] * axis[1][i] * axis[1][j];
-        Sigma(i, j) += sigma[2] * axis[2][i] * axis[2][j];
-      }
-    }
-
-    return *this;
-  }
-};
-
-}
-
-
-
-} // namespace hpp
-
-#endif
+#endif
\ No newline at end of file
diff --git a/include/hpp/fcl/math/transform.h b/include/hpp/fcl/math/transform.h
index 69c12043c6795bedf2c110374bf43a99afc3fa30..dd6e9f4cbaeb197d17742d7bfef4adc520b712e7 100644
--- a/include/hpp/fcl/math/transform.h
+++ b/include/hpp/fcl/math/transform.h
@@ -39,7 +39,7 @@
 #ifndef HPP_FCL_TRANSFORM_H
 #define HPP_FCL_TRANSFORM_H
 
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <boost/thread/mutex.hpp>
 
 namespace hpp
@@ -48,6 +48,7 @@ namespace fcl
 {
 
 typedef Eigen::Quaternion<FCL_REAL> Quaternion3f;
+
 static inline std::ostream& operator << (std::ostream& o, const Quaternion3f& q)
 {
   o << "(" << q.w() << " " << q.x() << " " << q.y() << " " << q.z() << ")";
@@ -68,18 +69,11 @@ inline bool areQuatEquals (const Quaternion3f& q1, const Quaternion3f& q2)
 /// @brief Simple transform class used locally by InterpMotion
 class Transform3f
 {
-  /// @brief Whether matrix cache is set
-  mutable bool matrix_set;
   /// @brief Matrix cache
-  mutable Matrix3f R;
+  Matrix3f R;
 
   /// @brief Tranlation vector
   Vec3f T;
-
-  /// @brief Rotation
-  Quaternion3f q;
-
-  const Matrix3f& getRotationInternal() const;
 public:
 
   /// @brief Default transform is no movement
@@ -89,57 +83,40 @@ public:
   }
 
   /// @brief Construct transform from rotation and translation
-  Transform3f(const Matrix3f& R_, const Vec3f& T_) : matrix_set(true),
-                                                     R(R_),
-                                                     T(T_)
-  {
-    q = Quaternion3f(R_);
-  }
+  template <typename Matrixx3Like, typename Vector3Like>
+  Transform3f(const Eigen::MatrixBase<Matrixx3Like>& R_,
+              const Eigen::MatrixBase<Vector3Like>& T_) :
+    R(R_),
+    T(T_)
+  {}
 
   /// @brief Construct transform from rotation and translation
-  Transform3f(const Quaternion3f& q_, const Vec3f& T_) : matrix_set(false),
-                                                         T(T_),
-                                                         q(q_)
-  {
-  }
+  template <typename Vector3Like>
+  Transform3f(const Quaternion3f& q_,
+              const Eigen::MatrixBase<Vector3Like>& T_) :
+    R(q_.toRotationMatrix()),
+    T(T_)
+  {}
 
   /// @brief Construct transform from rotation
-  Transform3f(const Matrix3f& R_) : matrix_set(true),
-                                    R(R_),
+  Transform3f(const Matrix3f& R_) : R(R_),
                                     T(Vec3f::Zero())
-  {
-    q = Quaternion3f(R_);
-  }
+  {}
 
   /// @brief Construct transform from rotation
-  Transform3f(const Quaternion3f& q_) : matrix_set(false),
-                                        T(Vec3f::Zero()),
-                                        q(q_)
-  {
-  }
+  Transform3f(const Quaternion3f& q_) : R(q_),
+                                        T(Vec3f::Zero())
+  {}
 
   /// @brief Construct transform from translation
-  Transform3f(const Vec3f& T_) : matrix_set(true), 
-                                 T(T_),
-                                 q(Quaternion3f::Identity())
-  {
-    R.setIdentity();
-  }
-
-  /// @brief Construct transform from another transform
-  Transform3f(const Transform3f& tf) : matrix_set(tf.matrix_set),
-                                       R(tf.R),
-                                       T(tf.T),
-                                       q(tf.q)
-  {
-  }
+  Transform3f(const Vec3f& T_) : R(Matrix3f::Identity()),
+                                 T(T_)
+  {}
 
   /// @brief operator = 
   Transform3f& operator = (const Transform3f& tf)
   {
-    matrix_set = tf.matrix_set;
     R = tf.R;
-    q = tf.q;
     T = tf.T;
     return *this;
   }
@@ -153,31 +130,28 @@ public:
   /// @brief get rotation
   inline const Matrix3f& getRotation() const
   {
-    if(matrix_set) return R;
-    return getRotationInternal();
+    return R;
   }
 
   /// @brief get quaternion
-  inline const Quaternion3f& getQuatRotation() const
+  inline Quaternion3f getQuatRotation() const
   {
-    return q;
+    return Quaternion3f (R);
   }
 
   /// @brief set transform from rotation and translation
-  inline void setTransform(const Matrix3f& R_, const Vec3f& T_)
+  template <typename Matrixx3Like, typename Vector3Like>
+  inline void setTransform(const Eigen::MatrixBase<Matrixx3Like>& R_, const Eigen::MatrixBase<Vector3Like>& T_)
   {
     R.noalias() = R_;
     T.noalias() = T_;
-    q = Quaternion3f(R_);
-    matrix_set = true;
   }
 
   /// @brief set transform from rotation and translation
   inline void setTransform(const Quaternion3f& q_, const Vec3f& T_)
   {
-    matrix_set = false;
-    q = q_;
-    T.noalias() = T_;
+    R = q_.toRotationMatrix();
+    T = T_;
   }
 
   /// @brief set transform from rotation
@@ -185,8 +159,6 @@ public:
   inline void setRotation(const Eigen::MatrixBase<Derived>& R_)
   {
     R.noalias() = R_;
-    matrix_set = true;
-    q = Quaternion3f(R);
   }
 
   /// @brief set transform from translation
@@ -199,53 +171,54 @@ public:
   /// @brief set transform from rotation
   inline void setQuatRotation(const Quaternion3f& q_)
   {
-    matrix_set = false;
-    q = q_;
+    R = q_.toRotationMatrix();
   }
 
   /// @brief transform a given vector by the transform
   template <typename Derived>
   inline Vec3f transform(const Eigen::MatrixBase<Derived>& v) const
   {
-    return q * v + T;
+    return R * v + T;
   }
 
   /// @brief inverse transform
-  inline Transform3f& inverse()
+  inline Transform3f& inverseInPlace()
   {
-    matrix_set = false;
-    q = q.conjugate();
-    T = q * (-T);
+    R.transposeInPlace();
+    T = - R * T;
     return *this;
   }
 
+  /// @brief inverse transform
+  inline Transform3f inverse()
+  {
+    return Transform3f (R.transpose(), - R.transpose() * T);
+  }
+
   /// @brief inverse the transform and multiply with another
   inline Transform3f inverseTimes(const Transform3f& other) const
   {
-    const Quaternion3f& q_inv = q.conjugate();
-    return Transform3f(q_inv * other.q, q_inv * (other.T - T));
+    return Transform3f(R.transpose() * other.R, R.transpose() * (other.T - T));
   }
 
   /// @brief multiply with another transform
   inline const Transform3f& operator *= (const Transform3f& other)
   {
-    matrix_set = false;
-    T += q * other.T;
-    q *= other.q;
+    T += R * other.T;
+    R *= other.R;
     return *this;
   }
 
   /// @brief multiply with another transform
   inline Transform3f operator * (const Transform3f& other) const
   {
-    Quaternion3f q_new = q * other.q;
-    return Transform3f(q_new, q * other.T + T);
+    return Transform3f(R * other.R, R * other.T + T);
   }
 
   /// @brief check whether the transform is identity
   inline bool isIdentity() const
   {
-    return isQuatIdentity(q) && T.isZero();
+    return R.isIdentity() && T.isZero();
   }
 
   /// @brief set the transform to be identity transform
@@ -253,36 +226,26 @@ public:
   {
     R.setIdentity();
     T.setZero();
-    q.setIdentity();
-    matrix_set = true;
   }
 
   bool operator == (const Transform3f& other) const
   {
-    return areQuatEquals(q, other.getQuatRotation()) && (T == other.getTranslation());
+    return R == other.R && (T == other.getTranslation());
   }
 
   bool operator != (const Transform3f& other) const
   {
     return !(*this == other);
   }
-
 };
 
-/// @brief inverse the transform
-Transform3f inverse(const Transform3f& tf);
-
-/// @brief compute the relative transform between two transforms: tf2 = tf1 * tf (relative to the local coordinate system in tf1)
-void relativeTransform(const Transform3f& tf1, const Transform3f& tf2,
-                       Transform3f& tf);
-
-/// @brief compute the relative transform between two transforms: tf2 = tf * tf1 (relative to the global coordinate system)
-void relativeTransform2(const Transform3f& tf1, const Transform3f& tf2,
-                        Transform3f& tf);
-
-
+template<typename Derived>
+inline Quaternion3f fromAxisAngle(const Eigen::MatrixBase<Derived>& axis, FCL_REAL angle)
+{
+  return Quaternion3f (Eigen::AngleAxis<double>(angle, axis));
 }
 
+}
 } // namespace hpp
 
 #endif
diff --git a/include/hpp/fcl/math/types.h b/include/hpp/fcl/math/types.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec431e7a92b59d788dc4582b7b84d25e3815696f
--- /dev/null
+++ b/include/hpp/fcl/math/types.h
@@ -0,0 +1,46 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2011-2014, Willow Garage, Inc.
+ *  Copyright (c) 2014-2015, Open Source Robotics Foundation
+ *  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 Open Source Robotics Foundation 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 Joseph Mirabel */
+
+#ifndef HPP_FCL_MATH_TYPES_H
+#define HPP_FCL_MATH_TYPES_H
+
+# warning "This file is deprecated. Include <hpp/fcl/data_types.h> instead."
+
+// List of equivalent includes.
+# include <hpp/fcl/data_types.h>
+
+#endif
\ No newline at end of file
diff --git a/include/hpp/fcl/math/vec_3f.h b/include/hpp/fcl/math/vec_3f.h
index b7fcef9db0947c75d0324e7fc3a0ab846ded248c..9d41c14f8fa9a8daaf0cf97bd7d90da811d4fe9a 100644
--- a/include/hpp/fcl/math/vec_3f.h
+++ b/include/hpp/fcl/math/vec_3f.h
@@ -38,37 +38,9 @@
 #ifndef HPP_FCL_VEC_3F_H
 #define HPP_FCL_VEC_3F_H
 
-#include <hpp/fcl/data_types.h>
+# warning "This file is deprecated. Include <hpp/fcl/math/types.h> instead."
 
-#include <Eigen/Core>
-#include <Eigen/Geometry>
-#include <hpp/fcl/math/tools.h>
+// List of equivalent includes.
+# include <hpp/fcl/math/types.h>
 
-#include <cmath>
-#include <iostream>
-#include <limits>
-
-
-namespace hpp
-{
-namespace fcl
-{
-  typedef Eigen::Matrix<FCL_REAL, 3, 1> Vec3f;
-}
-
-
-#ifdef HPP_FCL_HAVE_OCTOMAP
-  #define OCTOMAP_VERSION_AT_LEAST(x,y,z) \
-    (OCTOMAP_MAJOR_VERSION > x || (OCTOMAP_MAJOR_VERSION >= x && \
-    (OCTOMAP_MINOR_VERSION > y || (OCTOMAP_MINOR_VERSION >= y && \
-    OCTOMAP_PATCH_VERSION >= z))))
-
-  #define OCTOMAP_VERSION_AT_MOST(x,y,z) \
-    (OCTOMAP_MAJOR_VERSION < x || (OCTOMAP_MAJOR_VERSION <= x && \
-    (OCTOMAP_MINOR_VERSION < y || (OCTOMAP_MINOR_VERSION <= y && \
-    OCTOMAP_PATCH_VERSION <= z))))
-#endif // HPP_FCL_HAVE_OCTOMAP
-
-} // namespace hpp
-
-#endif
+#endif
\ No newline at end of file
diff --git a/include/hpp/fcl/mesh_loader/assimp.h b/include/hpp/fcl/mesh_loader/assimp.h
index b5c6ab0c7aa41b08bcbbb1a4cd65ecc9a77ef6b1..68748291dd9c9ce494040948dafc23d12e394bef 100644
--- a/include/hpp/fcl/mesh_loader/assimp.h
+++ b/include/hpp/fcl/mesh_loader/assimp.h
@@ -38,38 +38,21 @@
 #ifndef HPP_FCL_MESH_LOADER_ASSIMP_H
 #define HPP_FCL_MESH_LOADER_ASSIMP_H
 
-// Assimp >= 5.0 is forcing the use of C++11 keywords. A fix has been submitted https://github.com/assimp/assimp/pull/2758.
-// The next lines fixes the bug for current version of hpp-fcl.
-#include <assimp/defs.h>
-#if __cplusplus < 201103L && defined(AI_NO_EXCEPT)
-  #undef AI_NO_EXCEPT
-  #define AI_NO_EXCEPT
-#endif
-
-#ifdef HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES
-  #include <assimp/DefaultLogger.hpp>
-  #include <assimp/IOStream.hpp>
-  #include <assimp/IOSystem.hpp>
-  #include <assimp/scene.h>
-  #include <assimp/Importer.hpp>
-  #include <assimp/postprocess.h>
-#else
-  #include <assimp/DefaultLogger.h>
-  #include <assimp/assimp.hpp>
-  #include <assimp/IOStream.h>
-  #include <assimp/IOSystem.h>
-  #include <assimp/aiScene.h>
-  #include <assimp/aiPostProcess.h>
-#endif
-
 #include <hpp/fcl/BV/OBBRSS.h>
 #include <hpp/fcl/BVH/BVH_model.h>
 
+class aiScene;
+namespace Assimp {
+  class Importer;
+}
+
 namespace hpp
 {
 namespace fcl
 {
-  
+
+namespace internal
+{
 
 struct TriangleAndVertices
 {
@@ -77,6 +60,16 @@ struct TriangleAndVertices
   std::vector <fcl::Triangle> triangles_;
 };
 
+struct Loader {
+  Loader ();
+  ~Loader ();
+
+  void load (const std::string& resource_path);
+
+  Assimp::Importer* importer;
+  aiScene const* scene;
+};
+
 /**
  * @brief      Recursive procedure for building a mesh
  *
@@ -86,31 +79,26 @@ struct TriangleAndVertices
  * @param[in]  vertices_offset Current number of vertices in the model
  * @param      tv              Triangles and Vertices of the mesh submodels
  */
-unsigned buildMesh (const fcl::Vec3f & scale,
-                    const aiScene* scene,
-                    const aiNode* node,
-                    unsigned vertices_offset,
-                    TriangleAndVertices & tv);
+void buildMesh (const fcl::Vec3f & scale,
+                const aiScene* scene,
+                unsigned vertices_offset,
+                TriangleAndVertices & tv);
 
 /**
  * @brief      Convert an assimp scene to a mesh
  *
- * @param[in]  name   File (ressource) transformed into an assimp scene in loa
  * @param[in]  scale  Scale to apply when reading the ressource
  * @param[in]  scene  Pointer to the assimp scene
  * @param[out] mesh  The mesh that must be built
  */
 template<class BoundingVolume>   
-inline void meshFromAssimpScene(const std::string & name,
+inline void meshFromAssimpScene(
                          const fcl::Vec3f & scale,
                          const aiScene* scene,
                          const boost::shared_ptr < BVHModel<BoundingVolume> > & mesh)
 {
   TriangleAndVertices tv;
   
-  if (!scene->HasMeshes())
-    throw std::invalid_argument (std::string ("No meshes found in file ")+name);
-  
   int res = mesh->beginModel ();
   
   if (res != fcl::BVH_OK)
@@ -120,13 +108,14 @@ inline void meshFromAssimpScene(const std::string & name,
     throw std::runtime_error (error.str ());
   }
     
-  buildMesh (scale, scene, scene->mRootNode, 
-      (unsigned) mesh->num_vertices, tv);
+  buildMesh (scale, scene, (unsigned) mesh->num_vertices, tv);
   mesh->addSubModel (tv.vertices_, tv.triangles_);
     
   mesh->endModel ();
 }
 
+} // namespace internal
+
 /**
  * @brief      Read a mesh file and convert it to a polyhedral mesh
  *
@@ -139,46 +128,13 @@ inline void loadPolyhedronFromResource (const std::string & resource_path,
                                  const fcl::Vec3f & scale,
                                  const boost::shared_ptr < BVHModel<BoundingVolume> > & polyhedron)
 {
-  Assimp::Importer importer;
-  // set list of ignored parameters (parameters used for rendering)
-  importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
-      aiComponent_TANGENTS_AND_BITANGENTS|
-      aiComponent_COLORS |
-      aiComponent_BONEWEIGHTS |
-      aiComponent_ANIMATIONS |
-      aiComponent_LIGHTS |
-      aiComponent_CAMERAS|
-      aiComponent_TEXTURES |
-      aiComponent_TEXCOORDS |
-      aiComponent_MATERIALS |
-      aiComponent_NORMALS
-      );
-
-  const aiScene* scene = importer.ReadFile(resource_path.c_str(),
-      aiProcess_SortByPType |
-      aiProcess_Triangulate |
-      aiProcess_RemoveComponent |
-      aiProcess_ImproveCacheLocality |
-      // TODO: I (Joseph Mirabel) have no idea whether degenerated triangles are
-      // properly handled. Enabling aiProcess_FindDegenerates would throw an
-      // exception when that happens. Is it too conservative ?
-      // aiProcess_FindDegenerates |
-      aiProcess_JoinIdenticalVertices
-      );
-
-  if (!scene)
-  {
-    const std::string exception_message (std::string ("Could not load resource ") + resource_path + std::string("\n") +
-                                         importer.GetErrorString () + std::string("\n") +
-                                         "Hint: the mesh directory may be wrong.");
-    throw std::invalid_argument(exception_message);
-  }
-  
-  meshFromAssimpScene (resource_path, scale, scene, polyhedron);
-}
+  internal::Loader scene;
+  scene.load (resource_path);
 
+  internal::meshFromAssimpScene (scale, scene.scene, polyhedron);
 }
 
+} // namespace fcl
 } // namespace hpp
 
-#endif // FCL_MESH_LOADER_ASSIMP_H
+#endif // HPP_FCL_MESH_LOADER_ASSIMP_H
diff --git a/include/hpp/fcl/mesh_loader/loader.h b/include/hpp/fcl/mesh_loader/loader.h
index ce8a30afbb52e241c40668c6a4aca49457174e61..5039bc05fa6e97625313b6f39b34158e227a37d8 100644
--- a/include/hpp/fcl/mesh_loader/loader.h
+++ b/include/hpp/fcl/mesh_loader/loader.h
@@ -40,7 +40,7 @@
 #include <boost/shared_ptr.hpp>
 #include <hpp/fcl/fwd.hh>
 #include <hpp/fcl/config.hh>
-#include <hpp/fcl/math/vec_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <hpp/fcl/collision_object.h>
 
 namespace hpp
@@ -55,7 +55,7 @@ namespace fcl {
 
       /// \param bvType ignored
       /// \deprecated Use MeshLoader::load(const std::string&, const Vec3f&)
-      CollisionGeometryPtr_t load (const std::string& filename,
+      BVHModelPtr_t load (const std::string& filename,
           const Vec3f& scale,
           const NODE_TYPE& bvType) HPP_FCL_DEPRECATED
       {
@@ -63,7 +63,7 @@ namespace fcl {
         return load (filename, scale);
       }
 
-      virtual CollisionGeometryPtr_t load (const std::string& filename,
+      virtual BVHModelPtr_t load (const std::string& filename,
           const Vec3f& scale);
 
       MeshLoader (const NODE_TYPE& bvType = BV_OBBRSS) : bvType_ (bvType) {}
@@ -83,17 +83,7 @@ namespace fcl {
 
       CachedMeshLoader (const NODE_TYPE& bvType = BV_OBBRSS) : MeshLoader (bvType) {}
 
-      /// \param bvType ignored
-      /// \deprecated Use MeshLoader::load(const std::string&, const Vec3f&)
-      CollisionGeometryPtr_t load (const std::string& filename,
-          const Vec3f& scale,
-          const NODE_TYPE& bvType) HPP_FCL_DEPRECATED
-      {
-        (void) bvType;
-        return load(filename, scale);
-      }
-
-      virtual CollisionGeometryPtr_t load (const std::string& filename,
+      virtual BVHModelPtr_t load (const std::string& filename,
           const Vec3f& scale);
 
       struct Key {
@@ -105,7 +95,7 @@ namespace fcl {
 
         bool operator< (const CachedMeshLoader::Key& b) const;
       };
-      typedef std::map <Key, CollisionGeometryPtr_t> Cache_t;
+      typedef std::map <Key, BVHModelPtr_t> Cache_t;
 
       const Cache_t cache () const { return cache_; }
     private:
diff --git a/include/hpp/fcl/narrowphase/gjk.h b/include/hpp/fcl/narrowphase/gjk.h
index 4748e3e087efa12a8238d0df311eec54ec7b544c..6e7d25ffc487085b533802b52cf1fb94c67c93cb 100644
--- a/include/hpp/fcl/narrowphase/gjk.h
+++ b/include/hpp/fcl/narrowphase/gjk.h
@@ -50,83 +50,89 @@ namespace details
 {
 
 /// @brief the support function for shape
-Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir); 
+Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized); 
 
 /// @brief Minkowski difference class of two shapes
 ///
-/// \note The Minkowski difference is expressed in the frame of the first shape.
+/// @todo template this by the two shapes. The triangle / triangle case can be
+///       easily optimized computing once the triangle shapes[1] into frame0
+///
+/// @note The Minkowski difference is expressed in the frame of the first shape.
 struct MinkowskiDiff
 {
   /// @brief points to two shapes
   const ShapeBase* shapes[2];
 
-  /// @brief rotation from shape0 to shape1
-  Matrix3f toshape1;
+  /// @brief rotation from shape1 to shape0
+  /// such that @f$ p_in_0 = oR1 * p_in_1 + ot1 @f$.
+  Matrix3f oR1;
+
+  /// @brief translation from shape1 to shape0
+  /// such that @f$ p_in_0 = oR1 * p_in_1 + ot1 @f$.
+  Vec3f ot1;
+
+  typedef void (*GetSupportFunction) (const MinkowskiDiff& minkowskiDiff,
+      const Vec3f& dir, bool dirIsNormalized, Vec3f& support0, Vec3f& support1);
+  GetSupportFunction getSupportFunc;
 
-  /// @brief transform from shape1 to shape0 
-  Transform3f toshape0;
+  MinkowskiDiff() : getSupportFunc (NULL) {}
 
-  MinkowskiDiff() { }
+  /// Set the two shapes,
+  /// assuming the relative transformation between them is identity.
+  void set (const ShapeBase* shape0, const ShapeBase* shape1);
+
+  /// Set the two shapes, with a relative transformation.
+  void set (const ShapeBase* shape0, const ShapeBase* shape1,
+      const Transform3f& tf0, const Transform3f& tf1);
 
   /// @brief support function for shape0
-  inline Vec3f support0(const Vec3f& d) const
+  inline Vec3f support0(const Vec3f& d, bool dIsNormalized) const
   {
-    return getSupport(shapes[0], d);
+    return getSupport(shapes[0], d, dIsNormalized);
   }
-  
+
   /// @brief support function for shape1
-  inline Vec3f support1(const Vec3f& d) const
+  inline Vec3f support1(const Vec3f& d, bool dIsNormalized) const
   {
-    return toshape0.transform(getSupport(shapes[1], toshape1 * d));
+    return oR1 * getSupport(shapes[1], oR1.transpose() * d, dIsNormalized) + ot1;
   }
 
   /// @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
+  inline void support(const Vec3f& d, bool dIsNormalized, Vec3f& supp0, Vec3f& supp1) const
   {
-    if(index)
-      return support1(d);
-    else
-      return support0(d);
+    assert(getSupportFunc != NULL);
+    getSupportFunc(*this, d, dIsNormalized, supp0, supp1);
   }
 };
 
-
 /// @brief class for GJK algorithm
 ///
-/// \note The computations are performed in the frame of the first shape.
+/// @note The computations are performed in the frame of the first shape.
 struct GJK
 {
   struct SimplexV
   {
-    /// @brief support direction
-    Vec3f d; 
-    /// @brieg support vector (i.e., the furthest point on the shape along the support direction)
+    /// @brief support vector for shape 0 and 1.
+    Vec3f w0, w1; 
+    /// @brief support vector (i.e., the furthest point on the shape along the support direction)
     Vec3f w;
-
-    SimplexV () : d(Vec3f::Zero()), w(Vec3f::Zero()) {}
   };
 
+  typedef unsigned char vertex_id_t;
+
   struct Simplex
   {
     /// @brief simplex vertex
     SimplexV* vertex[4];
-    /// @brief weight 
-    FCL_REAL coefficient[4];
     /// @brief size of simplex (number of vertices)
-    size_t rank;
+    vertex_id_t rank;
 
-    Simplex() : rank(0) {}
+    Simplex() {}
   };
 
   enum Status {Valid, Inside, Failed};
 
-  MinkowskiDiff shape;
+  MinkowskiDiff const* shape;
   Vec3f ray;
   FCL_REAL distance;
   Simplex simplices[2];
@@ -141,16 +147,14 @@ struct GJK
   void initialize();
 
   /// @brief GJK algorithm, given the initial value guess
-  Status evaluate(const MinkowskiDiff& shape_, const Vec3f& guess);
+  Status evaluate(const MinkowskiDiff& shape, const Vec3f& guess);
 
   /// @brief apply the support function along a direction, the result is return in sv
-  void getSupport(const Vec3f& d, SimplexV& sv) const;
-
-  /// @brief discard one vertex from the simplex
-  void removeVertex(Simplex& simplex);
-
-  /// @brief append one vertex to the simplex
-  void appendVertex(Simplex& simplex, const Vec3f& v);
+  inline void getSupport(const Vec3f& d, bool dIsNormalized, SimplexV& sv) const
+  {
+    shape->support(d, dIsNormalized, sv.w0, sv.w1);
+    sv.w.noalias() = sv.w0 - sv.w1;
+  }
 
   /// @brief whether the simplex enclose the origin
   bool encloseOrigin();
@@ -161,20 +165,48 @@ struct GJK
     return simplex;
   }
 
+  /// Get the closest points on each object.
+  /// @return true on success
+  static bool getClosestPoints (const Simplex& simplex, Vec3f& w0, Vec3f& w1);
+
   /// @brief get the guess from current simplex
   Vec3f getGuessFromSimplex() const;
 
+  /// @brief Distance threshold for early break.
+  /// GJK stops when it proved the distance is more than this threshold.
+  /// @note The closest points will be erroneous in this case.
+  ///       If you want the closest points, set this to infinity (the default).
+  void setDistanceEarlyBreak (const FCL_REAL& dup)
+  {
+    distance_upper_bound = dup;
+  }
+
 private:
   SimplexV store_v[4];
   SimplexV* free_v[4];
-  size_t nfree;
-  size_t current;
+  vertex_id_t nfree;
+  vertex_id_t current;
   Simplex* simplex;
   Status status;
 
   unsigned int max_iterations;
   FCL_REAL tolerance;
+  FCL_REAL distance_upper_bound;
+
+  /// @brief discard one vertex from the simplex
+  inline void removeVertex(Simplex& simplex);
+
+  /// @brief append one vertex to the simplex
+  inline void appendVertex(Simplex& simplex, const Vec3f& v, bool isNormalized = false);
+
+  /// @brief Project origin (0) onto line a-b
+  bool projectLineOrigin(const Simplex& current, Simplex& next);
 
+  /// @brief Project origin (0) onto triangle a-b-c
+  bool projectTriangleOrigin(const Simplex& current, Simplex& next);
+
+  /// @brief Project origin (0) onto tetrahedran a-b-c-d
+  bool projectTetrahedraOrigin(const Simplex& current, Simplex& next);
 };
 
 
@@ -273,6 +305,9 @@ public:
 
   void initialize();
 
+  Status evaluate(GJK& gjk, const Vec3f& guess);
+
+private:
   bool getEdgeDist(SimplexF* face, SimplexV* a, SimplexV* b, FCL_REAL& dist);
 
   SimplexF* newFace(SimplexV* a, SimplexV* b, SimplexV* vertex, bool forced);
@@ -280,8 +315,6 @@ public:
   /// @brief Find the best polytope face to split
   SimplexF* findBest();
 
-  Status evaluate(GJK& gjk, const Vec3f& guess);
-
   /// @brief the goal is to add a face connecting vertex w and face edge f[e] 
   bool expand(size_t pass, SimplexV* w, SimplexF* f, size_t e, SimplexHorizon& horizon);  
 };
diff --git a/include/hpp/fcl/narrowphase/narrowphase.h b/include/hpp/fcl/narrowphase/narrowphase.h
index a85f7fae3131b7333d88401a4168af161bdaf42d..2dedf459c939ebb0ce1e21729eafafd6f2837149 100644
--- a/include/hpp/fcl/narrowphase/narrowphase.h
+++ b/include/hpp/fcl/narrowphase/narrowphase.h
@@ -50,7 +50,7 @@ namespace fcl
 
 
   /// @brief collision and distance solver based on GJK algorithm implemented in fcl (rewritten the code from the GJK in bullet)
-  struct GJKSolver_indep
+  struct GJKSolver
   {
     /// @brief intersection checking between two shapes
     template<typename S1, typename S2>
@@ -62,10 +62,7 @@ namespace fcl
       if(enable_cached_guess) guess = cached_guess;
     
       details::MinkowskiDiff shape;
-      shape.shapes[0] = &s1;
-      shape.shapes[1] = &s2;
-      shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation();
-      shape.toshape0 = tf1.inverseTimes(tf2);
+      shape.set (&s1, &s2, tf1, tf2);
   
       details::GJK gjk((unsigned int )gjk_max_iterations, gjk_tolerance);
       details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
@@ -79,12 +76,8 @@ namespace fcl
             details::EPA::Status epa_status = epa.evaluate(gjk, -guess);
             if(epa_status != details::EPA::Failed)
               {
-                Vec3f w0 (Vec3f::Zero());
-                for(size_t i = 0; i < epa.result.rank; ++i)
-                  {
-                    w0 += shape.support(epa.result.vertex[i]->d, 0) *
-                      epa.result.coefficient[i];
-                  }
+                Vec3f w0, w1;
+                details::GJK::getClosestPoints (epa.result, w0, w1);
                 if(penetration_depth) *penetration_depth = -epa.depth;
                 if(normal) *normal = tf2.getRotation() * epa.normal;
                 if(contact_points) *contact_points = tf1.transform(w0 - epa.normal*(epa.depth *0.5));
@@ -101,7 +94,7 @@ namespace fcl
     }
 
     //// @brief intersection checking between one shape and a triangle with transformation
-    /// \return true if the shape are colliding.
+    /// @return true if the shape are colliding.
     template<typename S>
     bool shapeTriangleInteraction
     (const S& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
@@ -109,16 +102,18 @@ namespace fcl
      Vec3f& p1, Vec3f& p2, Vec3f& normal) const
     {
       bool col;
-      TriangleP tri(P1, P2, P3);
+      // Express everything in frame 1
+      const Transform3f tf_1M2 (tf1.inverseTimes(tf2));
+      TriangleP tri(
+          tf_1M2.transform (P1),
+          tf_1M2.transform (P2),
+          tf_1M2.transform (P3));
 
       Vec3f guess(1, 0, 0);
       if(enable_cached_guess) guess = cached_guess;
 
       details::MinkowskiDiff shape;
-      shape.shapes[0] = &s;
-      shape.shapes[1] = &tri;
-      shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation();
-      shape.toshape0 = tf1.inverseTimes(tf2);
+      shape.set (&s, &tri);
   
       details::GJK gjk((unsigned int )gjk_max_iterations, gjk_tolerance);
       details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
@@ -132,12 +127,8 @@ namespace fcl
             details::EPA epa(epa_max_face_num, epa_max_vertex_num, epa_max_iterations, epa_tolerance);
             details::EPA::Status epa_status = epa.evaluate(gjk, -guess);
             assert (epa_status != details::EPA::Failed); (void) epa_status;
-            Vec3f w0 (Vec3f::Zero());
-            for(size_t i = 0; i < epa.result.rank; ++i)
-              {
-                w0 += shape.support(epa.result.vertex[i]->d, 0) *
-                  epa.result.coefficient[i];
-              }
+            Vec3f w0, w1;
+            details::GJK::getClosestPoints (epa.result, w0, w1);
             distance = -epa.depth;
             normal = -epa.normal;
             p1 = p2 = tf1.transform(w0 - epa.normal*(epa.depth *0.5));
@@ -148,16 +139,15 @@ namespace fcl
         case details::GJK::Failed:
           {
             col = false;
-            Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
-            for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
-              {
-                FCL_REAL p = gjk.getSimplex()->coefficient[i];
-                w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p;
-                w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p;
-              }
-            distance = (w0 - w1).norm();
-            p1 = tf1.transform (w0);
-            p2 = tf1.transform (w1);
+
+            details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2);
+            // TODO On degenerated case, the closest point may be wrong
+            // (i.e. an object face normal is colinear to gjk.ray
+            // assert (distance == (w0 - w1).norm());
+            distance = gjk.distance;
+
+            p1 = tf1.transform (p1);
+            p2 = tf1.transform (p2);
             assert (distance > 0);
           }
           break;
@@ -183,10 +173,7 @@ namespace fcl
       if(enable_cached_guess) guess = cached_guess;
 
       details::MinkowskiDiff shape;
-      shape.shapes[0] = &s1;
-      shape.shapes[1] = &s2;
-      shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation();
-      shape.toshape0 = tf1.inverseTimes(tf2);
+      shape.set (&s1, &s2, tf1, tf2);
 
       details::GJK gjk((unsigned int) gjk_max_iterations, gjk_tolerance);
       details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
@@ -196,13 +183,8 @@ namespace fcl
       {
         // TODO: understand why GJK fails between cylinder and box
         assert (distance * distance < sqrt (eps));
-        Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
-        for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
-        {
-          FCL_REAL p = gjk.getSimplex()->coefficient[i];
-          w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p;
-          w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p;
-        }
+        Vec3f w0, w1;
+        details::GJK::getClosestPoints (*gjk.getSimplex(), w0, w1);
         distance = 0;
         p1 = p2 = tf1.transform (.5* (w0 + w1));
         normal = Vec3f (0,0,0);
@@ -210,18 +192,14 @@ namespace fcl
       }
       else if(gjk_status == details::GJK::Valid)
         {
-          Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
-          for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
-            {
-              FCL_REAL p = gjk.getSimplex()->coefficient[i];
-              w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p;
-              w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p;
-            }
-
-          distance = (w0 - w1).norm();
-
-          p1 = tf1.transform (w0);
-          p2 = tf1.transform (w1);
+          details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2);
+          // TODO On degenerated case, the closest point may be wrong
+          // (i.e. an object face normal is colinear to gjk.ray
+          // assert (distance == (w0 - w1).norm());
+          distance = gjk.distance;
+
+          p1 = tf1.transform (p1);
+          p2 = tf1.transform (p2);
           return true;
         }
       else
@@ -234,12 +212,8 @@ namespace fcl
               details::EPA::Status epa_status = epa.evaluate(gjk, -guess);
               if(epa_status != details::EPA::Failed)
                 {
-                  Vec3f w0 (Vec3f::Zero());
-                  for(size_t i = 0; i < epa.result.rank; ++i)
-                    {
-                      w0 += shape.support(epa.result.vertex[i]->d, 0) *
-                        epa.result.coefficient[i];
-                    }
+                  Vec3f w0, w1;
+                  details::GJK::getClosestPoints (epa.result, w0, w1);
                   assert (epa.depth >= -eps);
                   distance = std::min (0., -epa.depth);
                   normal = tf2.getRotation() * epa.normal;
@@ -248,24 +222,18 @@ namespace fcl
             }
           else
             {
-              Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
-              for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
-                {
-                  FCL_REAL p = gjk.getSimplex()->coefficient[i];
-                  w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p;
-                  w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p;
-                }
+              details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2);
               distance = 0;
 
-              p1 = tf1.transform (w0);
-              p2 = tf1.transform (w1);
+              p1 = tf1.transform (p1);
+              p2 = tf1.transform (p2);
             }
           return false;
         }
     }
 
     /// @brief default setting for GJK algorithm
-    GJKSolver_indep()
+    GJKSolver()
     {
       gjk_max_iterations = 128;
       gjk_tolerance = 1e-6;
@@ -319,202 +287,202 @@ namespace fcl
 
   /// @brief Fast implementation for sphere-capsule collision
   template<>
-    bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1,
                                                           const Sphere &s2, const Transform3f& tf2,
                                                           Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
   /// @brief Fast implementation for sphere-sphere collision
   template<>
-    bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
                                                          const Sphere& s2, const Transform3f& tf2,
                                                          Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
   /// @brief Fast implementation for box-box collision
   template<>
-    bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1,
                                                    const Box& s2, const Transform3f& tf2,
                                                    Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace>(const Sphere& s1, const Transform3f& tf1,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1,
                                                             const Sphere& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Halfspace, Box>(const Halfspace& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Halfspace, Box>(const Halfspace& s1, const Transform3f& tf1,
                                                          const Box& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Halfspace, Capsule>(const Halfspace& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Halfspace, Capsule>(const Halfspace& s1, const Transform3f& tf1,
                                                              const Capsule& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Halfspace, Cylinder>(const Halfspace& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Halfspace, Cylinder>(const Halfspace& s1, const Transform3f& tf1,
                                                               const Cylinder& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Halfspace, Cone>(const Halfspace& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Halfspace, Cone>(const Halfspace& s1, const Transform3f& tf1,
                                                           const Cone& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Sphere, Plane>(const Sphere& s1, const Transform3f& tf1,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Plane, Sphere>(const Plane& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Plane, Sphere>(const Plane& s1, const Transform3f& tf1,
                                                         const Sphere& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Plane, Box>(const Plane& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Plane, Box>(const Plane& s1, const Transform3f& tf1,
                                                      const Box& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Plane, Capsule>(const Plane& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Plane, Capsule>(const Plane& s1, const Transform3f& tf1,
                                                          const Capsule& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Plane, Cylinder>(const Plane& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Plane, Cylinder>(const Plane& s1, const Transform3f& tf1,
                                                           const Cylinder& 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,
+    bool GJKSolver::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;
 
   template<>
-    bool GJKSolver_indep::shapeIntersect<Plane, Cone>(const Plane& s1, const Transform3f& tf1,
+    bool GJKSolver::shapeIntersect<Plane, Cone>(const Plane& s1, const Transform3f& tf1,
                                                       const Cone& 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,
+    bool GJKSolver::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;
 
   /// @brief Fast implementation for sphere-triangle collision
   template<>
-    bool GJKSolver_indep::shapeTriangleInteraction
+    bool GJKSolver::shapeTriangleInteraction
     (const Sphere& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
      const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance,
      Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   template<>
-    bool GJKSolver_indep::shapeTriangleInteraction
+    bool GJKSolver::shapeTriangleInteraction
     (const Halfspace& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
      const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance,
      Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   template<>
-    bool GJKSolver_indep::shapeTriangleInteraction
+    bool GJKSolver::shapeTriangleInteraction
     (const Plane& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
      const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance,
      Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   /// @brief Fast implementation for sphere-capsule distance
   template<>
-    bool GJKSolver_indep::shapeDistance<Sphere, Capsule>
+    bool GJKSolver::shapeDistance<Sphere, Capsule>
     (const Sphere& s1, const Transform3f& tf1,
      const Capsule& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   template<>
-    bool GJKSolver_indep::shapeDistance<Capsule, Sphere>
+    bool GJKSolver::shapeDistance<Capsule, Sphere>
     (const Capsule& s1, const Transform3f& tf1,
      const Sphere& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   /// @brief Fast implementation for sphere-cylinder distance
   template<>
-    bool GJKSolver_indep::shapeDistance<Sphere, Cylinder>
+    bool GJKSolver::shapeDistance<Sphere, Cylinder>
     (const Sphere& s1, const Transform3f& tf1,
      const Cylinder& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   template<>
-    bool GJKSolver_indep::shapeDistance<Cylinder, Sphere>
+    bool GJKSolver::shapeDistance<Cylinder, Sphere>
     (const Cylinder& s1, const Transform3f& tf1,
      const Sphere& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   /// @brief Fast implementation for sphere-sphere distance
   template<>
-    bool GJKSolver_indep::shapeDistance<Sphere, Sphere>
+    bool GJKSolver::shapeDistance<Sphere, Sphere>
     (const Sphere& s1, const Transform3f& tf1,
      const Sphere& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
 
   // @brief Computation of the distance result for capsule capsule. Closest points are based on two line-segments.
   template<>
-    bool GJKSolver_indep::shapeDistance<Capsule, Capsule>
+    bool GJKSolver::shapeDistance<Capsule, Capsule>
     (const Capsule& s1, const Transform3f& tf1,
      const Capsule& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
@@ -524,7 +492,7 @@ namespace fcl
   // Do not run EPA algorithm to compute penetration depth, use a dedicated
   // method.
   template<>
-    bool GJKSolver_indep::shapeDistance<TriangleP, TriangleP>
+    bool GJKSolver::shapeDistance<TriangleP, TriangleP>
     (const TriangleP& s1, const Transform3f& tf1,
      const TriangleP& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const;
diff --git a/include/hpp/fcl/profile.h b/include/hpp/fcl/profile.h
index 96d70d1cf8ec02916c1a608c3aef439c03d24155..a7e3f2780503a26cc021676e95cfec25d0f3dcbb 100644
--- a/include/hpp/fcl/profile.h
+++ b/include/hpp/fcl/profile.h
@@ -115,7 +115,7 @@ public:
   class ScopedBlock
   {
   public:
-    /// @brief Start counting time for the block named \e name of the profiler \e prof
+    /// @brief Start counting time for the block named @e name of the profiler @e prof
     ScopedBlock(const std::string &name, Profiler &prof = Profiler::Instance()) : name_(name), prof_(prof)
     {
       prof_.begin(name);
@@ -138,7 +138,7 @@ public:
   {
   public:
 
-    /// @brief Take as argument the profiler instance to operate on (\e prof)
+    /// @brief Take as argument the profiler instance to operate on (@e prof)
     ScopedStart(Profiler &prof = Profiler::Instance()) : prof_(prof), wasRunning_(prof_.running())
     {
       if (!wasRunning_)
diff --git a/include/hpp/fcl/shape/convex.h b/include/hpp/fcl/shape/convex.h
new file mode 100644
index 0000000000000000000000000000000000000000..cafbddd040b474fbab5204eb4c7d156869530db7
--- /dev/null
+++ b/include/hpp/fcl/shape/convex.h
@@ -0,0 +1,97 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2011-2014, Willow Garage, Inc.
+ *  Copyright (c) 2014-2015, Open Source Robotics Foundation
+ *  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 Open Source Robotics Foundation 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 Jia Pan */
+
+
+#ifndef HPP_FCL_SHAPE_CONVEX_H
+#define HPP_FCL_SHAPE_CONVEX_H
+
+#include <hpp/fcl/shape/geometric_shapes.h>
+
+namespace hpp
+{
+namespace fcl
+{
+
+/// @brief Convex polytope 
+/// @tparam PolygonT the polygon class. It must have method \c size() and
+///         \c operator[](int i)
+template <typename PolygonT>
+class Convex : public ConvexBase
+{
+public:
+  /// @brief Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information 
+  /// \param own_storage whether this class owns the pointers of points and
+  ///                    polygons. If owned, they are deleted upon destruction.
+  /// \param points_ list of 3D points
+  /// \param num_points_ number of 3D points
+  /// \param polygons_ \copydoc Convex::polygons
+  /// \param num_polygons_ the number of polygons.
+  /// \note num_polygons_ is not the allocated size of polygons_.
+  Convex(bool ownStorage,
+         Vec3f* points_, int num_points_,
+         PolygonT* polygons_, int num_polygons_);
+
+  /// @brief Copy constructor 
+  /// Only the list of neighbors is copied.
+  Convex(const Convex& other);
+
+  ~Convex();
+
+  /// @brief An array of PolygonT object.
+  /// PolygonT should contains a list of vertices for each polygon,
+  /// in counter clockwise order.
+  PolygonT* polygons;
+  int num_polygons;
+
+  /// based on http://number-none.com/blow/inertia/bb_inertia.doc
+  Matrix3f computeMomentofInertia() const;
+
+  Vec3f computeCOM() const;
+
+  FCL_REAL computeVolume() const;
+
+protected:
+  void fillNeighbors();
+};
+
+}
+
+} // namespace hpp
+
+#include <hpp/fcl/shape/details/convex.hxx>
+
+#endif
diff --git a/include/hpp/fcl/shape/details/convex.hxx b/include/hpp/fcl/shape/details/convex.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..b76eae2414acdf9ac5148488c6d782e500166a04
--- /dev/null
+++ b/include/hpp/fcl/shape/details/convex.hxx
@@ -0,0 +1,233 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2019, 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 Open Source Robotics Foundation 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 Joseph Mirabel */
+
+
+#ifndef HPP_FCL_SHAPE_CONVEX_HXX
+#define HPP_FCL_SHAPE_CONVEX_HXX
+
+#include <set>
+
+namespace hpp
+{
+namespace fcl
+{
+
+template <typename PolygonT>
+Convex<PolygonT>::Convex(bool own_storage, Vec3f* points_, int num_points_,
+       PolygonT* polygons_, int num_polygons_) :
+  ConvexBase(own_storage, points_, num_points_),
+  polygons     (polygons_),
+  num_polygons (num_polygons_)
+{
+  fillNeighbors();
+}
+
+template <typename PolygonT>
+Convex<PolygonT>::Convex(const Convex<PolygonT>& other) :
+  ConvexBase   (other),
+  polygons     (other.polygons),
+  num_polygons (other.num_polygons)
+{
+  if (own_storage_) {
+    polygons = new PolygonT[num_polygons];
+    memcpy(polygons, other.polygons, sizeof(PolygonT) * num_polygons);
+  }
+}
+
+template <typename PolygonT>
+Convex<PolygonT>::~Convex()
+{
+  if (own_storage_) delete [] polygons;
+}
+
+template <typename PolygonT>
+Matrix3f Convex<PolygonT>::computeMomentofInertia() const
+{
+  typedef typename PolygonT::size_type size_type;
+  typedef typename PolygonT::index_type index_type;
+  
+  Matrix3f C = Matrix3f::Zero();
+
+  Matrix3f C_canonical;
+  C_canonical << 1/60.0, 1/120.0, 1/120.0,
+                 1/120.0, 1/60.0, 1/120.0,
+                 1/120.0, 1/120.0, 1/60.0;
+
+  for(int i = 0; i < num_polygons; ++i)
+  {
+    const PolygonT& polygon (polygons[i]);
+
+    // compute the center of the polygon
+    Vec3f plane_center(0,0,0);
+    for(size_type j = 0; j < polygon.size(); ++j)
+      plane_center += points[polygon[j]];
+    plane_center /= polygon.size();
+
+    // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape
+    const Vec3f& v3 = plane_center;
+    for(size_type j = 0; j < polygon.size(); ++j)
+    {
+      index_type e_first = polygon[j];
+      index_type e_second = polygon[(j+1)%polygon.size()];
+      const Vec3f& v1 = points[e_first];
+      const Vec3f& v2 = points[e_second];
+      Matrix3f A; A << v1.transpose(), v2.transpose(), v3.transpose(); // this is A' in the original document
+      C += A.transpose() * C_canonical * A * (v1.cross(v2)).dot(v3);
+    }
+  }
+
+  return C.trace() * Matrix3f::Identity() - C;
+}
+
+template <typename PolygonT>
+Vec3f Convex<PolygonT>::computeCOM() const
+{
+  typedef typename PolygonT::size_type size_type;
+  typedef typename PolygonT::index_type index_type;
+
+  Vec3f com(0,0,0);
+  FCL_REAL vol = 0;
+  for(int i = 0; i < num_polygons; ++i)
+  {
+    const PolygonT& polygon (polygons[i]);
+    // compute the center of the polygon
+    Vec3f plane_center(0,0,0);
+    for(size_type j = 0; j < polygon.size(); ++j)
+      plane_center += points[polygon[j]];
+    plane_center /= polygon.size();
+
+    // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape
+    const Vec3f& v3 = plane_center;
+    for(size_type j = 0; j < polygon.size(); ++j)
+    {
+      index_type e_first = polygon[j];
+      index_type e_second = polygon[(j+1)%polygon.size()];
+      const Vec3f& v1 = points[e_first];
+      const Vec3f& v2 = points[e_second];
+      FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3);
+      vol += d_six_vol;
+      com += (points[e_first] + points[e_second] + plane_center) * d_six_vol;
+    }
+  }
+
+  return com / (vol * 4); // here we choose zero as the reference
+}
+
+template <typename PolygonT>
+FCL_REAL Convex<PolygonT>::computeVolume() const
+{
+  typedef typename PolygonT::size_type size_type;
+  typedef typename PolygonT::index_type index_type;
+
+  FCL_REAL vol = 0;
+  for(int i = 0; i < num_polygons; ++i)
+  {
+    const PolygonT& polygon (polygons[i]);
+
+    // compute the center of the polygon
+    Vec3f plane_center(0,0,0);
+    for(size_type j = 0; j < polygon.size(); ++j)
+      plane_center += points[polygon[j]];
+    plane_center /= polygon.size();
+
+    // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero point) of the convex shape
+    const Vec3f& v3 = plane_center;
+    for(size_type j = 0; j < polygon.size(); ++j)
+    {
+      index_type e_first = polygon[j];
+      index_type e_second = polygon[(j+1)%polygon.size()];
+      const Vec3f& v1 = points[e_first];
+      const Vec3f& v2 = points[e_second];
+      FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3);
+      vol += d_six_vol;
+    }
+  }
+
+  return vol / 6;
+}
+
+template <typename PolygonT>
+void Convex<PolygonT>::fillNeighbors()
+{
+  neighbors = new Neighbors[num_points];
+
+  typedef typename PolygonT::size_type size_type;
+  typedef typename PolygonT::index_type index_type;
+  std::vector<std::set<index_type> > nneighbors (num_points);
+  unsigned int c_nneighbors = 0;
+
+  for (int l = 0; l < num_polygons; ++l)
+  {
+    const PolygonT& polygon (polygons[l]);
+    size_type n = polygon.size();
+
+    for(size_type j = 0; j < polygon.size(); ++j)
+    {
+      size_type i = (j==0  ) ? n-1 : j-1;
+      size_type k = (j==n-1) ? 0   : j+1;
+      index_type pi = polygon[i],
+                 pj = polygon[j],
+                 pk = polygon[k];
+      // Update neighbors of pj;
+      if (nneighbors[pj].count(pi) == 0) {
+        c_nneighbors++;
+        nneighbors[pj].insert(pi);
+      }
+      if (nneighbors[pj].count(pk) == 0) {
+        c_nneighbors++;
+        nneighbors[pj].insert(pk);
+      }
+    }
+  }
+
+  nneighbors_ = new unsigned int[c_nneighbors];
+  unsigned int* p_nneighbors = nneighbors_;
+  for (int i = 0; i < num_points; ++i) {
+    Neighbors& n = neighbors[i];
+    if (nneighbors[i].size() >= std::numeric_limits<unsigned char>::max())
+      throw std::logic_error ("Too many neighbors.");
+    n.count_ = (unsigned char)nneighbors[i].size();
+    n.n_     = p_nneighbors;
+    p_nneighbors = std::copy (nneighbors[i].begin(), nneighbors[i].end(), p_nneighbors);
+  }
+  assert (p_nneighbors == nneighbors_ + c_nneighbors);
+}
+
+}
+
+} // namespace hpp
+
+#endif
diff --git a/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h b/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h
index f50309a01012cdbf2c9bf2158c7e2f917ead3549..5307014ad0762d4d83d8f6473a2ebfb0513a1dfc 100644
--- a/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h
+++ b/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h
@@ -52,30 +52,30 @@ namespace fcl
 template<typename BV>
 void generateBVHModel(BVHModel<BV>& model, const Box& shape, const Transform3f& pose)
 {
-  double a = shape.side[0];
-  double b = shape.side[1];
-  double c = shape.side[2];
+  double a = shape.halfSide[0];
+  double b = shape.halfSide[1];
+  double c = shape.halfSide[2];
   std::vector<Vec3f> points(8);
-  std::vector<Triangle> tri_indices(12);
-  points[0] << 0.5 * a, -0.5 * b, 0.5 * c;
-  points[1] << 0.5 * a, 0.5 * b, 0.5 * c;
-  points[2] << -0.5 * a, 0.5 * b, 0.5 * c;
-  points[3] << -0.5 * a, -0.5 * b, 0.5 * c;
-  points[4] << 0.5 * a, -0.5 * b, -0.5 * c;
-  points[5] << 0.5 * a, 0.5 * b, -0.5 * c;
-  points[6] << -0.5 * a, 0.5 * b, -0.5 * c;
-  points[7] << -0.5 * a, -0.5 * b, -0.5 * c;
-
-  tri_indices[0].set(0, 4, 1);
-  tri_indices[1].set(1, 4, 5);
-  tri_indices[2].set(2, 6, 3);
-  tri_indices[3].set(3, 6, 7);
-  tri_indices[4].set(3, 0, 2);
-  tri_indices[5].set(2, 0, 1);
-  tri_indices[6].set(6, 5, 7);
-  tri_indices[7].set(7, 5, 4);
-  tri_indices[8].set(1, 5, 2);
-  tri_indices[9].set(2, 5, 6);
+  Triangle tri_indices[12];
+  points[0] = Vec3f ( a, -b,  c);
+  points[1] = Vec3f ( a,  b,  c);
+  points[2] = Vec3f (-a,  b,  c);
+  points[3] = Vec3f (-a, -b,  c);
+  points[4] = Vec3f ( a, -b, -c);
+  points[5] = Vec3f ( a,  b, -c);
+  points[6] = Vec3f (-a,  b, -c);
+  points[7] = Vec3f (-a, -b, -c);
+
+  tri_indices[ 0].set(0, 4, 1);
+  tri_indices[ 1].set(1, 4, 5);
+  tri_indices[ 2].set(2, 6, 3);
+  tri_indices[ 3].set(3, 6, 7);
+  tri_indices[ 4].set(3, 0, 2);
+  tri_indices[ 5].set(2, 0, 1);
+  tri_indices[ 6].set(6, 5, 7);
+  tri_indices[ 7].set(7, 5, 4);
+  tri_indices[ 8].set(1, 5, 2);
+  tri_indices[ 9].set(2, 5, 6);
   tri_indices[10].set(3, 7, 0);
   tri_indices[11].set(0, 7, 4);
 
diff --git a/include/hpp/fcl/shape/geometric_shapes.h b/include/hpp/fcl/shape/geometric_shapes.h
index 87723bbd4df6a1b9b5cb5fb1aff37bc337c0e27f..d991f4e02f0e1d81813fad1bb50c5458e485c84e 100644
--- a/include/hpp/fcl/shape/geometric_shapes.h
+++ b/include/hpp/fcl/shape/geometric_shapes.h
@@ -42,7 +42,7 @@
 #include <boost/math/constants/constants.hpp>
 
 #include <hpp/fcl/collision_object.h>
-#include <hpp/fcl/math/vec_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <string.h>
 
 namespace hpp
@@ -56,10 +56,16 @@ class ShapeBase : public CollisionGeometry
 public:
   ShapeBase() {}
 
+  virtual ~ShapeBase () {};
+
   /// @brief Get object type: a geometric shape
   OBJECT_TYPE getObjectType() const { return OT_GEOM; }
 };
 
+/// @defgroup Geometric_Shapes
+/// regroup class of differents types of geometric shapes.
+/// @{
+
 /// @brief Triangle stores the points instead of only indices of points
 class TriangleP : public ShapeBase
 {
@@ -80,18 +86,18 @@ public:
 class Box : public ShapeBase
 {
 public:
-  Box(FCL_REAL x, FCL_REAL y, FCL_REAL z) : ShapeBase(), side(x, y, z)
+  Box(FCL_REAL x, FCL_REAL y, FCL_REAL z) : ShapeBase(), halfSide(x/2, y/2, z/2)
   {
   }
 
-  Box(const Vec3f& side_) : ShapeBase(), side(side_) 
+  Box(const Vec3f& side_) : ShapeBase(), halfSide(side_/2) 
   {
   }
 
   Box() {}
 
-  /// @brief box side length
-  Vec3f side;
+  /// @brief box side half-length
+  Vec3f halfSide;
 
   /// @brief Compute AABB
   void computeLocalAABB();
@@ -101,18 +107,14 @@ public:
 
   FCL_REAL computeVolume() const
   {
-    return side[0] * side[1] * side[2];
+    return 8*halfSide.prod();
   }
 
   Matrix3f computeMomentofInertia() const
   {
     FCL_REAL V = computeVolume();
-    FCL_REAL a2 = side[0] * side[0] * V;
-    FCL_REAL b2 = side[1] * side[1] * V;
-    FCL_REAL c2 = side[2] * side[2] * V;
-    return (Matrix3f() << (b2 + c2) / 12, 0, 0,
-                          0, (a2 + c2) / 12, 0,
-                          0, 0, (a2 + b2) / 12).finished();
+    Vec3f s (halfSide.cwiseAbs2() * V);
+    return (Vec3f (s[1] + s[2], s[0] + s[2], s[0] + s[1]) / 3).asDiagonal();
   }
 };
 
@@ -149,15 +151,16 @@ public:
 class Capsule : public ShapeBase
 {
 public:
-  Capsule(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_)
+  Capsule(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_)
   {
+    halfLength = lz_/2;
   }
 
   /// @brief Radius of capsule 
   FCL_REAL radius;
 
-  /// @brief Length along z axis 
-  FCL_REAL lz;
+  /// @brief Half Length along z axis 
+  FCL_REAL halfLength;
 
   /// @brief Compute AABB 
   void computeLocalAABB();
@@ -167,15 +170,15 @@ public:
 
   FCL_REAL computeVolume() const
   {
-    return boost::math::constants::pi<FCL_REAL>() * radius * radius *(lz + radius * 4/3.0);
+    return boost::math::constants::pi<FCL_REAL>() * radius * radius *((halfLength * 2) + radius * 4/3.0);
   }
 
   Matrix3f computeMomentofInertia() const
   {
-    FCL_REAL v_cyl = radius * radius * lz * boost::math::constants::pi<FCL_REAL>();
+    FCL_REAL v_cyl = radius * radius * (halfLength * 2) * boost::math::constants::pi<FCL_REAL>();
     FCL_REAL v_sph = radius * radius * radius * boost::math::constants::pi<FCL_REAL>() * 4 / 3.0;
     
-    FCL_REAL ix = v_cyl * lz * lz / 12.0 + 0.25 * v_cyl * radius + 0.4 * v_sph * radius * radius + 0.25 * v_sph * lz * lz;
+    FCL_REAL ix = v_cyl * halfLength * halfLength / 3. + 0.25 * v_cyl * radius + 0.4 * v_sph * radius * radius + v_sph * halfLength * halfLength;
     FCL_REAL iz = (0.5 * v_cyl + 0.4 * v_sph) * radius * radius;
 
     return (Matrix3f() << ix, 0, 0,
@@ -189,15 +192,16 @@ public:
 class Cone : public ShapeBase
 {
 public:
-  Cone(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_)
+  Cone(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_)
   {
+    halfLength = lz_/2;
   }
 
   /// @brief Radius of the cone 
   FCL_REAL radius;
 
-  /// @brief Length along z axis 
-  FCL_REAL lz;
+  /// @brief Half Length along z axis 
+  FCL_REAL halfLength;
 
   /// @brief Compute AABB 
   void computeLocalAABB();
@@ -207,13 +211,14 @@ public:
 
   FCL_REAL computeVolume() const
   {
-    return boost::math::constants::pi<FCL_REAL>() * radius * radius * lz / 3;
+    return boost::math::constants::pi<FCL_REAL>() * radius * radius * (halfLength * 2) / 3;
   }
 
+  /// \todo verify this formula as it seems different from https://en.wikipedia.org/wiki/List_of_moments_of_inertia#List_of_3D_inertia_tensors
   Matrix3f computeMomentofInertia() const
   {
     FCL_REAL V = computeVolume();
-    FCL_REAL ix = V * (0.1 * lz * lz + 3 * radius * radius / 20);
+    FCL_REAL ix = V * (0.4 * halfLength * halfLength + 3 * radius * radius / 20);
     FCL_REAL iz = 0.3 * V * radius * radius;
 
     return (Matrix3f() << ix, 0, 0,
@@ -223,7 +228,7 @@ public:
 
   Vec3f computeCOM() const
   {
-    return Vec3f(0, 0, -0.25 * lz);
+    return Vec3f(0, 0, -0.5 * halfLength);
   }
 };
 
@@ -231,16 +236,16 @@ public:
 class Cylinder : public ShapeBase
 {
 public:
-  Cylinder(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_)
+  Cylinder(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_)
   {
+    halfLength = lz_/2;
   }
-
   
   /// @brief Radius of the cylinder 
   FCL_REAL radius;
 
-  /// @brief Length along z axis 
-  FCL_REAL lz;
+  /// @brief Half Length along z axis 
+  FCL_REAL halfLength;
 
   /// @brief Compute AABB 
   void computeLocalAABB();
@@ -250,13 +255,13 @@ public:
 
   FCL_REAL computeVolume() const
   {
-    return boost::math::constants::pi<FCL_REAL>() * radius * radius * lz;
+    return boost::math::constants::pi<FCL_REAL>() * radius * radius * (halfLength * 2);
   }
 
   Matrix3f computeMomentofInertia() const
   {
     FCL_REAL V = computeVolume();
-    FCL_REAL ix = V * (3 * radius * radius + lz * lz) / 12;
+    FCL_REAL ix = V * (radius * radius / 4 + halfLength * halfLength / 3);
     FCL_REAL iz = V * radius * radius / 2;
     return (Matrix3f() << ix, 0, 0,
                           0, ix, 0,
@@ -264,54 +269,13 @@ public:
   }
 };
 
-/// @brief Convex polytope 
-class Convex : public ShapeBase
+/// @brief Base for convex polytope.
+/// @note Inherited classes are responsible for filling ConvexBase::neighbors;
+class ConvexBase : public ShapeBase
 {
 public:
-  /// @brief Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information 
-  /// \param points_ list of 3D points
-  /// \param num_points_ number of 3D points
-  /// \param polygons_ \copydoc Convex::polygons
-  /// \param num_polygons_ the number of polygons.
-  /// \note num_polygons_ is not the allocated size of polygons_.
-  Convex(Vec3f* points_,
-         int num_points_,
-         int* polygons_,
-         int num_polygons_) : ShapeBase()
-  {
-    num_polygons = num_polygons_;
-    points = points_;
-    num_points = num_points_;
-    polygons = polygons_;
-    edges = NULL;
-
-    Vec3f sum (0,0,0);
-    for(int i = 0; i < num_points; ++i)
-    {
-      sum += points[i];
-    }
 
-    center = sum * (FCL_REAL)(1.0 / num_points);
-
-    fillEdges();
-  }
-
-  /// @brief Copy constructor 
-  Convex(const Convex& other) : ShapeBase(other)
-  {
-    num_polygons = other.num_polygons;
-    points = other.points;
-    num_points = other.num_points;
-    polygons = other.polygons;
-    num_edges = other.num_edges;
-    edges = new Edge[num_edges];
-    memcpy(edges, other.edges, sizeof(Edge) * num_edges);
-  }
-
-  ~Convex()
-  {
-    delete [] edges;
-  }
+  virtual ~ConvexBase();
 
   /// @brief Compute AABB 
   void computeLocalAABB();
@@ -319,141 +283,46 @@ public:
   /// @brief Get node type: a conex polytope 
   NODE_TYPE getNodeType() const { return GEOM_CONVEX; }
 
-  /// @brief An array of indices to the points of each polygon, it should be the number of vertices
-  /// followed by that amount of indices to "points" in counter clockwise order
-  int* polygons;
-
+  /// @brief An array of the points of the polygon.
   Vec3f* points;
   int num_points;
-  int num_edges;
-  int num_polygons;
 
-  struct Edge
+  struct Neighbors
   {
-    int first, second;
-  };
+    unsigned char count_;
+    unsigned int* n_;
 
-  Edge* edges;
+    unsigned char const& count () const { return count_; }
+    unsigned int      & operator[] (int i)       { assert(i<count_); return n_[i]; }
+    unsigned int const& operator[] (int i) const { assert(i<count_); return n_[i]; }
+  };
+  /// Neighbors of each vertex.
+  /// It is an array of size num_points. For each vertex, it contains the number
+  /// of neighbors and a list of indices to them.
+  Neighbors* neighbors;
 
   /// @brief center of the convex polytope, this is used for collision: center is guaranteed in the internal of the polytope (as it is convex) 
   Vec3f center;
 
-  /// based on http://number-none.com/blow/inertia/bb_inertia.doc
-  Matrix3f computeMomentofInertia() const
-  {
-    
-    Matrix3f C = Matrix3f::Zero();
-
-    Matrix3f C_canonical;
-    C_canonical << 1/60.0, 1/120.0, 1/120.0,
-                   1/120.0, 1/60.0, 1/120.0,
-                   1/120.0, 1/120.0, 1/60.0;
-
-    int* points_in_poly = polygons;
-    int* index = polygons + 1;
-    for(int i = 0; i < num_polygons; ++i)
-    {
-      Vec3f plane_center(0,0,0);
-
-      // compute the center of the polygon
-      for(int j = 0; j < *points_in_poly; ++j)
-        plane_center += points[index[j]];
-      plane_center = plane_center * (1.0 / *points_in_poly);
-
-      // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape
-      const Vec3f& v3 = plane_center;
-      for(int j = 0; j < *points_in_poly; ++j)
-      {
-        int e_first = index[j];
-        int e_second = index[(j+1)%*points_in_poly];
-        const Vec3f& v1 = points[e_first];
-        const Vec3f& v2 = points[e_second];
-        Matrix3f A; A << v1.transpose(), v2.transpose(), v3.transpose(); // this is A' in the original document
-        C += A.derived().transpose() * C_canonical * A * (v1.cross(v2)).dot(v3);
-      }
-      
-      points_in_poly += (*points_in_poly + 1);
-      index = points_in_poly + 1;
-    }
-
-    return C.trace() * Matrix3f::Identity() - C;
-  }
+protected:
+  /// @brief Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information 
+  /// \param points_ list of 3D points
+  /// \param num_points_ number of 3D points
+  ConvexBase(bool ownStorage, Vec3f* points_, int num_points_);
 
-  Vec3f computeCOM() const
-  {
-    Vec3f com(0,0,0);
-    FCL_REAL vol = 0;
-    int* points_in_poly = polygons;
-    int* index = polygons + 1;
-    for(int i = 0; i < num_polygons; ++i)
-    {
-      Vec3f plane_center(0,0,0);
-
-      // compute the center of the polygon
-      for(int j = 0; j < *points_in_poly; ++j)
-        plane_center += points[index[j]];
-      plane_center = plane_center * (1.0 / *points_in_poly);
-
-      // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape
-      const Vec3f& v3 = plane_center;
-      for(int j = 0; j < *points_in_poly; ++j)
-      {
-        int e_first = index[j];
-        int e_second = index[(j+1)%*points_in_poly];
-        const Vec3f& v1 = points[e_first];
-        const Vec3f& v2 = points[e_second];
-        FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3);
-        vol += d_six_vol;
-        com += (points[e_first] + points[e_second] + plane_center) * d_six_vol;
-      }
-      
-      points_in_poly += (*points_in_poly + 1);
-      index = points_in_poly + 1;
-    }
-
-    return com / (vol * 4); // here we choose zero as the reference
-  }
+  /// @brief Copy constructor 
+  /// Only the list of neighbors is copied.
+  ConvexBase(const ConvexBase& other);
 
-  FCL_REAL computeVolume() const
-  {
-    FCL_REAL vol = 0;
-    int* points_in_poly = polygons;
-    int* index = polygons + 1;
-    for(int i = 0; i < num_polygons; ++i)
-    {
-      Vec3f plane_center(0,0,0);
-
-      // compute the center of the polygon
-      for(int j = 0; j < *points_in_poly; ++j)
-        plane_center += points[index[j]];
-      plane_center = plane_center * (1.0 / *points_in_poly);
-
-      // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero point) of the convex shape
-      const Vec3f& v3 = plane_center;
-      for(int j = 0; j < *points_in_poly; ++j)
-      {
-        int e_first = index[j];
-        int e_second = index[(j+1)%*points_in_poly];
-        const Vec3f& v1 = points[e_first];
-        const Vec3f& v2 = points[e_second];
-        FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3);
-        vol += d_six_vol;
-      }
-      
-      points_in_poly += (*points_in_poly + 1);
-      index = points_in_poly + 1;
-    }
-
-    return vol / 6;
-  }
+  unsigned int* nneighbors_;
 
-  
+  bool own_storage_;
 
-protected:
-  /// @brief Get edge information 
-  void fillEdges();
+private:
+  void computeCenter();
 };
 
+template <typename PolygonT> class Convex;
 
 /// @brief Half Space: this is equivalent to the Plane in ODE. The separation plane is defined as n * x = d;
 /// Points in the negative side of the separation plane (i.e. {x | n * x < d}) are inside the half space and points
@@ -552,7 +421,6 @@ protected:
   void unitNormalTest();
 };
 
-
 }
 
 } // namespace hpp
diff --git a/include/hpp/fcl/shape/geometric_shapes_utility.h b/include/hpp/fcl/shape/geometric_shapes_utility.h
index bec2e05e97fb9212cbb017e7747f8ba6c0b4624b..b078f5e05f1702d49c733feb57d303a544286097 100644
--- a/include/hpp/fcl/shape/geometric_shapes_utility.h
+++ b/include/hpp/fcl/shape/geometric_shapes_utility.h
@@ -42,6 +42,7 @@
 #include <vector>
 #include <hpp/fcl/shape/geometric_shapes.h>
 #include <hpp/fcl/BV/BV.h>
+#include <hpp/fcl/internal/BV_fitter.h>
 
 namespace hpp
 {
@@ -57,7 +58,7 @@ std::vector<Vec3f> getBoundVertices(const Sphere& sphere, const Transform3f& tf)
 std::vector<Vec3f> getBoundVertices(const Capsule& capsule, const Transform3f& tf);
 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 ConvexBase& convex, const Transform3f& tf);
 std::vector<Vec3f> getBoundVertices(const TriangleP& triangle, const Transform3f& tf);
 } 
 /// @endcond
@@ -87,7 +88,7 @@ template<>
 void computeBV<AABB, Cylinder>(const Cylinder& s, const Transform3f& tf, AABB& bv);
 
 template<>
-void computeBV<AABB, Convex>(const Convex& s, const Transform3f& tf, AABB& bv);
+void computeBV<AABB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, AABB& bv);
 
 template<>
 void computeBV<AABB, TriangleP>(const TriangleP& s, const Transform3f& tf, AABB& bv);
@@ -116,7 +117,7 @@ template<>
 void computeBV<OBB, Cylinder>(const Cylinder& s, const Transform3f& tf, OBB& bv);
 
 template<>
-void computeBV<OBB, Convex>(const Convex& s, const Transform3f& tf, OBB& bv);
+void computeBV<OBB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, OBB& bv);
 
 template<>
 void computeBV<OBB, Halfspace>(const Halfspace& s, const Transform3f& tf, OBB& bv);
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..270080ff5fba46aa5dcd260be20af0046b1519a5
--- /dev/null
+++ b/python/CMakeLists.txt
@@ -0,0 +1,61 @@
+#
+# Software License Agreement (BSD License)
+#
+#  Copyright (c) 2019 CNRS-LAAS
+#  Author: Joseph Mirabel
+#  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 CNRS-LAAS. 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.
+
+ADD_REQUIRED_DEPENDENCY("eigenpy >= 1.2")
+
+SET(LIBRARY_NAME hppfcl)
+
+INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}" ${PYTHON_INCLUDE_DIRS})
+
+ADD_LIBRARY(${LIBRARY_NAME} SHARED
+  version.cc
+  math.cc
+  collision-geometries.cc
+  collision.cc
+  distance.cc
+  fcl.cc)
+
+TARGET_LINK_BOOST_PYTHON(${LIBRARY_NAME})
+TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${Boost_LIBRARIES})
+TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${PROJECT_NAME})
+PKG_CONFIG_USE_DEPENDENCY(${LIBRARY_NAME} eigenpy)
+
+SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES
+  PREFIX ""
+  LIBRARY_OUTPUT_NAME ${LIBRARY_NAME})
+
+SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES SUFFIX "${PYTHON_EXT_SUFFIX}")
+
+INSTALL(TARGETS ${LIBRARY_NAME}
+  DESTINATION ${PYTHON_SITELIB})
diff --git a/python/collision-geometries.cc b/python/collision-geometries.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fc604318acd9736acdf852c41dd401b748700d40
--- /dev/null
+++ b/python/collision-geometries.cc
@@ -0,0 +1,244 @@
+//
+// Software License Agreement (BSD License)
+//
+//  Copyright (c) 2019 CNRS-LAAS
+//  Author: Joseph Mirabel
+//  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 CNRS-LAAS. 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.
+
+#include <boost/python.hpp>
+
+#include "fcl.hh"
+
+#include <hpp/fcl/fwd.hh>
+#include <hpp/fcl/shape/geometric_shapes.h>
+#include <hpp/fcl/shape/convex.h>
+#include <hpp/fcl/BVH/BVH_model.h>
+
+using namespace boost::python;
+
+using namespace hpp::fcl;
+using boost::shared_ptr;
+using boost::noncopyable;
+
+struct BVHModelBaseWrapper
+{
+  static Vec3f vertices (const BVHModelBase& bvh, int i)
+  {
+    if (i >= bvh.num_vertices) throw std::out_of_range("index is out of range");
+    return bvh.vertices[i];
+  }
+
+  static Triangle tri_indices (const BVHModelBase& bvh, int i)
+  {
+    if (i >= bvh.num_tris) throw std::out_of_range("index is out of range");
+    return bvh.tri_indices[i];
+  }
+};
+
+template <typename BV>
+void exposeBVHModel (const std::string& bvname)
+{
+  typedef BVHModel<BV> BVHModel_t;
+
+  std::string type = "BVHModel" + bvname;
+  class_ <BVHModel_t, bases<BVHModelBase>, shared_ptr<BVHModel_t> >
+    (type.c_str(), init<>())
+    ;
+}
+
+struct ConvexBaseWrapper
+{
+  static Vec3f points (const ConvexBase& convex, int i)
+  {
+    if (i >= convex.num_points) throw std::out_of_range("index is out of range");
+    return convex.points[i];
+  }
+
+  static list neighbors (const ConvexBase& convex, int i)
+  {
+    if (i >= convex.num_points) throw std::out_of_range("index is out of range");
+    list n;
+    for (unsigned char j = 0; j < convex.neighbors[i].count(); ++j)
+      n.append (convex.neighbors[i][j]);
+    return n;
+  }
+};
+
+template <typename PolygonT>
+struct ConvexWrapper
+{
+  typedef Convex<PolygonT> Convex_t;
+
+  static PolygonT polygons (const Convex_t& convex, int i)
+  {
+    if (i >= convex.num_polygons) throw std::out_of_range("index is out of range");
+    return convex.polygons[i];
+  }
+};
+
+void exposeShapes ()
+{
+  class_ <ShapeBase, bases<CollisionGeometry>, shared_ptr<ShapeBase>, noncopyable>
+    ("ShapeBase", no_init)
+    //.def ("getObjectType", &CollisionGeometry::getObjectType)
+    ;
+
+  class_ <Box, bases<ShapeBase>, shared_ptr<Box> >
+    ("Box", init<>())
+    .def (init<FCL_REAL,FCL_REAL,FCL_REAL>())
+    .def (init<Vec3f>())
+    .add_property("halfSide",
+                  make_getter(&Box::halfSide, return_value_policy<return_by_value>()),
+                  make_setter(&Box::halfSide, return_value_policy<return_by_value>()));
+    ;
+
+  class_ <Capsule, bases<ShapeBase>, shared_ptr<Capsule> >
+    ("Capsule", init<FCL_REAL, FCL_REAL>())
+    .def_readwrite ("radius", &Capsule::radius)
+    .def_readwrite ("halfLength", &Capsule::halfLength)
+    ;
+
+  class_ <Cone, bases<ShapeBase>, shared_ptr<Cone> >
+    ("Cone", init<FCL_REAL, FCL_REAL>())
+    .def_readwrite ("radius", &Cone::radius)
+    .def_readwrite ("halfLength", &Cone::halfLength)
+    ;
+
+  class_ <ConvexBase, bases<ShapeBase>, shared_ptr<ConvexBase >, noncopyable>
+    ("ConvexBase", no_init)
+    .def_readonly ("center", &ConvexBase::center)
+    .def_readonly ("num_points", &ConvexBase::num_points)
+    .def ("points", &ConvexBaseWrapper::points)
+    .def ("neighbors", &ConvexBaseWrapper::neighbors)
+    ;
+
+  class_ <Convex<Triangle>, bases<ConvexBase>, shared_ptr<Convex<Triangle> >, noncopyable>
+    ("Convex", no_init)
+    .def_readonly ("num_polygons", &Convex<Triangle>::num_polygons)
+    .def ("polygons", &ConvexWrapper<Triangle>::polygons)
+    ;
+
+  class_ <Cylinder, bases<ShapeBase>, shared_ptr<Cylinder> >
+    ("Cylinder", init<FCL_REAL, FCL_REAL>())
+    .def_readwrite ("radius", &Cylinder::radius)
+    .def_readwrite ("halfLength", &Cylinder::halfLength)
+    ;
+
+  class_ <Halfspace, bases<ShapeBase>, shared_ptr<Halfspace> >
+    ("Halfspace", "The half-space is defined by {x | n * x < d}.", init<const Vec3f&, FCL_REAL>())
+    .def (init<FCL_REAL,FCL_REAL,FCL_REAL,FCL_REAL>())
+    .def (init<>())
+    .def_readwrite ("n", &Halfspace::n)
+    .def_readwrite ("d", &Halfspace::d)
+    ;
+
+  class_ <Plane, bases<ShapeBase>, shared_ptr<Plane> >
+    ("Plane", "The plane is defined by {x | n * x = d}.", init<const Vec3f&, FCL_REAL>())
+    .def (init<FCL_REAL,FCL_REAL,FCL_REAL,FCL_REAL>())
+    .def (init<>())
+    .def_readwrite ("n", &Plane::n)
+    .def_readwrite ("d", &Plane::d)
+    ;
+
+  class_ <Sphere, bases<ShapeBase>, shared_ptr<Sphere> >
+    ("Sphere", init<FCL_REAL>())
+    .def_readwrite ("radius", &Sphere::radius)
+    ;
+
+  class_ <TriangleP, bases<ShapeBase>, shared_ptr<TriangleP> >
+    ("TriangleP", init<const Vec3f&, const Vec3f&, const Vec3f&>())
+    .def_readwrite ("a", &TriangleP::a)
+    .def_readwrite ("b", &TriangleP::b)
+    .def_readwrite ("c", &TriangleP::c)
+    ;
+
+}
+
+void exposeCollisionGeometries ()
+{
+  enum_<OBJECT_TYPE>("OBJECT_TYPE")
+    .value ("OT_UNKNOWN", OT_UNKNOWN)
+    .value ("OT_BVH"    , OT_BVH)
+    .value ("OT_GEOM"   , OT_GEOM)
+    .value ("OT_OCTREE" , OT_OCTREE)
+    ;
+  enum_<NODE_TYPE>("NODE_TYPE")
+    .value ("BV_UNKNOWN", BV_UNKNOWN)
+    .value ("BV_AABB"  , BV_AABB)
+    .value ("BV_OBB"   , BV_OBB)
+    .value ("BV_RSS"   , BV_RSS)
+    .value ("BV_kIOS"  , BV_kIOS)
+    .value ("BV_OBBRSS", BV_OBBRSS)
+    .value ("BV_KDOP16", BV_KDOP16)
+    .value ("BV_KDOP18", BV_KDOP18)
+    .value ("BV_KDOP24", BV_KDOP24)
+    .value ("GEOM_BOX"      , GEOM_BOX)
+    .value ("GEOM_SPHERE"   , GEOM_SPHERE)
+    .value ("GEOM_CAPSULE"  , GEOM_CAPSULE)
+    .value ("GEOM_CONE"     , GEOM_CONE)
+    .value ("GEOM_CYLINDER" , GEOM_CYLINDER)
+    .value ("GEOM_CONVEX"   , GEOM_CONVEX)
+    .value ("GEOM_PLANE"    , GEOM_PLANE)
+    .value ("GEOM_HALFSPACE", GEOM_HALFSPACE)
+    .value ("GEOM_TRIANGLE" , GEOM_TRIANGLE)
+    .value ("GEOM_OCTREE"   , GEOM_OCTREE)
+    ;
+
+  class_ <CollisionGeometry, CollisionGeometryPtr_t, noncopyable>
+    ("CollisionGeometry", no_init)
+    .def ("getObjectType", &CollisionGeometry::getObjectType)
+    .def ("getNodeType", &CollisionGeometry::getNodeType)
+
+    .def ("computeLocalAABB", &CollisionGeometry::computeLocalAABB)
+
+    .def ("computeCOM", &CollisionGeometry::computeCOM)
+    .def ("computeMomentofInertia", &CollisionGeometry::computeMomentofInertia)
+    .def ("computeVolume", &CollisionGeometry::computeVolume)
+    .def ("computeMomentofInertiaRelatedToCOM", &CollisionGeometry::computeMomentofInertiaRelatedToCOM)
+
+    .def_readwrite("aabb_radius",&CollisionGeometry::aabb_radius,"AABB radius")
+    ;
+
+  exposeShapes();
+
+  class_ <BVHModelBase, bases<CollisionGeometry>, BVHModelPtr_t, noncopyable>
+    ("BVHModelBase", no_init)
+    .def ("vertices", &BVHModelBaseWrapper::vertices)
+    .def ("tri_indices", &BVHModelBaseWrapper::tri_indices)
+    .def_readonly ("num_vertices", &BVHModelBase::num_vertices)
+    .def_readonly ("num_tris", &BVHModelBase::num_tris)
+
+    .def_readonly ("convex", &BVHModelBase::convex)
+
+    .def ("buildConvexRepresentation", &BVHModelBase::buildConvexRepresentation)
+    ;
+  exposeBVHModel<OBB    >("OBB"    );
+  exposeBVHModel<OBBRSS >("OBBRSS" );
+}
diff --git a/python/collision.cc b/python/collision.cc
new file mode 100644
index 0000000000000000000000000000000000000000..47be7f5eae7b7f463195fa3bedd509406d63ea89
--- /dev/null
+++ b/python/collision.cc
@@ -0,0 +1,105 @@
+//
+// Software License Agreement (BSD License)
+//
+//  Copyright (c) 2019 CNRS-LAAS
+//  Author: Joseph Mirabel
+//  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 CNRS-LAAS. 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.
+
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include "fcl.hh"
+
+#include <hpp/fcl/fwd.hh>
+#include <hpp/fcl/collision.h>
+
+using namespace boost::python;
+
+using namespace hpp::fcl;
+using boost::shared_ptr;
+using boost::noncopyable;
+
+void exposeCollisionAPI ()
+{
+  enum_ <CollisionRequestFlag> ("CollisionRequestFlag")
+    .value ("CONTACT", CONTACT)
+    .value ("DISTANCE_LOWER_BOUND", DISTANCE_LOWER_BOUND)
+    .value ("NO_REQUEST", NO_REQUEST)
+    ;
+
+  class_ <CollisionRequest> ("CollisionRequest", init<>())
+    .def (init<CollisionRequestFlag, size_t>())
+
+    .def_readwrite ("num_max_contacts"           , &CollisionRequest::num_max_contacts)
+    .def_readwrite ("enable_contact"             , &CollisionRequest::enable_contact)
+    .def_readwrite ("enable_distance_lower_bound", &CollisionRequest::enable_distance_lower_bound)
+    .def_readwrite ("enable_cached_gjk_guess"    , &CollisionRequest::enable_cached_gjk_guess)
+    .def_readwrite ("cached_gjk_guess"           , &CollisionRequest::cached_gjk_guess)
+    .def_readwrite ("security_margin"            , &CollisionRequest::security_margin)
+    .def_readwrite ("break_distance"             , &CollisionRequest::break_distance)
+    ;
+
+  class_ <Contact> ("Contact", init<>())
+    //.def(init<CollisionGeometryPtr_t, CollisionGeometryPtr_t, int, int>())
+    //.def(init<CollisionGeometryPtr_t, CollisionGeometryPtr_t, int, int, Vec3f, Vec3f, FCL_REAL>())
+    .def_readonly ("o1", &Contact::o1)
+    .def_readonly ("o2", &Contact::o2)
+    .def_readwrite ("b1", &Contact::b1)
+    .def_readwrite ("b2", &Contact::b2)
+    .def_readwrite ("normal", &Contact::normal)
+    .def_readwrite ("pos", &Contact::pos)
+    .def_readwrite ("penetration_depth", &Contact::penetration_depth)
+    .def (self == self)
+    ;
+
+  class_< std::vector<Contact> >("StdVec_Contact")
+    .def(vector_indexing_suite< std::vector<Contact> >())
+    ;
+
+  class_ <CollisionResult> ("CollisionResult", init<>())
+    .def ("isCollision", &CollisionResult::isCollision)
+    .def ("numContacts", &CollisionResult::numContacts)
+    .def ("getContact" , &CollisionResult::getContact , return_value_policy<copy_const_reference>())
+    .def ("getContacts", &CollisionResult::getContacts, return_internal_reference<>())
+    .def ("addContact" , &CollisionResult::addContact )
+    .def ("clear", &CollisionResult::clear)
+    ;
+
+  class_< std::vector<CollisionResult> >("CollisionResult")
+    .def(vector_indexing_suite< std::vector<CollisionResult> >())
+    ;
+
+  def ("collide", static_cast< std::size_t (*)(const CollisionObject*, const CollisionObject*,
+        const CollisionRequest&, CollisionResult&) > (&collide));
+  def ("collide", static_cast< std::size_t (*)(
+        const CollisionGeometry*, const Transform3f&,
+        const CollisionGeometry*, const Transform3f&,
+        const CollisionRequest&, CollisionResult&) > (&collide));
+}
diff --git a/python/distance.cc b/python/distance.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d7ca2e8f096798c3ada63f15e8745af95a678ec9
--- /dev/null
+++ b/python/distance.cc
@@ -0,0 +1,87 @@
+//
+// Software License Agreement (BSD License)
+//
+//  Copyright (c) 2019 CNRS-LAAS
+//  Author: Joseph Mirabel
+//  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 CNRS-LAAS. 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.
+
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include "fcl.hh"
+
+#include <hpp/fcl/fwd.hh>
+#include <hpp/fcl/distance.h>
+
+using namespace boost::python;
+
+using namespace hpp::fcl;
+using boost::shared_ptr;
+using boost::noncopyable;
+
+struct DistanceRequestWrapper
+{
+  static Vec3f getNearestPoint1(const DistanceResult & res) { return res.nearest_points[0]; }
+  static Vec3f getNearestPoint2(const DistanceResult & res) { return res.nearest_points[1]; }
+};
+
+void exposeDistanceAPI ()
+{
+  class_ <DistanceRequest> ("DistanceRequest", init<optional<bool,FCL_REAL,FCL_REAL> >())
+    .def_readwrite ("enable_nearest_points", &DistanceRequest::enable_nearest_points)
+    .def_readwrite ("rel_err"              , &DistanceRequest::rel_err)
+    .def_readwrite ("abs_err"              , &DistanceRequest::abs_err)
+    ;
+
+  class_ <DistanceResult> ("DistanceResult", init<>())
+    .def_readwrite ("min_distance", &DistanceResult::min_distance)
+    .def_readwrite ("normal", &DistanceResult::normal)
+    //.def_readwrite ("nearest_points", &DistanceResult::nearest_points)
+    .def("getNearestPoint1",&DistanceRequestWrapper::getNearestPoint1)
+    .def("getNearestPoint2",&DistanceRequestWrapper::getNearestPoint2)
+    .def_readonly ("o1", &DistanceResult::o1)
+    .def_readonly ("o2", &DistanceResult::o2)
+    .def_readwrite ("b1", &DistanceResult::b1)
+    .def_readwrite ("b2", &DistanceResult::b2)
+
+    .def ("clear", &DistanceResult::clear)
+    ;
+
+  class_< std::vector<DistanceResult> >("StdVec_DistanceResult")
+    .def(vector_indexing_suite< std::vector<DistanceResult> >())
+    ;
+
+  def ("distance", static_cast< FCL_REAL (*)(const CollisionObject*, const CollisionObject*,
+        const DistanceRequest&, DistanceResult&) > (&distance));
+  def ("distance", static_cast< FCL_REAL (*)(
+        const CollisionGeometry*, const Transform3f&,
+        const CollisionGeometry*, const Transform3f&,
+        const DistanceRequest&, DistanceResult&) > (&distance));
+}
diff --git a/python/fcl.cc b/python/fcl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0aa4b104fb09dd6ff8a033237d409bd230483789
--- /dev/null
+++ b/python/fcl.cc
@@ -0,0 +1,71 @@
+//
+// Software License Agreement (BSD License)
+//
+//  Copyright (c) 2019 CNRS-LAAS
+//  Author: Joseph Mirabel
+//  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 CNRS-LAAS. 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.
+
+#include <boost/python.hpp>
+
+#include "fcl.hh"
+
+#include <hpp/fcl/fwd.hh>
+#include <hpp/fcl/shape/geometric_shapes.h>
+#include <hpp/fcl/BVH/BVH_model.h>
+
+#include <hpp/fcl/mesh_loader/loader.h>
+
+#include <hpp/fcl/collision.h>
+
+using namespace boost::python;
+
+using namespace hpp::fcl;
+using boost::shared_ptr;
+using boost::noncopyable;
+
+void exposeMeshLoader ()
+{
+  class_ <MeshLoader> ("MeshLoader", init< optional< NODE_TYPE> >())
+    .def ("load", static_cast <BVHModelPtr_t (MeshLoader::*) (const std::string&, const Vec3f&)> (&MeshLoader::load))
+    ;
+
+  class_ <CachedMeshLoader, bases<MeshLoader> > ("CachedMeshLoader", init< optional< NODE_TYPE> >())
+    ;
+}
+
+BOOST_PYTHON_MODULE(hppfcl)
+{
+  exposeVersion();
+  exposeMaths();
+  exposeCollisionGeometries();
+  exposeMeshLoader();
+  exposeCollisionAPI();
+  exposeDistanceAPI();
+}
diff --git a/python/fcl.hh b/python/fcl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f56b9d19ac5b479cfde2b25be9fc4e8ba492c951
--- /dev/null
+++ b/python/fcl.hh
@@ -0,0 +1,11 @@
+void exposeVersion();
+
+void exposeMaths();
+
+void exposeCollisionGeometries();
+
+void exposeMeshLoader();
+
+void exposeCollisionAPI();
+
+void exposeDistanceAPI();
diff --git a/python/math.cc b/python/math.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0b47a345ce5f938cbea72fb258be5ae67c05c119
--- /dev/null
+++ b/python/math.cc
@@ -0,0 +1,107 @@
+//
+// Software License Agreement (BSD License)
+//
+//  Copyright (c) 2019 CNRS-LAAS
+//  Author: Joseph Mirabel
+//  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 CNRS-LAAS. 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.
+
+#include <boost/python.hpp>
+
+#include <eigenpy/eigenpy.hpp>
+#include <eigenpy/geometry.hpp>
+
+#include <hpp/fcl/fwd.hh>
+#include <hpp/fcl/math/transform.h>
+
+#include "fcl.hh"
+
+using namespace boost::python;
+
+using namespace hpp::fcl;
+
+struct TriangleWrapper
+{
+  static Triangle::index_type getitem (const Triangle& t, int i)
+  {
+    if (i >= 3) throw std::out_of_range("index is out of range");
+    return t[i];
+  }
+  static void setitem (Triangle& t, int i, Triangle::index_type v)
+  {
+    if (i >= 3) throw std::out_of_range("index is out of range");
+    t[i] = v;
+  }
+};
+
+void exposeMaths ()
+{
+  eigenpy::enableEigenPy();
+
+  if(!eigenpy::register_symbolic_link_to_registered_type<Eigen::Quaterniond>())
+    eigenpy::exposeQuaternion();
+  if(!eigenpy::register_symbolic_link_to_registered_type<Eigen::AngleAxisd>())
+    eigenpy::exposeAngleAxis();
+
+  class_ <Transform3f> ("Transform3f", init<>())
+    .def (init<Matrix3f, Vec3f>())
+    .def (init<Quaternion3f, Vec3f>())
+    .def (init<Matrix3f>())
+    .def (init<Quaternion3f>())
+    .def (init<Vec3f>())
+
+    .def ("getQuatRotation", &Transform3f::getQuatRotation)
+    .def ("getTranslation", &Transform3f::getTranslation, return_value_policy<copy_const_reference>())
+    .def ("getRotation", &Transform3f::getRotation, return_value_policy<copy_const_reference>())
+    .def ("isIdentity", &Transform3f::setIdentity)
+
+    .def ("setQuatRotation", &Transform3f::setQuatRotation)
+    .def ("setTranslation", &Transform3f::setTranslation<Vec3f>)
+    .def ("setRotation", &Transform3f::setRotation<Matrix3f>)
+    .def ("setTransform", &Transform3f::setTransform<Matrix3f,Vec3f>)
+    .def ("setTransform", static_cast<void (Transform3f::*)(const Quaternion3f&, const Vec3f&)>(&Transform3f::setTransform))
+    .def ("setIdentity", &Transform3f::setIdentity)
+
+    .def ("transform", &Transform3f::transform<Vec3f>)
+    .def ("inverseInPlace", &Transform3f::inverseInPlace, return_internal_reference<>())
+    .def ("inverse", &Transform3f::inverse)
+    .def ("inverseTimes", &Transform3f::inverseTimes)
+
+    .def (self * self)
+    .def (self *= self)
+    .def (self == self)
+    .def (self != self)
+    ;
+
+  class_ <Triangle> ("Triangle", init<>())
+    .def (init <Triangle::index_type, Triangle::index_type, Triangle::index_type>())
+    .def ("__getitem__", &TriangleWrapper::getitem)
+    .def ("__setitem__", &TriangleWrapper::setitem)
+    ;
+}
diff --git a/python/version.cc b/python/version.cc
new file mode 100644
index 0000000000000000000000000000000000000000..886493d122e5b400699d6f9e376477e067c78017
--- /dev/null
+++ b/python/version.cc
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2019 CNRS
+//
+
+#include "hpp/fcl/config.hh"
+#include <boost/python.hpp>
+#include <boost/preprocessor/stringize.hpp>
+
+namespace bp = boost::python;
+
+inline bool checkVersionAtLeast(unsigned int major,
+                                unsigned int minor,
+                                unsigned int patch)
+{
+  return HPP_FCL_VERSION_AT_LEAST(major, minor, patch);
+}
+
+inline bool checkVersionAtMost(unsigned int major,
+                               unsigned int minor,
+                               unsigned int patch)
+{
+  return HPP_FCL_VERSION_AT_MOST(major, minor, patch);
+}
+
+void exposeVersion()
+{
+  // Define release numbers of the current hpp-fcl version.
+  bp::scope().attr("__version__") = BOOST_PP_STRINGIZE(HPP_FCL_MAJOR_VERSION) "."
+    BOOST_PP_STRINGIZE(HPP_FCL_MINOR_VERSION) "."
+    BOOST_PP_STRINGIZE(HPP_FCL_PATCH_VERSION);
+  bp::scope().attr("HPP_FCL_MAJOR_VERSION") = HPP_FCL_MAJOR_VERSION;
+  bp::scope().attr("HPP_FCL_MINOR_VERSION") = HPP_FCL_MINOR_VERSION;
+  bp::scope().attr("HPP_FCL_PATCH_VERSION") = HPP_FCL_PATCH_VERSION;
+
+  bp::def("checkVersionAtLeast",&checkVersionAtLeast,
+          bp::args("major","minor","patch"),
+          "Checks if the current version of hpp-fcl is at least"
+          " the version provided by the input arguments.");
+
+  bp::def("checkVersionAtMost",&checkVersionAtMost,
+          bp::args("major","minor","patch"),
+          "Checks if the current version of hpp-fcl is at most"
+          " the version provided by the input arguments.");
+}
diff --git a/src/BV/AABB.cpp b/src/BV/AABB.cpp
index 782e0bc16b778e3a31ad3b92acdd95a1671679a6..e9829aae6756b48c1f554579b8b68dcc37312f44 100644
--- a/src/BV/AABB.cpp
+++ b/src/BV/AABB.cpp
@@ -38,7 +38,7 @@
 #include <hpp/fcl/BV/AABB.h>
 
 #include <limits>
-#include <iostream>
+#include <hpp/fcl/collision_data.h>
 
 namespace hpp
 {
@@ -50,6 +50,21 @@ AABB::AABB() : min_(Vec3f::Constant(std::numeric_limits<FCL_REAL>::max())),
 {
 }
 
+bool AABB::overlap(const AABB& other, const CollisionRequest& request,
+                    FCL_REAL& sqrDistLowerBound) const
+{
+  const FCL_REAL breakDistance (request.break_distance + request.security_margin);
+  const FCL_REAL breakDistance2 = breakDistance * breakDistance;
+
+  sqrDistLowerBound = (min_ - other.max_).array().max(0).matrix().squaredNorm();
+  if(sqrDistLowerBound > breakDistance2) return false;
+
+  sqrDistLowerBound = (other.min_ - max_).array().max(0).matrix().squaredNorm();
+  if(sqrDistLowerBound > breakDistance2) return false;
+
+  return true;
+}
+
 FCL_REAL AABB::distance(const AABB& other, Vec3f* P, Vec3f* Q) const
 {
   FCL_REAL result = 0;
diff --git a/src/BV/OBB.cpp b/src/BV/OBB.cpp
index 4cf4c49d40a16fc032172a6ea66799887a8c7805..98a45f4668fbd81d847f37745575fd166bcedb77 100644
--- a/src/BV/OBB.cpp
+++ b/src/BV/OBB.cpp
@@ -39,6 +39,7 @@
 #include <hpp/fcl/BVH/BVH_utility.h>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/collision_data.h>
+#include <hpp/fcl/internal/tools.h>
 
 #include <iostream>
 #include <limits>
@@ -294,6 +295,71 @@ bool obbDisjoint(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f&
 
 }
 
+namespace internal
+{
+  inline FCL_REAL obbDisjoint_check_A_axis (
+      const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf)
+  {
+    // |T| - |B| * b - a
+    Vec3f AABB_corner (T.cwiseAbs () - a);
+    AABB_corner.noalias() -= Bf.col(0) * b[0];
+    AABB_corner.noalias() -= Bf.col(1) * b[1];
+    AABB_corner.noalias() -= Bf.col(2) * b[2];
+    return AABB_corner.array().max(0).matrix().squaredNorm ();
+  }
+
+  inline FCL_REAL obbDisjoint_check_B_axis (
+      const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf)
+  {
+    // Bf = |B|
+    // | B^T T| - Bf^T * a - b
+    register FCL_REAL s, t = 0;
+    s = std::abs(B.col(0).dot(T)) - Bf.col(0).dot(a) - b[0];
+    if (s > 0) t += s*s;
+    s = std::abs(B.col(1).dot(T)) - Bf.col(1).dot(a) - b[1];
+    if (s > 0) t += s*s;
+    s = std::abs(B.col(2).dot(T)) - Bf.col(2).dot(a) - b[2];
+    if (s > 0) t += s*s;
+    return t;
+  }
+
+  template <int ib, int jb = (ib+1)%3, int kb = (ib+2)%3 >
+  struct obbDisjoint_check_Ai_cross_Bi
+  {
+    static inline bool run (int ia, int ja, int ka,
+        const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b,
+        const Matrix3f& Bf,
+        const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+    {
+      const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
+
+      const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
+                                       b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
+      // We need to divide by the norm || Aia x Bib ||
+      // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
+      if (diff > 0) {
+        FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+        if (sinus2 > 1e-6) {
+          squaredLowerBoundDistance = diff * diff / sinus2;
+          if (squaredLowerBoundDistance > breakDistance2) {
+            return true;
+          }
+        }
+        /* // or
+           FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+           squaredLowerBoundDistance = diff * diff;
+           if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
+           squaredLowerBoundDistance /= sinus2;
+           return true;
+           }
+        // */
+      }
+      return false;
+    }
+  };
+}
+
+
 // B, T orientation and position of 2nd OBB in frame of 1st OBB,
 // a extent of 1st OBB,
 // b extent of 2nd OBB.
@@ -301,193 +367,39 @@ bool obbDisjoint(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f&
 // This function tests whether bounding boxes should be broken down.
 //
 bool obbDisjointAndLowerBoundDistance (const Matrix3f& B, const Vec3f& T,
-				       const Vec3f& a, const Vec3f& b,
+                                       const Vec3f& a, const Vec3f& b,
                                        const CollisionRequest& request,
-				       FCL_REAL& squaredLowerBoundDistance)
+                                       FCL_REAL& squaredLowerBoundDistance)
 {
-  FCL_REAL t, s;
-  FCL_REAL diff;
-  FCL_REAL breakDistance (request.break_distance + request.security_margin);
-  FCL_REAL breakDistance2 = breakDistance * breakDistance;
+  const FCL_REAL breakDistance (request.break_distance + request.security_margin);
+  const FCL_REAL breakDistance2 = breakDistance * breakDistance;
 
-  // Matrix3f Bf = abs(B);
-  // Bf += reps;
   Matrix3f Bf (B.cwiseAbs());
 
   // Corner of b axis aligned bounding box the closest to the origin
-  Vec3f AABB_corner (T.cwiseAbs () - Bf * b);
-  Vec3f diff3 (AABB_corner - a);
-  diff3 = diff3.cwiseMax (Vec3f::Zero());
-
-  //for (Vec3f::Index i=0; i<3; ++i) diff3 [i] = std::max (0, diff3 [i]);
-  squaredLowerBoundDistance = diff3.squaredNorm ();
+  squaredLowerBoundDistance = internal::obbDisjoint_check_A_axis (T, a, b, Bf);
   if (squaredLowerBoundDistance > breakDistance2)
     return true;
 
-  AABB_corner = (B.transpose () * T).cwiseAbs ()  - Bf.transpose () * a;
-  // diff3 = | B^T T| - b - Bf^T a
-  diff3 = AABB_corner - b;
-  diff3 = diff3.cwiseMax (Vec3f::Zero());
-  squaredLowerBoundDistance = diff3.squaredNorm ();
-
+  squaredLowerBoundDistance = internal::obbDisjoint_check_B_axis (B, T, a, b, Bf);
   if (squaredLowerBoundDistance > breakDistance2)
     return true;
 
-  // A0 x B0
-  s = T[2] * B(1, 0) - T[1] * B(2, 0);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  FCL_REAL sinus2;
-  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) +
-	      b[1] * Bf(0, 2) + b[2] * Bf(0, 1));
-  // We need to divide by the norm || A0 x B0 ||
-  // As ||A0|| = ||B0|| = 1,
-  //              2            2
-  // || A0 x B0 ||  + (A0 | B0)  = 1
-  if (diff > 0) {
-    sinus2 = 1 - Bf (0,0) * Bf (0,0);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A0 x B1
-  s = T[2] * B(1, 1) - T[1] * B(2, 1);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) +
-	      b[0] * Bf(0, 2) + b[2] * Bf(0, 0));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (0,1) * Bf (0,1);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A0 x B2
-  s = T[2] * B(1, 2) - T[1] * B(2, 2);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) +
-	      b[0] * Bf(0, 1) + b[1] * Bf(0, 0));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (0,2) * Bf (0,2);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A1 x B0
-  s = T[0] * B(2, 0) - T[2] * B(0, 0);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) +
-	      b[1] * Bf(1, 2) + b[2] * Bf(1, 1));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (1,0) * Bf (1,0);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A1 x B1
-  s = T[0] * B(2, 1) - T[2] * B(0, 1);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) +
-	      b[0] * Bf(1, 2) + b[2] * Bf(1, 0));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (1,1) * Bf (1,1);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A1 x B2
-  s = T[0] * B(2, 2) - T[2] * B(0, 2);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) +
-	      b[0] * Bf(1, 1) + b[1] * Bf(1, 0));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (1,2) * Bf (1,2);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A2 x B0
-  s = T[1] * B(0, 0) - T[0] * B(1, 0);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) +
-	      b[1] * Bf(2, 2) + b[2] * Bf(2, 1));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (2,0) * Bf (2,0);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A2 x B1
-  s = T[1] * B(0, 1) - T[0] * B(1, 1);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) +
-	      b[0] * Bf(2, 2) + b[2] * Bf(2, 0));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (2,1) * Bf (2,1);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
-  }
-
-  // A2 x B2
-  s = T[1] * B(0, 2) - T[0] * B(1, 2);
-  t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
-
-  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) +
-	      b[0] * Bf(2, 1) + b[1] * Bf(2, 0));
-  if (diff > 0) {
-    sinus2 = 1 - Bf (2,2) * Bf (2,2);
-    if (sinus2 > 1e-6) {
-      squaredLowerBoundDistance = diff * diff / sinus2;
-      if (squaredLowerBoundDistance > breakDistance2) {
-	return true;
-      }
-    }
+  // Ai x Bj
+  int ja = 1, ka = 2;
+  for (int ia = 0; ia < 3; ++ia) {
+    if (internal::obbDisjoint_check_Ai_cross_Bi<0>::run (ia, ja, ka,
+          B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (internal::obbDisjoint_check_Ai_cross_Bi<1>::run (ia, ja, ka,
+          B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (internal::obbDisjoint_check_Ai_cross_Bi<2>::run (ia, ja, ka,
+          B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    ja = ka; ka = ia;
   }
 
   return false;
-
 }
 
-
-
 bool OBB::overlap(const OBB& other) const
 {
   /// compute what transform [R,T] that takes us from cs1 to cs2.
diff --git a/src/BV/OBBRSS.cpp b/src/BV/OBBRSS.cpp
index 5c3c7f830a1363b6cc7286f68815ac620fee8d94..648c1c054145d409635e51cceb9817a0b53de7b2 100644
--- a/src/BV/OBBRSS.cpp
+++ b/src/BV/OBBRSS.cpp
@@ -42,23 +42,6 @@ namespace hpp
 namespace fcl
 {
 
-bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2)
-{
-  return overlap(R0, T0, b1.obb, b2.obb);
-}
-
-bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1,
-             const OBBRSS& b2, const CollisionRequest& request,
-	     FCL_REAL& sqrDistLowerBound)
-{
-  return overlap(R0, T0, b1.obb, b2.obb, request, sqrDistLowerBound);
-}
-
-FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2, Vec3f* P, Vec3f* Q)
-{
-  return distance(R0, T0, b1.rss, b2.rss, P, Q);
-}
-
 OBBRSS translate(const OBBRSS& bv, const Vec3f& t)
 {
   OBBRSS res(bv);
diff --git a/src/BV/RSS.cpp b/src/BV/RSS.cpp
index 0f719bcebdad1f71a2bcbfe2b78005dd164842a9..220e6b449071abe273d4d53b125bdbe2700fc556 100644
--- a/src/BV/RSS.cpp
+++ b/src/BV/RSS.cpp
@@ -38,6 +38,7 @@
 #include <hpp/fcl/BV/RSS.h>
 #include <hpp/fcl/BVH/BVH_utility.h>
 #include <iostream>
+#include <hpp/fcl/internal/tools.h>
 namespace hpp
 {
 namespace fcl
@@ -843,8 +844,8 @@ bool RSS::overlap(const RSS& other) const
   /// Now compute R1'R2
   Matrix3f R (axes.transpose() * other.axes);
 
-  FCL_REAL dist = rectDistance(R, T, l, other.l);
-  return (dist <= (r + other.r));
+  FCL_REAL dist = rectDistance(R, T, length, other.length);
+  return (dist <= (radius + other.radius));
 }
 
 bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2)
@@ -858,8 +859,8 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2)
   Vec3f T(b1.axes.transpose() * Ttemp);
   Matrix3f R(b1.axes.transpose() * R0 * b2.axes);
 
-  FCL_REAL dist = rectDistance(R, T, b1.l, b2.l);
-  return (dist <= (b1.r + b2.r));
+  FCL_REAL dist = rectDistance(R, T, b1.length, b2.length);
+  return (dist <= (b1.radius + b2.radius));
 }
 
 bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2,
@@ -875,7 +876,7 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2,
   Vec3f T(b1.axes.transpose() * Ttemp);
   Matrix3f R(b1.axes.transpose() * R0 * b2.axes);
 
-  FCL_REAL dist = rectDistance(R, T, b1.l, b2.l) - b1.r - b2.r;
+  FCL_REAL dist = rectDistance(R, T, b1.length, b2.length) - b1.radius - b2.radius;
   if (dist <= 0) return true;
   sqrDistLowerBound = dist * dist;
   return false;
@@ -892,28 +893,28 @@ bool RSS::contain(const Vec3f& p) const
   Vec3f proj(proj0, proj1, proj2);
 
   /// projection is within the rectangle
-  if((proj0 < l[0]) && (proj0 > 0) && (proj1 < l[1]) && (proj1 > 0))
+  if((proj0 < length[0]) && (proj0 > 0) && (proj1 < length[1]) && (proj1 > 0))
   {
-    return (abs_proj2 < r);
+    return (abs_proj2 < radius);
   }
-  else if((proj0 < l[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > l[1])))
+  else if((proj0 < length[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > length[1])))
   {
-    FCL_REAL y = (proj1 > 0) ? l[1] : 0;
+    FCL_REAL y = (proj1 > 0) ? length[1] : 0;
     Vec3f v(proj0, y, 0);
-    return ((proj - v).squaredNorm() < r * r);
+    return ((proj - v).squaredNorm() < radius * radius);
   }
-  else if((proj1 < l[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > l[0])))
+  else if((proj1 < length[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > length[0])))
   {
-    FCL_REAL x = (proj0 > 0) ? l[0] : 0;
+    FCL_REAL x = (proj0 > 0) ? length[0] : 0;
     Vec3f v(x, proj1, 0);
-    return ((proj - v).squaredNorm() < r * r);
+    return ((proj - v).squaredNorm() < radius * radius);
   }
   else
   {
-    FCL_REAL x = (proj0 > 0) ? l[0] : 0;
-    FCL_REAL y = (proj1 > 0) ? l[1] : 0;
+    FCL_REAL x = (proj0 > 0) ? length[0] : 0;
+    FCL_REAL y = (proj1 > 0) ? length[1] : 0;
     Vec3f v(x, y, 0);
-    return ((proj - v).squaredNorm() < r * r);
+    return ((proj - v).squaredNorm() < radius * radius);
   }
 }
 
@@ -927,99 +928,99 @@ RSS& RSS::operator += (const Vec3f& p)
   Vec3f proj(proj0, proj1, proj2);
 
   // projection is within the rectangle
-  if((proj0 < l[0]) && (proj0 > 0) && (proj1 < l[1]) && (proj1 > 0))
+  if((proj0 < length[0]) && (proj0 > 0) && (proj1 < length[1]) && (proj1 > 0))
   {
-    if(abs_proj2 < r)
+    if(abs_proj2 < radius)
       ; // do nothing
     else
     {
-      r = 0.5 * (r + abs_proj2); // enlarge the r
+      radius = 0.5 * (radius + abs_proj2); // enlarge the r
       // change RSS origin position
       if(proj2 > 0)
-        Tr[2] += 0.5 * (abs_proj2 - r);
+        Tr[2] += 0.5 * (abs_proj2 - radius);
       else
-        Tr[2] -= 0.5 * (abs_proj2 - r);
+        Tr[2] -= 0.5 * (abs_proj2 - radius);
     }
   }
-  else if((proj0 < l[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > l[1])))
+  else if((proj0 < length[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > length[1])))
   {
-    FCL_REAL y = (proj1 > 0) ? l[1] : 0;
+    FCL_REAL y = (proj1 > 0) ? length[1] : 0;
     Vec3f v(proj0, y, 0);
     FCL_REAL new_r_sqr = (proj - v).squaredNorm();
-    if(new_r_sqr < r * r)
+    if(new_r_sqr < radius * radius)
       ; // do nothing
     else
     {
-      if(abs_proj2 < r)
+      if(abs_proj2 < radius)
       {
-        FCL_REAL delta_y = - std::sqrt(r * r - proj2 * proj2) + fabs(proj1 - y);
-        l[1] += delta_y;
+        FCL_REAL delta_y = - std::sqrt(radius * radius - proj2 * proj2) + fabs(proj1 - y);
+        length[1] += delta_y;
         if(proj1 < 0)
           Tr[1] -= delta_y;
       }
       else
       {
         FCL_REAL delta_y = fabs(proj1 - y);
-        l[1] += delta_y;
+        length[1] += delta_y;
         if(proj1 < 0)
           Tr[1] -= delta_y;
 
         if(proj2 > 0)
-          Tr[2] += 0.5 * (abs_proj2 - r);
+          Tr[2] += 0.5 * (abs_proj2 - radius);
         else
-          Tr[2] -= 0.5 * (abs_proj2 - r);
+          Tr[2] -= 0.5 * (abs_proj2 - radius);
       }
     }
   }
-  else if((proj1 < l[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > l[0])))
+  else if((proj1 < length[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > length[0])))
   {
-    FCL_REAL x = (proj0 > 0) ? l[0] : 0;
+    FCL_REAL x = (proj0 > 0) ? length[0] : 0;
     Vec3f v(x, proj1, 0);
     FCL_REAL new_r_sqr = (proj - v).squaredNorm();
-    if(new_r_sqr < r * r)
+    if(new_r_sqr < radius * radius)
       ; // do nothing
     else
     {
-      if(abs_proj2 < r)
+      if(abs_proj2 < radius)
       {
-        FCL_REAL delta_x = - std::sqrt(r * r - proj2 * proj2) + fabs(proj0 - x);
-        l[0] += delta_x;
+        FCL_REAL delta_x = - std::sqrt(radius * radius - proj2 * proj2) + fabs(proj0 - x);
+        length[0] += delta_x;
         if(proj0 < 0)
           Tr[0] -= delta_x;
       }
       else
       {
         FCL_REAL delta_x = fabs(proj0 - x);
-        l[0] += delta_x;
+        length[0] += delta_x;
         if(proj0 < 0)
           Tr[0] -= delta_x;
 
         if(proj2 > 0)
-          Tr[2] += 0.5 * (abs_proj2 - r);
+          Tr[2] += 0.5 * (abs_proj2 - radius);
         else
-          Tr[2] -= 0.5 * (abs_proj2 - r);
+          Tr[2] -= 0.5 * (abs_proj2 - radius);
       }
     }
   }
   else
   {
-    FCL_REAL x = (proj0 > 0) ? l[0] : 0;
-    FCL_REAL y = (proj1 > 0) ? l[1] : 0;
+    FCL_REAL x = (proj0 > 0) ? length[0] : 0;
+    FCL_REAL y = (proj1 > 0) ? length[1] : 0;
     Vec3f v(x, y, 0);
     FCL_REAL new_r_sqr = (proj - v).squaredNorm();
-    if(new_r_sqr < r * r)
+    if(new_r_sqr < radius * radius)
       ; // do nothing
     else
     {
-      if(abs_proj2 < r)
+      if(abs_proj2 < radius)
       {
         FCL_REAL diag = std::sqrt(new_r_sqr - proj2 * proj2);
-        FCL_REAL delta_diag = - std::sqrt(r * r - proj2 * proj2) + diag;
+        FCL_REAL delta_diag = - std::sqrt(radius * radius - proj2 * proj2) + diag;
 
         FCL_REAL delta_x = delta_diag / diag * fabs(proj0 - x);
         FCL_REAL delta_y = delta_diag / diag * fabs(proj1 - y);
-        l[0] += delta_x;
-        l[1] += delta_y;
+        length[0] += delta_x;
+        length[1] += delta_y;
 
         if(proj0 < 0 && proj1 < 0)
         {
@@ -1032,8 +1033,8 @@ RSS& RSS::operator += (const Vec3f& p)
         FCL_REAL delta_x = fabs(proj0 - x);
         FCL_REAL delta_y = fabs(proj1 - y);
 
-        l[0] += delta_x;
-        l[1] += delta_y;
+        length[0] += delta_x;
+        length[1] += delta_y;
 
         if(proj0 < 0 && proj1 < 0)
         {
@@ -1042,9 +1043,9 @@ RSS& RSS::operator += (const Vec3f& p)
         }
 
         if(proj2 > 0)
-          Tr[2] += 0.5 * (abs_proj2 - r);
+          Tr[2] += 0.5 * (abs_proj2 - radius);
         else
-          Tr[2] -= 0.5 * (abs_proj2 - r);
+          Tr[2] -= 0.5 * (abs_proj2 - radius);
       }
     }
   }
@@ -1057,12 +1058,12 @@ RSS RSS::operator + (const RSS& other) const
   RSS bv;
 
   Vec3f v[16];
-  Vec3f d0_pos (other.axes.col(0) * (other.l[0] + other.r));
-  Vec3f d1_pos (other.axes.col(1) * (other.l[1] + other.r));
-  Vec3f d0_neg (other.axes.col(0) * (-other.r));
-  Vec3f d1_neg (other.axes.col(1) * (-other.r));
-  Vec3f d2_pos (other.axes.col(2) * other.r);
-  Vec3f d2_neg (other.axes.col(2) * (-other.r));
+  Vec3f d0_pos (other.axes.col(0) * (other.length[0] + other.radius));
+  Vec3f d1_pos (other.axes.col(1) * (other.length[1] + other.radius));
+  Vec3f d0_neg (other.axes.col(0) * (-other.radius));
+  Vec3f d1_neg (other.axes.col(1) * (-other.radius));
+  Vec3f d2_pos (other.axes.col(2) * other.radius);
+  Vec3f d2_neg (other.axes.col(2) * (-other.radius));
 
   v[0].noalias() = other.Tr + d0_pos + d1_pos + d2_pos;
   v[1].noalias() = other.Tr + d0_pos + d1_pos + d2_neg;
@@ -1073,12 +1074,12 @@ RSS RSS::operator + (const RSS& other) const
   v[6].noalias() = other.Tr + d0_neg + d1_neg + d2_pos;
   v[7].noalias() = other.Tr + d0_neg + d1_neg + d2_neg;
 
-  d0_pos.noalias() = axes.col(0) * (l[0] + r);
-  d1_pos.noalias() = axes.col(1) * (l[1] + r);
-  d0_neg.noalias() = axes.col(0) * (-r);
-  d1_neg.noalias() = axes.col(1) * (-r);
-  d2_pos.noalias() = axes.col(2) * r;
-  d2_neg.noalias() = axes.col(2) * (-r);
+  d0_pos.noalias() = axes.col(0) * (length[0] + radius);
+  d1_pos.noalias() = axes.col(1) * (length[1] + radius);
+  d0_neg.noalias() = axes.col(0) * (-radius);
+  d1_neg.noalias() = axes.col(1) * (-radius);
+  d2_pos.noalias() = axes.col(2) * radius;
+  d2_neg.noalias() = axes.col(2) * (-radius);
 
   v[ 8].noalias() = Tr + d0_pos + d1_pos + d2_pos;
   v[ 9].noalias() = Tr + d0_pos + d1_pos + d2_neg;
@@ -1112,7 +1113,7 @@ RSS RSS::operator + (const RSS& other) const
                     E[0][max]*E[1][mid] - E[0][mid]*E[1][max];
 
   // set rss origin, rectangle size and radius
-  getRadiusAndOriginAndRectangleSize(v, NULL, NULL, NULL, 16, bv.axes, bv.Tr, bv.l, bv.r);
+  getRadiusAndOriginAndRectangleSize(v, NULL, NULL, NULL, 16, bv.axes, bv.Tr, bv.length, bv.radius);
 
   return bv;
 }
@@ -1125,8 +1126,8 @@ FCL_REAL RSS::distance(const RSS& other, Vec3f* P, Vec3f* Q) const
   Matrix3f R (axes.transpose() * other.axes);
   Vec3f T (axes.transpose() * (other.Tr - Tr));
 
-  FCL_REAL dist = rectDistance(R, T, l, other.l, P, Q);
-  dist -= (r + other.r);
+  FCL_REAL dist = rectDistance(R, T, length, other.length, P, Q);
+  dist -= (radius + other.radius);
   return (dist < (FCL_REAL)0.0) ? (FCL_REAL)0.0 : dist;
 }
 
@@ -1137,8 +1138,8 @@ FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS&
 
   Vec3f T(b1.axes.transpose() * Ttemp);
 
-  FCL_REAL dist = rectDistance(R, T, b1.l, b2.l, P, Q);
-  dist -= (b1.r + b2.r);
+  FCL_REAL dist = rectDistance(R, T, b1.length, b2.length, P, Q);
+  dist -= (b1.radius + b2.radius);
   return (dist < (FCL_REAL)0.0) ? (FCL_REAL)0.0 : dist;
 }
 
diff --git a/src/BVH/BVH_model.cpp b/src/BVH/BVH_model.cpp
index 58ab55200a01cdbc29b3fc03ff554a8264ca1316..bba163c7457ff844f3060f1c681b56fd11333501 100644
--- a/src/BVH/BVH_model.cpp
+++ b/src/BVH/BVH_model.cpp
@@ -36,25 +36,28 @@
 /** \author Jia Pan */
 
 #include <hpp/fcl/BVH/BVH_model.h>
-#include <hpp/fcl/BV/BV.h>
+
 #include <iostream>
 #include <string.h>
 
+#include <hpp/fcl/BV/BV.h>
+#include <hpp/fcl/shape/convex.h>
+
+#include <hpp/fcl/internal/BV_splitter.h>
+#include <hpp/fcl/internal/BV_fitter.h>
+
 namespace hpp
 {
 namespace fcl
 {
 
-template<typename BV>
-BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other),
-                                                    boost::noncopyable(),
-                                                    num_tris(other.num_tris),
-                                                    num_vertices(other.num_vertices),
-                                                    build_state(other.build_state),
-                                                    bv_splitter(other.bv_splitter),
-                                                    bv_fitter(other.bv_fitter),
-                                                    num_tris_allocated(other.num_tris),
-                                                    num_vertices_allocated(other.num_vertices)
+BVHModelBase::BVHModelBase(const BVHModelBase& other) :
+  CollisionGeometry(other),
+  num_tris(other.num_tris),
+  num_vertices(other.num_vertices),
+  build_state(other.build_state),
+  num_tris_allocated(other.num_tris),
+  num_vertices_allocated(other.num_vertices)
 {
   if(other.vertices)
   {
@@ -79,7 +82,29 @@ BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other),
   }
   else
     prev_vertices = NULL;
+}
 
+void BVHModelBase::buildConvexRepresentation(bool share_memory)
+{
+  if (!convex) {
+    Vec3f* points = vertices;
+    Triangle* polygons = tri_indices;
+    if (!share_memory) {
+      points = new Vec3f[num_vertices];
+      memcpy(points, vertices, sizeof(Vec3f) * num_vertices);
+
+      polygons = new Triangle[num_tris];
+      memcpy(polygons, tri_indices, sizeof(Triangle) * num_tris);
+    }
+    convex.reset(new Convex<Triangle>(!share_memory, points, num_vertices, polygons, num_vertices));
+  }
+}
+
+template<typename BV>
+BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : BVHModelBase(other),
+                                                    bv_splitter(other.bv_splitter),
+                                                    bv_fitter(other.bv_fitter)
+{
   if(other.primitive_indices)
   {
     int num_primitives = 0;
@@ -112,18 +137,16 @@ BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other),
 }
 
 
-template<typename BV>
-int BVHModel<BV>::beginModel(int num_tris_, int num_vertices_)
+int BVHModelBase::beginModel(int num_tris_, int num_vertices_)
 {
   if(build_state != BVH_BUILD_STATE_EMPTY)
   {
     delete [] vertices; vertices = NULL;
     delete [] tri_indices; tri_indices = NULL;
-    delete [] bvs; bvs = NULL;
     delete [] prev_vertices; prev_vertices = NULL;
-    delete [] primitive_indices; primitive_indices = NULL;
 
-    num_vertices_allocated = num_vertices = num_tris_allocated = num_tris = num_bvs_allocated = num_bvs = 0;
+    num_vertices_allocated = num_vertices = num_tris_allocated = num_tris = 0;
+    deleteBVs();
   }
 
   if(num_tris_ <= 0) num_tris_ = 8;
@@ -158,9 +181,7 @@ int BVHModel<BV>::beginModel(int num_tris_, int num_vertices_)
   return BVH_OK;
 }
 
-
-template<typename BV>
-int BVHModel<BV>::addVertex(const Vec3f& p)
+int BVHModelBase::addVertex(const Vec3f& p)
 {
   if(build_state != BVH_BUILD_STATE_BEGUN)
   {
@@ -189,8 +210,7 @@ int BVHModel<BV>::addVertex(const Vec3f& p)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
+int BVHModelBase::addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
 {
   if(build_state == BVH_BUILD_STATE_PROCESSED)
   {
@@ -243,8 +263,7 @@ int BVHModel<BV>::addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps)
+int BVHModelBase::addSubModel(const std::vector<Vec3f>& ps)
 {
   if(build_state == BVH_BUILD_STATE_PROCESSED)
   {
@@ -278,8 +297,7 @@ int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps, const std::vector<Triangle>& ts)
+int BVHModelBase::addSubModel(const std::vector<Vec3f>& ps, const std::vector<Triangle>& ts)
 {
   if(build_state == BVH_BUILD_STATE_PROCESSED)
   {
@@ -340,8 +358,7 @@ int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps, const std::vector<Tr
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::endModel()
+int BVHModelBase::endModel()
 {
   if(build_state != BVH_BUILD_STATE_BEGUN)
   {
@@ -383,24 +400,9 @@ int BVHModel<BV>::endModel()
     num_vertices_allocated = num_vertices;
   }
 
-
   // construct BVH tree
-  int num_bvs_to_be_allocated = 0;
-  if(num_tris == 0)
-    num_bvs_to_be_allocated = 2 * num_vertices - 1;
-  else
-    num_bvs_to_be_allocated = 2 * num_tris - 1;
-
-
-  bvs = new BVNode<BV> [num_bvs_to_be_allocated];
-  primitive_indices = new unsigned int [num_bvs_to_be_allocated];
-  if(!bvs || !primitive_indices)
-  {
-    std::cerr << "BVH Error! Out of memory for BV array in endModel()!" << std::endl;
+  if (!allocateBVs ())
     return BVH_ERR_MODEL_OUT_OF_MEMORY;
-  }
-  num_bvs_allocated = num_bvs_to_be_allocated;
-  num_bvs = 0;
 
   buildTree();
 
@@ -412,8 +414,7 @@ int BVHModel<BV>::endModel()
 
 
 
-template<typename BV>
-int BVHModel<BV>::beginReplaceModel()
+int BVHModelBase::beginReplaceModel()
 {
   if(build_state != BVH_BUILD_STATE_PROCESSED)
   {
@@ -421,7 +422,8 @@ int BVHModel<BV>::beginReplaceModel()
     return BVH_ERR_BUILD_EMPTY_PREVIOUS_FRAME;
   }
 
-  if(prev_vertices) delete [] prev_vertices; prev_vertices = NULL;
+  if(prev_vertices) delete [] prev_vertices;
+  prev_vertices = NULL;
 
   num_vertex_updated = 0;
 
@@ -430,8 +432,7 @@ int BVHModel<BV>::beginReplaceModel()
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::replaceVertex(const Vec3f& p)
+int BVHModelBase::replaceVertex(const Vec3f& p)
 {
   if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN)
   {
@@ -445,8 +446,7 @@ int BVHModel<BV>::replaceVertex(const Vec3f& p)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
+int BVHModelBase::replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
 {
   if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN)
   {
@@ -460,8 +460,7 @@ int BVHModel<BV>::replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f&
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::replaceSubModel(const std::vector<Vec3f>& ps)
+int BVHModelBase::replaceSubModel(const std::vector<Vec3f>& ps)
 {
   if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN)
   {
@@ -477,8 +476,7 @@ int BVHModel<BV>::replaceSubModel(const std::vector<Vec3f>& ps)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::endReplaceModel(bool refit, bool bottomup)
+int BVHModelBase::endReplaceModel(bool refit, bool bottomup)
 {
   if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN)
   {
@@ -510,8 +508,7 @@ int BVHModel<BV>::endReplaceModel(bool refit, bool bottomup)
 
 
 
-template<typename BV>
-int BVHModel<BV>::beginUpdateModel()
+int BVHModelBase::beginUpdateModel()
 {
   if(build_state != BVH_BUILD_STATE_PROCESSED && build_state != BVH_BUILD_STATE_UPDATED)
   {
@@ -538,8 +535,7 @@ int BVHModel<BV>::beginUpdateModel()
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::updateVertex(const Vec3f& p)
+int BVHModelBase::updateVertex(const Vec3f& p)
 {
   if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN)
   {
@@ -553,8 +549,7 @@ int BVHModel<BV>::updateVertex(const Vec3f& p)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
+int BVHModelBase::updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
 {
   if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN)
   {
@@ -568,8 +563,7 @@ int BVHModel<BV>::updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f&
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::updateSubModel(const std::vector<Vec3f>& ps)
+int BVHModelBase::updateSubModel(const std::vector<Vec3f>& ps)
 {
   if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN)
   {
@@ -585,8 +579,7 @@ int BVHModel<BV>::updateSubModel(const std::vector<Vec3f>& ps)
   return BVH_OK;
 }
 
-template<typename BV>
-int BVHModel<BV>::endUpdateModel(bool refit, bool bottomup)
+int BVHModelBase::endUpdateModel(bool refit, bool bottomup)
 {
   if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN)
   {
@@ -621,6 +614,72 @@ int BVHModel<BV>::endUpdateModel(bool refit, bool bottomup)
 
 
 
+void BVHModelBase::computeLocalAABB()
+{
+  AABB aabb_;
+  for(int i = 0; i < num_vertices; ++i)
+  {
+    aabb_ += vertices[i];
+  }
+
+  aabb_center = aabb_.center();
+
+  aabb_radius = 0;
+  for(int i = 0; i < num_vertices; ++i)
+  {
+    FCL_REAL r = (aabb_center - vertices[i]).squaredNorm();
+    if(r > aabb_radius) aabb_radius = r;
+  }
+
+  aabb_radius = sqrt(aabb_radius);
+
+  aabb_local = aabb_;
+}
+
+
+  /// @brief Constructing an empty BVH
+template<typename BV>
+BVHModel<BV>::BVHModel() :
+  BVHModelBase (),
+  bv_splitter(new BVSplitter<BV>(SPLIT_METHOD_MEAN)),
+  bv_fitter(new BVFitter<BV>()),
+  num_bvs_allocated(0),
+  primitive_indices(NULL),
+  bvs(NULL),
+  num_bvs(0)
+{
+}
+
+template<typename BV>
+void BVHModel<BV>::deleteBVs()
+{
+  delete [] bvs; bvs = NULL;
+  delete [] primitive_indices; primitive_indices = NULL;
+  num_bvs_allocated = num_bvs = 0;
+}
+
+template<typename BV>
+bool BVHModel<BV>::allocateBVs()
+{
+  // construct BVH tree
+  int num_bvs_to_be_allocated = 0;
+  if(num_tris == 0)
+    num_bvs_to_be_allocated = 2 * num_vertices - 1;
+  else
+    num_bvs_to_be_allocated = 2 * num_tris - 1;
+
+
+  bvs = new BVNode<BV> [num_bvs_to_be_allocated];
+  primitive_indices = new unsigned int [num_bvs_to_be_allocated];
+  if(!bvs || !primitive_indices)
+  {
+    std::cerr << "BVH Error! Out of memory for BV array in endModel()!" << std::endl;
+    return false;
+  }
+  num_bvs_allocated = num_bvs_to_be_allocated;
+  num_bvs = 0;
+  return true;
+}
 
 template<typename BV>
 int BVHModel<BV>::memUsage(int msg) const
@@ -642,7 +701,6 @@ int BVHModel<BV>::memUsage(int msg) const
   return BVH_OK;
 }
 
-
 template<typename BV>
 int BVHModel<BV>::buildTree()
 {
@@ -765,8 +823,14 @@ int BVHModel<BV>::refitTree(bool bottomup)
 template<typename BV>
 int BVHModel<BV>::refitTree_bottomup()
 {
+  // TODO the recomputation of the BV is done manually, without using
+  // bv_fitter. The manual BV recomputation seems bugged. Using bv_fitter
+  // seems to correct the bug.
+  //bv_fitter->set(vertices, tri_indices, getModelType());
+
   int res = recursiveRefitTree_bottomup(0);
 
+  //bv_fitter->clear();
   return res;
 }
 
@@ -813,6 +877,9 @@ int BVHModel<BV>::recursiveRefitTree_bottomup(int bv_id)
       }
       else
       {
+        //TODO use bv_fitter to build BV. See comment in refitTree_bottomup
+        //unsigned int* cur_primitive_indices = primitive_indices + bvnode->first_primitive;
+        //bv = bv_fitter->fit(cur_primitive_indices, bvnode->num_primitives);
         Vec3f v[3];
         for(int i = 0; i < 3; ++i)
         {
@@ -835,6 +902,9 @@ int BVHModel<BV>::recursiveRefitTree_bottomup(int bv_id)
     recursiveRefitTree_bottomup(bvnode->leftChild());
     recursiveRefitTree_bottomup(bvnode->rightChild());
     bvnode->bv = bvs[bvnode->leftChild()].bv + bvs[bvnode->rightChild()].bv;
+    //TODO use bv_fitter to build BV. See comment in refitTree_bottomup
+    //unsigned int* cur_primitive_indices = primitive_indices + bvnode->first_primitive;
+    //bvnode->bv = bv_fitter->fit(cur_primitive_indices, bvnode->num_primitives);
   }
 
   return BVH_OK;
@@ -855,29 +925,6 @@ int BVHModel<BV>::refitTree_topdown()
   return BVH_OK;
 }
 
-template<typename BV>
-void BVHModel<BV>::computeLocalAABB()
-{
-  AABB aabb_;
-  for(int i = 0; i < num_vertices; ++i)
-  {
-    aabb_ += vertices[i];
-  }
-
-  aabb_center = aabb_.center();
-
-  aabb_radius = 0;
-  for(int i = 0; i < num_vertices; ++i)
-  {
-    FCL_REAL r = (aabb_center - vertices[i]).squaredNorm();
-    if(r > aabb_radius) aabb_radius = r;
-  }
-
-  aabb_radius = sqrt(aabb_radius);
-
-  aabb_local = aabb_;
-}
-
 
 template<>
 void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes, const Vec3f& parent_c)
@@ -988,11 +1035,6 @@ NODE_TYPE BVHModel<KDOP<24> >::getNodeType() const
   return BV_KDOP24;
 }
 
-
-
-
-
-
 template class BVHModel<KDOP<16> >;
 template class BVHModel<KDOP<18> >;
 template class BVHModel<KDOP<24> >;
@@ -1001,6 +1043,7 @@ template class BVHModel<AABB>;
 template class BVHModel<RSS>;
 template class BVHModel<kIOS>;
 template class BVHModel<OBBRSS>;
-}
+
+} // namespace fcl
 
 } // namespace hpp
diff --git a/src/BVH/BVH_utility.cpp b/src/BVH/BVH_utility.cpp
index 4c343906021f13f3ead41c3ddc040bebc1430c71..c408fc613aeb351e46037a2e0adcf00b47ea2ccc 100644
--- a/src/BVH/BVH_utility.cpp
+++ b/src/BVH/BVH_utility.cpp
@@ -45,80 +45,18 @@ namespace hpp
 namespace fcl
 {
 
-void BVHExpand(BVHModel<OBB>& model, const Variance3f* ucs, FCL_REAL r = 1.0)
-{
-  for(int i = 0; i < model.getNumBVs(); ++i)
-  {
-    BVNode<OBB>& bvnode = model.getBV(i);
-
-    Vec3f* vs = new Vec3f[bvnode.num_primitives * 6];
-
-    for(int j = 0; j < bvnode.num_primitives; ++j)
-    {
-      int v_id = bvnode.first_primitive + j;
-      const Variance3f& uc = ucs[v_id];
-
-      Vec3f&v = model.vertices[bvnode.first_primitive + j];
-
-      for(int k = 0; k < 3; ++k)
-      {
-        vs[6 * j + 2 * k] = v + uc.axis[k] * (r * uc.sigma[k]);
-        vs[6 * j + 2 * k + 1] = v - uc.axis[k] * (r * uc.sigma[k]);
-      }
-    }
-
-    OBB bv;
-    fit(vs, bvnode.num_primitives * 6, bv);
-
-    delete [] vs;
-
-    bvnode.bv = bv;
-  }
-}
-
-void BVHExpand(BVHModel<RSS>& model, const Variance3f* ucs, FCL_REAL r = 1.0)
-{
-  for(int i = 0; i < model.getNumBVs(); ++i)
-  {
-    BVNode<RSS>& bvnode = model.getBV(i);
-
-    Vec3f* vs = new Vec3f[bvnode.num_primitives * 6];
-
-    for(int j = 0; j < bvnode.num_primitives; ++j)
-    {
-      int v_id = bvnode.first_primitive + j;
-      const Variance3f& uc = ucs[v_id];
-
-      Vec3f&v = model.vertices[bvnode.first_primitive + j];
-
-      for(int k = 0; k < 3; ++k)
-      {
-        vs[6 * j + 2 * k] = v + uc.axis[k] * (r * uc.sigma[k]);
-        vs[6 * j + 2 * k + 1] = v - uc.axis[k] * (r * uc.sigma[k]);
-      }
-    }
-
-    RSS bv;
-    fit(vs, bvnode.num_primitives * 6, bv);
-
-    delete [] vs;
-
-    bvnode.bv = bv;
-  }
-}
-
 template<typename BV>
 BVHModel<BV>* BVHExtract(const BVHModel<BV>& model, const Transform3f& pose, const AABB& _aabb)
 {
   assert(model.getModelType() == BVH_MODEL_TRIANGLES);
-  const Quaternion3f& q = pose.getQuatRotation();
+  const Matrix3f& q = pose.getRotation();
   AABB aabb = translate (_aabb, - pose.getTranslation());
 
   Transform3f box_pose; Box box;
   constructBox(_aabb, box, box_pose);
   box_pose = pose.inverseTimes (box_pose);
 
-  GJKSolver_indep gjk;
+  GJKSolver gjk;
 
   // Check what triangles should be kept.
   // TODO use the BV hierarchy
@@ -280,7 +218,7 @@ void getCovariance(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, i
 }
 
 
-/** \brief Compute the RSS bounding volume parameters: radius, rectangle size and the origin.
+/** @brief Compute the RSS bounding volume parameters: radius, rectangle size and the origin.
  * The bounding volume axes are known.
  */
 void getRadiusAndOriginAndRectangleSize(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, const Matrix3f& axes, Vec3f& origin, FCL_REAL l[2], FCL_REAL& r)
@@ -561,7 +499,7 @@ void getRadiusAndOriginAndRectangleSize(Vec3f* ps, Vec3f* ps2, Triangle* ts, uns
 }
 
 
-/** \brief Compute the bounding volume extent and center for a set or subset of points.
+/** @brief Compute the bounding volume extent and center for a set or subset of points.
  * The bounding volume axes are known.
  */
 static inline void getExtentAndCenter_pointcloud(Vec3f* ps, Vec3f* ps2, unsigned int* indices, int n, Matrix3f& axes, Vec3f& center, Vec3f& extent)
@@ -606,7 +544,7 @@ static inline void getExtentAndCenter_pointcloud(Vec3f* ps, Vec3f* ps2, unsigned
 }
 
 
-/** \brief Compute the bounding volume extent and center for a set or subset of points.
+/** @brief Compute the bounding volume extent and center for a set or subset of points.
  * The bounding volume axes are known.
  */
 static inline void getExtentAndCenter_mesh(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Matrix3f& axes, Vec3f& center, Vec3f& extent)
diff --git a/src/BVH/BV_fitter.cpp b/src/BVH/BV_fitter.cpp
index e27b76fc8e5950fef5d1c2b6b14b0b7403393b2a..aeed105d9b2f9f5ccb50b9c8b18dde114d790718 100644
--- a/src/BVH/BV_fitter.cpp
+++ b/src/BVH/BV_fitter.cpp
@@ -35,9 +35,10 @@
 
 /** \author Jia Pan */
 
-#include <hpp/fcl/BVH/BV_fitter.h>
+#include <hpp/fcl/internal/BV_fitter.h>
 #include <hpp/fcl/BVH/BVH_utility.h>
 #include <limits>
+#include <hpp/fcl/internal/tools.h>
 
 namespace hpp
 {
@@ -149,9 +150,9 @@ void fit1(Vec3f* ps, RSS& bv)
 {
   bv.Tr.noalias() = ps[0];
   bv.axes.setIdentity();
-  bv.l[0] = 0;
-  bv.l[1] = 0;
-  bv.r = 0;
+  bv.length[0] = 0;
+  bv.length[1] = 0;
+  bv.radius = 0;
 }
 
 void fit2(Vec3f* ps, RSS& bv)
@@ -163,11 +164,11 @@ void fit2(Vec3f* ps, RSS& bv)
   bv.axes.col(0) /= len_p1p2;
 
   generateCoordinateSystem(bv.axes.col(0), bv.axes.col(1), bv.axes.col(2));
-  bv.l[0] = len_p1p2;
-  bv.l[1] = 0;
+  bv.length[0] = len_p1p2;
+  bv.length[1] = 0;
 
   bv.Tr = p2;
-  bv.r = 0;
+  bv.radius = 0;
 }
 
 void fit3(Vec3f* ps, RSS& bv)
@@ -192,7 +193,7 @@ void fit3(Vec3f* ps, RSS& bv)
   bv.axes.col(0).noalias() = e[imax].normalized();
   bv.axes.col(1).noalias() = bv.axes.col(2).cross(bv.axes.col(0));
 
-  getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, 3, bv.axes, bv.Tr, bv.l, bv.r);
+  getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, 3, bv.axes, bv.Tr, bv.length, bv.radius);
 }
 
 void fit6(Vec3f* ps, RSS& bv)
@@ -214,7 +215,7 @@ void fitn(Vec3f* ps, int n, RSS& bv)
   axisFromEigen(E, s, bv.axes);
 
   // set rss origin, rectangle size and radius
-  getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, n, bv.axes, bv.Tr, bv.l, bv.r);
+  getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, n, bv.axes, bv.Tr, bv.length, bv.radius);
 }
 
 }
@@ -433,7 +434,6 @@ void fit(Vec3f* ps, int n, OBB& bv)
   }
 }
 
-
 template<>
 void fit(Vec3f* ps, int n, RSS& bv)
 {
@@ -491,6 +491,16 @@ void fit(Vec3f* ps, int n, OBBRSS& bv)
   }
 }
 
+template<>
+void fit(Vec3f* ps, int n, AABB& bv)
+{
+  if (n <= 0) return;
+  bv = AABB (ps[0]);
+  for(int i = 1; i < n; ++i)
+  {
+    bv += ps[i];
+  }
+}
 
 OBB BVFitter<OBB>::fit(unsigned int* primitive_indices, int num_primitives)
 {
@@ -532,9 +542,9 @@ OBBRSS BVFitter<OBBRSS>::fit(unsigned int* primitive_indices, int num_primitives
   getRadiusAndOriginAndRectangleSize(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.rss.axes, origin, l, r);
 
   bv.rss.Tr = origin;
-  bv.rss.l[0] = l[0];
-  bv.rss.l[1] = l[1];
-  bv.rss.r = r;
+  bv.rss.length[0] = l[0];
+  bv.rss.length[1] = l[1];
+  bv.rss.radius = r;
 
   return bv;
 }
@@ -558,15 +568,14 @@ RSS BVFitter<RSS>::fit(unsigned int* primitive_indices, int num_primitives)
   getRadiusAndOriginAndRectangleSize(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.axes, origin, l, r);
 
   bv.Tr = origin;
-  bv.l[0] = l[0];
-  bv.l[1] = l[1];
-  bv.r = r;
+  bv.length[0] = l[0];
+  bv.length[1] = l[1];
+  bv.radius = r;
 
 
   return bv;
 }
 
-
 kIOS BVFitter<kIOS>::fit(unsigned int* primitive_indices, int num_primitives)
 {
   kIOS bv;
@@ -637,6 +646,47 @@ kIOS BVFitter<kIOS>::fit(unsigned int* primitive_indices, int num_primitives)
   return bv;
 }
 
+AABB BVFitter<AABB>::fit(unsigned int* primitive_indices, int num_primitives)
+{
+  AABB bv;
+  if (num_primitives == 0) return bv;
+
+  if(type == BVH_MODEL_TRIANGLES)             /// The primitive is triangle
+  {
+    Triangle t0 = tri_indices[primitive_indices[0]];
+    bv = AABB (vertices[t0[0]]);
+
+    for(int i = 0; i < num_primitives; ++i)
+    {
+      Triangle t = tri_indices[primitive_indices[i]];
+      bv += vertices[t[0]];
+      bv += vertices[t[1]];
+      bv += vertices[t[2]];
+
+      if(prev_vertices)                      /// can fitting both current and previous frame
+      {
+        bv += prev_vertices[t[0]];
+        bv += prev_vertices[t[1]];
+        bv += prev_vertices[t[2]];
+      }
+    }
+    return bv;
+  }
+  else if(type == BVH_MODEL_POINTCLOUD)       /// The primitive is point
+  {
+    bv = AABB (vertices[primitive_indices[0]]);
+    for(int i = 0; i < num_primitives; ++i)
+    {
+      bv += vertices[primitive_indices[i]];
+
+      if(prev_vertices)                       /// can fitting both current and previous frame
+      {
+        bv += prev_vertices[primitive_indices[i]];
+      }
+    }
+  }
+  return bv;
+}
 
 }
 
diff --git a/src/BVH/BV_splitter.cpp b/src/BVH/BV_splitter.cpp
index 1674cef4a88b52ba85bb5c64f166efa20063f112..bb5ac2e80034c6f3e5dc6548f121fd10aeb67a0b 100644
--- a/src/BVH/BV_splitter.cpp
+++ b/src/BVH/BV_splitter.cpp
@@ -35,7 +35,7 @@
 
 /** \author Jia Pan */
 
-#include <hpp/fcl/BVH/BV_splitter.h>
+#include <hpp/fcl/internal/BV_splitter.h>
 
 namespace hpp
 {
diff --git a/src/collision.cpp b/src/collision.cpp
index a5e5bb81edb26769d07e05190a814b0c4007dca9..b07f2b5d69292b1f64488533b23a1ef8aa8de857 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -47,23 +47,12 @@ namespace hpp
 namespace fcl
 {
 
-template<typename GJKSolver>
-CollisionFunctionMatrix<GJKSolver>& getCollisionFunctionLookTable()
+CollisionFunctionMatrix& getCollisionFunctionLookTable()
 {
-  static CollisionFunctionMatrix<GJKSolver> table;
+  static CollisionFunctionMatrix table;
   return table;
 }
 
-template<typename NarrowPhaseSolver>
-std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
-                    const NarrowPhaseSolver* nsolver,
-                    const CollisionRequest& request,
-                    CollisionResult& result)
-{
-  return collide(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(),
-                 nsolver, request, result);
-}
-
 // reorder collision results in the order the call has been made.
 void invertResults(CollisionResult& result)
 {
@@ -81,18 +70,17 @@ void invertResults(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 GJKSolver* nsolver_,
                     const CollisionRequest& request,
                     CollisionResult& result)
 {
-  const NarrowPhaseSolver* nsolver = nsolver_;
+  const GJKSolver* nsolver = nsolver_;
   if(!nsolver_)
-    nsolver = new NarrowPhaseSolver();  
+    nsolver = new GJKSolver();  
 
-  const CollisionFunctionMatrix<NarrowPhaseSolver>& looktable = getCollisionFunctionLookTable<NarrowPhaseSolver>();
+  const CollisionFunctionMatrix& looktable = getCollisionFunctionLookTable();
   result.distance_lower_bound = -1;
   std::size_t res; 
   if(request.num_max_contacts == 0)
@@ -138,6 +126,14 @@ std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
   return res;
 }
 
+std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
+                    const GJKSolver* nsolver,
+                    const CollisionRequest& request,
+                    CollisionResult& result)
+{
+  return collide(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), nsolver, request, result);
+}
+
 std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
                     const CollisionRequest& request, CollisionResult& result)
 {
@@ -145,8 +141,8 @@ std::size_t collide(const CollisionObject* o1, const CollisionObject* o2,
   {
   case GST_INDEP:
     {
-      GJKSolver_indep solver;
-      return collide<GJKSolver_indep>(o1, o2, &solver, request, result);
+      GJKSolver solver;
+      return collide(o1, o2, &solver, request, result);
     }
   default:
     return -1; // error
@@ -161,8 +157,8 @@ std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1,
   {
   case GST_INDEP:
     {
-      GJKSolver_indep solver;
-      return collide<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result);
+      GJKSolver solver;
+      return collide(o1, tf1, o2, tf2, &solver, request, result);
     }
   default:
     std::cerr << "Warning! Invalid GJK solver" << std::endl;
diff --git a/src/collision_func_matrix.cpp b/src/collision_func_matrix.cpp
index 91b4116748d6b67472cb69629281188309040bf8..efffb50c2394f05a55136bb80247c8fc9da075aa 100644
--- a/src/collision_func_matrix.cpp
+++ b/src/collision_func_matrix.cpp
@@ -38,10 +38,11 @@
 
 #include <hpp/fcl/collision_func_matrix.h>
 
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-#include <hpp/fcl/collision_node.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include <../src/collision_node.h>
 #include <hpp/fcl/narrowphase/narrowphase.h>
-#include "distance_func_matrix.h"
+#include <../src/distance_func_matrix.h>
+#include <../src/traits_traversal.h>
 
 namespace hpp
 {
@@ -49,106 +50,36 @@ namespace fcl
 {
 
 #ifdef HPP_FCL_HAVE_OCTOMAP
-template<typename T_SH, typename NarrowPhaseSolver>
-std::size_t ShapeOcTreeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
-                               const NarrowPhaseSolver* nsolver,
-                               const CollisionRequest& request, CollisionResult& result)
-{
-  if(request.isSatisfied(result)) return result.numContacts();
-
-  ShapeOcTreeCollisionTraversalNode<T_SH, NarrowPhaseSolver> node (request);
-  const T_SH* obj1 = static_cast<const T_SH*>(o1);
-  const OcTree* obj2 = static_cast<const OcTree*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
 
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result);
-  collide(&node, request, result);
-
-  return result.numContacts();
-}
-
-template<typename T_SH, typename NarrowPhaseSolver>
-std::size_t OcTreeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
-                               const NarrowPhaseSolver* nsolver,
+template<typename TypeA, typename TypeB>
+std::size_t Collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
+                               const GJKSolver* nsolver,
                                const CollisionRequest& request, CollisionResult& result)
 {
   if(request.isSatisfied(result)) return result.numContacts();
 
-  OcTreeShapeCollisionTraversalNode<T_SH, NarrowPhaseSolver> node (request);
-  const OcTree* obj1 = static_cast<const OcTree*>(o1);
-  const T_SH* obj2 = static_cast<const T_SH*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
-
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result);
-  collide(&node, request, result);
-
-  return result.numContacts();
-}
-
-template<typename NarrowPhaseSolver>
-std::size_t OcTreeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
-                          const NarrowPhaseSolver* nsolver,
-                          const CollisionRequest& request, CollisionResult& result)
-{
-  if(request.isSatisfied(result)) return result.numContacts();
-
-  OcTreeCollisionTraversalNode<NarrowPhaseSolver> node (request);
-  const OcTree* obj1 = static_cast<const OcTree*>(o1);
-  const OcTree* obj2 = static_cast<const OcTree*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
-
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result);
-  collide(&node, request, result);
-
-  return result.numContacts();
-}
-
-template<typename T_BVH, typename NarrowPhaseSolver>
-std::size_t OcTreeBVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
-                             const NarrowPhaseSolver* nsolver,
-                             const CollisionRequest& request, CollisionResult& result)
-{
-  if(request.isSatisfied(result)) return result.numContacts();
-
-  OcTreeMeshCollisionTraversalNode<T_BVH, NarrowPhaseSolver> node (request);
-  const OcTree* obj1 = static_cast<const OcTree*>(o1);
-  const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
+  typename TraversalTraitsCollision<TypeA, TypeB>::CollisionTraversal_t node (request);
+  const TypeA* obj1 = dynamic_cast<const TypeA*>(o1);
+  const TypeB* obj2 = dynamic_cast<const TypeB*>(o2);
+  OcTreeSolver otsolver(nsolver);
 
   initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result);
   collide(&node, request, result);
-  return result.numContacts();
-}
-
-template<typename T_BVH, typename NarrowPhaseSolver>
-std::size_t BVHOcTreeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
-                             const NarrowPhaseSolver* nsolver,
-                             const CollisionRequest& request, CollisionResult& result)
-{
-  if(request.isSatisfied(result)) return result.numContacts();
- 
-  MeshOcTreeCollisionTraversalNode<T_BVH, NarrowPhaseSolver> node (request);
-  const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>*>(o1);
-  const OcTree* obj2 = static_cast<const OcTree*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
 
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result);
-  collide(&node, request, result);
   return result.numContacts();
 }
-
 #endif
 
-template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver>
+template<typename T_SH1, typename T_SH2>
 std::size_t ShapeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                              const NarrowPhaseSolver* nsolver,
+                              const GJKSolver* nsolver,
                               const CollisionRequest& request, CollisionResult& result)
 {
   if(request.isSatisfied(result)) return result.numContacts();
 
   DistanceResult distanceResult;
   DistanceRequest distanceRequest (request.enable_contact);
-  FCL_REAL distance = ShapeShapeDistance <T_SH1, T_SH2, NarrowPhaseSolver>
+  FCL_REAL distance = ShapeShapeDistance <T_SH1, T_SH2>
     (o1, tf1, o2, tf2, nsolver, distanceRequest, distanceResult);
 
   if (distance <= 0) {
@@ -179,35 +110,12 @@ std::size_t ShapeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf
   return 0;
 }
 
-template<typename T_BVH, typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeCollider
-{
-  static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                             const NarrowPhaseSolver* nsolver,
-                             const CollisionRequest& request, CollisionResult& result)
-  {
-    if(request.isSatisfied(result)) return result.numContacts();
-
-    MeshShapeCollisionTraversalNode<T_BVH, T_SH, NarrowPhaseSolver> node (request);
-    const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1);
-    BVHModel<T_BVH>* obj1_tmp = new BVHModel<T_BVH>(*obj1);
-    Transform3f tf1_tmp = tf1;
-    const T_SH* obj2 = static_cast<const T_SH*>(o2);
-
-    initialize(node, *obj1_tmp, tf1_tmp, *obj2, tf2, nsolver, result);
-    fcl::collide(&node, request, result);
-
-    delete obj1_tmp;
-    return result.numContacts();
-  }
-};
-
 namespace details
 {
 
-template<typename OrientMeshShapeCollisionTraveralNode, typename T_BVH, typename T_SH, typename NarrowPhaseSolver>
+template<typename OrientMeshShapeCollisionTraveralNode, typename T_BVH, typename T_SH>
 std::size_t orientedBVHShapeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                                    const NarrowPhaseSolver* nsolver,
+                                    const GJKSolver* nsolver,
                                     const CollisionRequest& request, CollisionResult& result)
 {
   if(request.isSatisfied(result)) return result.numContacts();
@@ -224,53 +132,94 @@ std::size_t orientedBVHShapeCollide(const CollisionGeometry* o1, const Transform
 }
 
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeCollider<OBB, T_SH, NarrowPhaseSolver>
+template<typename T_BVH, typename T_SH>
+struct BVHShapeCollider
+{
+  static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
+                             const GJKSolver* nsolver,
+                             const CollisionRequest& request, CollisionResult& result)
+  {
+    if(request.isSatisfied(result)) return result.numContacts();
+
+    MeshShapeCollisionTraversalNode<T_BVH, T_SH> node (request);
+    const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1);
+    BVHModel<T_BVH>* obj1_tmp = new BVHModel<T_BVH>(*obj1);
+    Transform3f tf1_tmp = tf1;
+    const T_SH* obj2 = static_cast<const T_SH*>(o2);
+
+    initialize(node, *obj1_tmp, tf1_tmp, *obj2, tf2, nsolver, result);
+    fcl::collide(&node, request, result);
+
+    delete obj1_tmp;
+    return result.numContacts();
+  }
+};
+
+template<typename T_SH>
+struct BVHShapeCollider<OBB, T_SH>
 {
   static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                             const NarrowPhaseSolver* nsolver,
+                             const GJKSolver* nsolver,
                              const CollisionRequest& request, CollisionResult& result)
   {
-    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBB<T_SH, NarrowPhaseSolver>, OBB, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBB<T_SH>, OBB, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   } 
 };
 
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeCollider<RSS, T_SH, NarrowPhaseSolver>
+template<typename T_SH>
+struct BVHShapeCollider<RSS, T_SH>
 {
   static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                             const NarrowPhaseSolver* nsolver,
+                             const GJKSolver* nsolver,
                              const CollisionRequest& request, CollisionResult& result)
   {
-    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeRSS<T_SH, NarrowPhaseSolver>, RSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeRSS<T_SH>, RSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   } 
 };
 
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeCollider<kIOS, T_SH, NarrowPhaseSolver>
+template<typename T_SH>
+struct BVHShapeCollider<kIOS, T_SH>
 {
   static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                             const NarrowPhaseSolver* nsolver,
+                             const GJKSolver* nsolver,
                              const CollisionRequest& request, CollisionResult& result)
   {
-    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodekIOS<T_SH, NarrowPhaseSolver>, kIOS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodekIOS<T_SH>, kIOS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   } 
 };
 
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeCollider<OBBRSS, T_SH, NarrowPhaseSolver>
+template<typename T_SH>
+struct BVHShapeCollider<OBBRSS, T_SH>
 {
   static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                             const NarrowPhaseSolver* nsolver,
+                             const GJKSolver* nsolver,
                              const CollisionRequest& request, CollisionResult& result)
   {
-    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBBRSS<T_SH, NarrowPhaseSolver>, OBBRSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBBRSS<T_SH>, OBBRSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   } 
 };
 
+namespace details
+{
+template<typename OrientedMeshCollisionTraversalNode, typename T_BVH>
+std::size_t orientedMeshCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result)
+{
+  if(request.isSatisfied(result)) return result.numContacts();
+
+  OrientedMeshCollisionTraversalNode node (request);
+  const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1);
+  const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>* >(o2);
+
+  initialize(node, *obj1, tf1, *obj2, tf2, result);
+  collide(&node, request, result);
+
+  return result.numContacts();
+}
+
+}
 
 template<typename T_BVH>
 std::size_t BVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result)
@@ -294,25 +243,6 @@ std::size_t BVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, cons
   return result.numContacts();
 }
 
-namespace details
-{
-template<typename OrientedMeshCollisionTraversalNode, typename T_BVH>
-std::size_t orientedMeshCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result)
-{
-  if(request.isSatisfied(result)) return result.numContacts();
-
-  OrientedMeshCollisionTraversalNode node (request);
-  const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1);
-  const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>* >(o2);
-
-  initialize(node, *obj1, tf1, *obj2, tf2, result);
-  collide(&node, request, result);
-
-  return result.numContacts();
-}
-
-}
-
 template<>
 std::size_t BVHCollide<OBB>(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result)
 {
@@ -333,17 +263,16 @@ std::size_t BVHCollide<kIOS>(const CollisionGeometry* o1, const Transform3f& tf1
 }
 
 
-template<typename T_BVH, typename NarrowPhaseSolver>
+template<typename T_BVH>
 std::size_t BVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, 
-                       const NarrowPhaseSolver* /*nsolver*/,
+                       const GJKSolver* /*nsolver*/,
                        const CollisionRequest& request, CollisionResult& result)
 {
   return BVHCollide<T_BVH>(o1, tf1, o2, tf2, request, result);
 }
 
 
-template<typename NarrowPhaseSolver>
-CollisionFunctionMatrix<NarrowPhaseSolver>::CollisionFunctionMatrix()
+CollisionFunctionMatrix::CollisionFunctionMatrix()
 {
   for(int i = 0; i < NODE_COUNT; ++i)
   {
@@ -351,200 +280,200 @@ CollisionFunctionMatrix<NarrowPhaseSolver>::CollisionFunctionMatrix()
       collision_matrix[i][j] = NULL;
   }
 
-  collision_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeCollide<Box, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeCollide<Box, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeCollide<Box, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeCollide<Box, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeCollide<Box, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeCollide<Box, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeCollide<Box, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeCollide<Box, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeCollide<Sphere, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeCollide<Sphere, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeCollide<Sphere, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeCollide<Sphere, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeCollide<Sphere, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeCollide<Sphere, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeCollide<Sphere, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeCollide<Sphere, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeCollide<Capsule, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeCollide<Capsule, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeCollide<Capsule, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeCollide<Capsule, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeCollide<Capsule, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeCollide<Capsule, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeCollide<Capsule, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeCollide<Capsule, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeCollide<Cone, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeCollide<Cone, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeCollide<Cone, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeCollide<Cone, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeCollide<Cone, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeCollide<Cone, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeCollide<Cone, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeCollide<Cone, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeCollide<Cylinder, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeCollide<Cylinder, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeCollide<Cylinder, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeCollide<Cylinder, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeCollide<Cylinder, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeCollide<Cylinder, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeCollide<Cylinder, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeCollide<Cylinder, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeCollide<Convex, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeCollide<Convex, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeCollide<Convex, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeCollide<Convex, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeCollide<Convex, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeCollide<Convex, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeCollide<Convex, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeCollide<Convex, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeCollide<Plane, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeCollide<Plane, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeCollide<Plane, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeCollide<Plane, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeCollide<Plane, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeCollide<Plane, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeCollide<Plane, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeCollide<Plane, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeCollide<Halfspace, Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeCollide<Halfspace, Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeCollide<Halfspace, Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeCollide<Halfspace, Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeCollide<Halfspace, Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeCollide<Halfspace, Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeCollide<Halfspace, Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeCollide<Halfspace, Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[BV_AABB][GEOM_BOX] = &BVHShapeCollider<AABB, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeCollider<AABB, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeCollider<AABB, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_CONE] = &BVHShapeCollider<AABB, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeCollider<AABB, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeCollider<AABB, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeCollider<AABB, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeCollider<AABB, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_OBB][GEOM_BOX] = &BVHShapeCollider<OBB, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeCollider<OBB, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeCollider<OBB, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_CONE] = &BVHShapeCollider<OBB, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeCollider<OBB, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeCollider<OBB, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeCollider<OBB, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeCollider<OBB, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_RSS][GEOM_BOX] = &BVHShapeCollider<RSS, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeCollider<RSS, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeCollider<RSS, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_CONE] = &BVHShapeCollider<RSS, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeCollider<RSS, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeCollider<RSS, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeCollider<RSS, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeCollider<RSS, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeCollider<KDOP<16>, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeCollider<KDOP<16>, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<16>, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeCollider<KDOP<16>, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<16>, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeCollider<KDOP<16>, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeCollider<KDOP<16>, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<16>, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeCollider<KDOP<18>, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeCollider<KDOP<18>, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<18>, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeCollider<KDOP<18>, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<18>, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeCollider<KDOP<18>, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeCollider<KDOP<18>, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<18>, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeCollider<KDOP<24>, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeCollider<KDOP<24>, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<24>, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeCollider<KDOP<24>, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<24>, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeCollider<KDOP<24>, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeCollider<KDOP<24>, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<24>, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeCollider<kIOS, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeCollider<kIOS, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeCollider<kIOS, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeCollider<kIOS, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeCollider<kIOS, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeCollider<kIOS, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeCollider<kIOS, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeCollider<kIOS, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeCollider<OBBRSS, Box, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeCollider<OBBRSS, Sphere, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeCollider<OBBRSS, Capsule, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeCollider<OBBRSS, Cone, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeCollider<OBBRSS, Cylinder, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeCollider<OBBRSS, Convex, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeCollider<OBBRSS, Plane, NarrowPhaseSolver>::collide;
-  collision_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeCollider<OBBRSS, Halfspace, NarrowPhaseSolver>::collide;
-
-  collision_matrix[BV_AABB][BV_AABB] = &BVHCollide<AABB, NarrowPhaseSolver>;
-  collision_matrix[BV_OBB][BV_OBB] = &BVHCollide<OBB, NarrowPhaseSolver>;
-  collision_matrix[BV_RSS][BV_RSS] = &BVHCollide<RSS, NarrowPhaseSolver>;
-  collision_matrix[BV_KDOP16][BV_KDOP16] = &BVHCollide<KDOP<16>, NarrowPhaseSolver>;
-  collision_matrix[BV_KDOP18][BV_KDOP18] = &BVHCollide<KDOP<18>, NarrowPhaseSolver>;
-  collision_matrix[BV_KDOP24][BV_KDOP24] = &BVHCollide<KDOP<24>, NarrowPhaseSolver>;
-  collision_matrix[BV_kIOS][BV_kIOS] = &BVHCollide<kIOS, NarrowPhaseSolver>;
-  collision_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHCollide<OBBRSS, NarrowPhaseSolver>;
+  collision_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeCollide<Box, Box>;
+  collision_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeCollide<Box, Sphere>;
+  collision_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeCollide<Box, Capsule>;
+  collision_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeCollide<Box, Cone>;
+  collision_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeCollide<Box, Cylinder>;
+  collision_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeCollide<Box, ConvexBase>;
+  collision_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeCollide<Box, Plane>;
+  collision_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeCollide<Box, Halfspace>;
+
+  collision_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeCollide<Sphere, Box>;
+  collision_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeCollide<Sphere, Sphere>;
+  collision_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeCollide<Sphere, Capsule>;
+  collision_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeCollide<Sphere, Cone>;
+  collision_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeCollide<Sphere, Cylinder>;
+  collision_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeCollide<Sphere, ConvexBase>;
+  collision_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeCollide<Sphere, Plane>;
+  collision_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeCollide<Sphere, Halfspace>;
+
+  collision_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeCollide<Capsule, Box>;
+  collision_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeCollide<Capsule, Sphere>;
+  collision_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeCollide<Capsule, Capsule>;
+  collision_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeCollide<Capsule, Cone>;
+  collision_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeCollide<Capsule, Cylinder>;
+  collision_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeCollide<Capsule, ConvexBase>;
+  collision_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeCollide<Capsule, Plane>;
+  collision_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeCollide<Capsule, Halfspace>;
+
+  collision_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeCollide<Cone, Box>;
+  collision_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeCollide<Cone, Sphere>;
+  collision_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeCollide<Cone, Capsule>;
+  collision_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeCollide<Cone, Cone>;
+  collision_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeCollide<Cone, Cylinder>;
+  collision_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeCollide<Cone, ConvexBase>;
+  collision_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeCollide<Cone, Plane>;
+  collision_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeCollide<Cone, Halfspace>;
+
+  collision_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeCollide<Cylinder, Box>;
+  collision_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeCollide<Cylinder, Sphere>;
+  collision_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeCollide<Cylinder, Capsule>;
+  collision_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeCollide<Cylinder, Cone>;
+  collision_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeCollide<Cylinder, Cylinder>;
+  collision_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeCollide<Cylinder, ConvexBase>;
+  collision_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeCollide<Cylinder, Plane>;
+  collision_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeCollide<Cylinder, Halfspace>;
+
+  collision_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeCollide<ConvexBase, Box>;
+  collision_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeCollide<ConvexBase, Sphere>;
+  collision_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeCollide<ConvexBase, Capsule>;
+  collision_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeCollide<ConvexBase, Cone>;
+  collision_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeCollide<ConvexBase, Cylinder>;
+  collision_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeCollide<ConvexBase, ConvexBase>;
+  collision_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeCollide<ConvexBase, Plane>;
+  collision_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeCollide<ConvexBase, Halfspace>;
+
+  collision_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeCollide<Plane, Box>;
+  collision_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeCollide<Plane, Sphere>;
+  collision_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeCollide<Plane, Capsule>;
+  collision_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeCollide<Plane, Cone>;
+  collision_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeCollide<Plane, Cylinder>;
+  collision_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeCollide<Plane, ConvexBase>;
+  collision_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeCollide<Plane, Plane>;
+  collision_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeCollide<Plane, Halfspace>;
+
+  collision_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeCollide<Halfspace, Box>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeCollide<Halfspace, Sphere>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeCollide<Halfspace, Capsule>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeCollide<Halfspace, Cone>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeCollide<Halfspace, Cylinder>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeCollide<Halfspace, ConvexBase>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeCollide<Halfspace, Plane>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeCollide<Halfspace, Halfspace>;
+
+  collision_matrix[BV_AABB][GEOM_BOX] = &BVHShapeCollider<AABB, Box>::collide;
+  collision_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeCollider<AABB, Sphere>::collide;
+  collision_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeCollider<AABB, Capsule>::collide;
+  collision_matrix[BV_AABB][GEOM_CONE] = &BVHShapeCollider<AABB, Cone>::collide;
+  collision_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeCollider<AABB, Cylinder>::collide;
+  collision_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeCollider<AABB, ConvexBase>::collide;
+  collision_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeCollider<AABB, Plane>::collide;
+  collision_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeCollider<AABB, Halfspace>::collide;
+
+  collision_matrix[BV_OBB][GEOM_BOX] = &BVHShapeCollider<OBB, Box>::collide;
+  collision_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeCollider<OBB, Sphere>::collide;
+  collision_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeCollider<OBB, Capsule>::collide;
+  collision_matrix[BV_OBB][GEOM_CONE] = &BVHShapeCollider<OBB, Cone>::collide;
+  collision_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeCollider<OBB, Cylinder>::collide;
+  collision_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeCollider<OBB, ConvexBase>::collide;
+  collision_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeCollider<OBB, Plane>::collide;
+  collision_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeCollider<OBB, Halfspace>::collide;
+
+  collision_matrix[BV_RSS][GEOM_BOX] = &BVHShapeCollider<RSS, Box>::collide;
+  collision_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeCollider<RSS, Sphere>::collide;
+  collision_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeCollider<RSS, Capsule>::collide;
+  collision_matrix[BV_RSS][GEOM_CONE] = &BVHShapeCollider<RSS, Cone>::collide;
+  collision_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeCollider<RSS, Cylinder>::collide;
+  collision_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeCollider<RSS, ConvexBase>::collide;
+  collision_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeCollider<RSS, Plane>::collide;
+  collision_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeCollider<RSS, Halfspace>::collide;
+
+  collision_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeCollider<KDOP<16>, Box>::collide;
+  collision_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeCollider<KDOP<16>, Sphere>::collide;
+  collision_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<16>, Capsule>::collide;
+  collision_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeCollider<KDOP<16>, Cone>::collide;
+  collision_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<16>, Cylinder>::collide;
+  collision_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeCollider<KDOP<16>, ConvexBase>::collide;
+  collision_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeCollider<KDOP<16>, Plane>::collide;
+  collision_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<16>, Halfspace>::collide;
+
+  collision_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeCollider<KDOP<18>, Box>::collide;
+  collision_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeCollider<KDOP<18>, Sphere>::collide;
+  collision_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<18>, Capsule>::collide;
+  collision_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeCollider<KDOP<18>, Cone>::collide;
+  collision_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<18>, Cylinder>::collide;
+  collision_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeCollider<KDOP<18>, ConvexBase>::collide;
+  collision_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeCollider<KDOP<18>, Plane>::collide;
+  collision_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<18>, Halfspace>::collide;
+
+  collision_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeCollider<KDOP<24>, Box>::collide;
+  collision_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeCollider<KDOP<24>, Sphere>::collide;
+  collision_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<24>, Capsule>::collide;
+  collision_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeCollider<KDOP<24>, Cone>::collide;
+  collision_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<24>, Cylinder>::collide;
+  collision_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeCollider<KDOP<24>, ConvexBase>::collide;
+  collision_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeCollider<KDOP<24>, Plane>::collide;
+  collision_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<24>, Halfspace>::collide;
+
+  collision_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeCollider<kIOS, Box>::collide;
+  collision_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeCollider<kIOS, Sphere>::collide;
+  collision_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeCollider<kIOS, Capsule>::collide;
+  collision_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeCollider<kIOS, Cone>::collide;
+  collision_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeCollider<kIOS, Cylinder>::collide;
+  collision_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeCollider<kIOS, ConvexBase>::collide;
+  collision_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeCollider<kIOS, Plane>::collide;
+  collision_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeCollider<kIOS, Halfspace>::collide;
+
+  collision_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeCollider<OBBRSS, Box>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeCollider<OBBRSS, Sphere>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeCollider<OBBRSS, Capsule>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeCollider<OBBRSS, Cone>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeCollider<OBBRSS, Cylinder>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeCollider<OBBRSS, ConvexBase>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeCollider<OBBRSS, Plane>::collide;
+  collision_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeCollider<OBBRSS, Halfspace>::collide;
+
+  collision_matrix[BV_AABB][BV_AABB] = &BVHCollide<AABB>;
+  collision_matrix[BV_OBB][BV_OBB] = &BVHCollide<OBB>;
+  collision_matrix[BV_RSS][BV_RSS] = &BVHCollide<RSS>;
+  collision_matrix[BV_KDOP16][BV_KDOP16] = &BVHCollide<KDOP<16> >;
+  collision_matrix[BV_KDOP18][BV_KDOP18] = &BVHCollide<KDOP<18> >;
+  collision_matrix[BV_KDOP24][BV_KDOP24] = &BVHCollide<KDOP<24> >;
+  collision_matrix[BV_kIOS][BV_kIOS] = &BVHCollide<kIOS>;
+  collision_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHCollide<OBBRSS>;
 
 #ifdef HPP_FCL_HAVE_OCTOMAP
-  collision_matrix[GEOM_OCTREE][GEOM_BOX] = &OcTreeShapeCollide<Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_SPHERE] = &OcTreeShapeCollide<Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &OcTreeShapeCollide<Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_CONE] = &OcTreeShapeCollide<Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &OcTreeShapeCollide<Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_CONVEX] = &OcTreeShapeCollide<Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_PLANE] = &OcTreeShapeCollide<Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &OcTreeShapeCollide<Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_BOX][GEOM_OCTREE] = &ShapeOcTreeCollide<Box, NarrowPhaseSolver>;
-  collision_matrix[GEOM_SPHERE][GEOM_OCTREE] = &ShapeOcTreeCollide<Sphere, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &ShapeOcTreeCollide<Capsule, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONE][GEOM_OCTREE] = &ShapeOcTreeCollide<Cone, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &ShapeOcTreeCollide<Cylinder, NarrowPhaseSolver>;
-  collision_matrix[GEOM_CONVEX][GEOM_OCTREE] = &ShapeOcTreeCollide<Convex, NarrowPhaseSolver>;
-  collision_matrix[GEOM_PLANE][GEOM_OCTREE] = &ShapeOcTreeCollide<Plane, NarrowPhaseSolver>;
-  collision_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &ShapeOcTreeCollide<Halfspace, NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_OCTREE][GEOM_OCTREE] = &OcTreeCollide<NarrowPhaseSolver>;
-
-  collision_matrix[GEOM_OCTREE][BV_AABB] = &OcTreeBVHCollide<AABB, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_OBB] = &OcTreeBVHCollide<OBB, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_RSS] = &OcTreeBVHCollide<RSS, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_OBBRSS] = &OcTreeBVHCollide<OBBRSS, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_kIOS] = &OcTreeBVHCollide<kIOS, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_KDOP16] = &OcTreeBVHCollide<KDOP<16>, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_KDOP18] = &OcTreeBVHCollide<KDOP<18>, NarrowPhaseSolver>;
-  collision_matrix[GEOM_OCTREE][BV_KDOP24] = &OcTreeBVHCollide<KDOP<24>, NarrowPhaseSolver>;
-
-  collision_matrix[BV_AABB][GEOM_OCTREE] = &BVHOcTreeCollide<AABB, NarrowPhaseSolver>;
-  collision_matrix[BV_OBB][GEOM_OCTREE] = &BVHOcTreeCollide<OBB, NarrowPhaseSolver>;
-  collision_matrix[BV_RSS][GEOM_OCTREE] = &BVHOcTreeCollide<RSS, NarrowPhaseSolver>;
-  collision_matrix[BV_OBBRSS][GEOM_OCTREE] = &BVHOcTreeCollide<OBBRSS, NarrowPhaseSolver>;
-  collision_matrix[BV_kIOS][GEOM_OCTREE] = &BVHOcTreeCollide<kIOS, NarrowPhaseSolver>;
-  collision_matrix[BV_KDOP16][GEOM_OCTREE] = &BVHOcTreeCollide<KDOP<16>, NarrowPhaseSolver>;
-  collision_matrix[BV_KDOP18][GEOM_OCTREE] = &BVHOcTreeCollide<KDOP<18>, NarrowPhaseSolver>;
-  collision_matrix[BV_KDOP24][GEOM_OCTREE] = &BVHOcTreeCollide<KDOP<24>, NarrowPhaseSolver>;
+  collision_matrix[GEOM_OCTREE][GEOM_BOX] = &Collide<OcTree, Box>;
+  collision_matrix[GEOM_OCTREE][GEOM_SPHERE] = &Collide<OcTree, Sphere>;
+  collision_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &Collide<OcTree, Capsule>;
+  collision_matrix[GEOM_OCTREE][GEOM_CONE] = &Collide<OcTree, Cone>;
+  collision_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &Collide<OcTree, Cylinder>;
+  collision_matrix[GEOM_OCTREE][GEOM_CONVEX] = &Collide<OcTree, ConvexBase>;
+  collision_matrix[GEOM_OCTREE][GEOM_PLANE] = &Collide<OcTree, Plane>;
+  collision_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &Collide<OcTree, Halfspace>;
+
+  collision_matrix[GEOM_BOX][GEOM_OCTREE] = &Collide<Box, OcTree>;
+  collision_matrix[GEOM_SPHERE][GEOM_OCTREE] = &Collide<Sphere, OcTree>;
+  collision_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &Collide<Capsule, OcTree>;
+  collision_matrix[GEOM_CONE][GEOM_OCTREE] = &Collide<Cone, OcTree>;
+  collision_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &Collide<Cylinder, OcTree>;
+  collision_matrix[GEOM_CONVEX][GEOM_OCTREE] = &Collide<ConvexBase, OcTree>;
+  collision_matrix[GEOM_PLANE][GEOM_OCTREE] = &Collide<Plane, OcTree>;
+  collision_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &Collide<Halfspace, OcTree>;
+
+  collision_matrix[GEOM_OCTREE][GEOM_OCTREE] = &Collide<OcTree, OcTree>;
+
+  collision_matrix[GEOM_OCTREE][BV_AABB  ] = &Collide<OcTree, BVHModel<AABB     > >;
+  collision_matrix[GEOM_OCTREE][BV_OBB   ] = &Collide<OcTree, BVHModel<OBB      > >;
+  collision_matrix[GEOM_OCTREE][BV_RSS   ] = &Collide<OcTree, BVHModel<RSS      > >;
+  collision_matrix[GEOM_OCTREE][BV_OBBRSS] = &Collide<OcTree, BVHModel<OBBRSS   > >;
+  collision_matrix[GEOM_OCTREE][BV_kIOS  ] = &Collide<OcTree, BVHModel<kIOS     > >;
+  collision_matrix[GEOM_OCTREE][BV_KDOP16] = &Collide<OcTree, BVHModel<KDOP<16> > >;
+  collision_matrix[GEOM_OCTREE][BV_KDOP18] = &Collide<OcTree, BVHModel<KDOP<18> > >;
+  collision_matrix[GEOM_OCTREE][BV_KDOP24] = &Collide<OcTree, BVHModel<KDOP<24> > >;
+
+  collision_matrix[BV_AABB  ][GEOM_OCTREE] = &Collide<BVHModel<AABB     >, OcTree>;
+  collision_matrix[BV_OBB   ][GEOM_OCTREE] = &Collide<BVHModel<OBB      >, OcTree>;
+  collision_matrix[BV_RSS   ][GEOM_OCTREE] = &Collide<BVHModel<RSS      >, OcTree>;
+  collision_matrix[BV_OBBRSS][GEOM_OCTREE] = &Collide<BVHModel<OBBRSS   >, OcTree>;
+  collision_matrix[BV_kIOS  ][GEOM_OCTREE] = &Collide<BVHModel<kIOS     >, OcTree>;
+  collision_matrix[BV_KDOP16][GEOM_OCTREE] = &Collide<BVHModel<KDOP<16> >, OcTree>;
+  collision_matrix[BV_KDOP18][GEOM_OCTREE] = &Collide<BVHModel<KDOP<18> >, OcTree>;
+  collision_matrix[BV_KDOP24][GEOM_OCTREE] = &Collide<BVHModel<KDOP<24> >, OcTree>;
 #endif
 }
-template struct CollisionFunctionMatrix<GJKSolver_indep>;
+//template struct CollisionFunctionMatrix;
 }
 
 } // namespace hpp
diff --git a/src/collision_node.cpp b/src/collision_node.cpp
index ad936342337342ba1076485ddca314d4d2709188..436c033d433bf09863c29b48bf2f09b9e644a48b 100644
--- a/src/collision_node.cpp
+++ b/src/collision_node.cpp
@@ -36,8 +36,8 @@
 /** \author Jia Pan */
 
 
-#include <hpp/fcl/collision_node.h>
-#include <hpp/fcl/traversal/traversal_recurse.h>
+#include <../src/collision_node.h>
+#include <hpp/fcl/internal/traversal_recurse.h>
 
 namespace hpp
 {
@@ -46,7 +46,8 @@ namespace fcl
 
 void collide(CollisionTraversalNodeBase* node,
              const CollisionRequest& request, CollisionResult& result,
-	     BVHFrontList* front_list)
+	     BVHFrontList* front_list,
+             bool recursive)
 {
   if(front_list && front_list->size() > 0)
   {
@@ -55,7 +56,10 @@ void collide(CollisionTraversalNodeBase* node,
   else
   {
     FCL_REAL sqrDistLowerBound=0;
-    collisionRecurse(node, 0, 0, front_list, sqrDistLowerBound);
+    if (recursive)
+      collisionRecurse(node, 0, 0, front_list, sqrDistLowerBound);
+    else
+      collisionNonRecurse(node, front_list, sqrDistLowerBound);
     result.distance_lower_bound = sqrt (sqrDistLowerBound);
   }
 }
diff --git a/include/hpp/fcl/collision_node.h b/src/collision_node.h
similarity index 82%
rename from include/hpp/fcl/collision_node.h
rename to src/collision_node.h
index 23fd309de6da0d0281da458463727c00e40d367b..d657eea8fee87da58c7f2e16165264bd3f5b97a6 100644
--- a/include/hpp/fcl/collision_node.h
+++ b/src/collision_node.h
@@ -35,15 +35,14 @@
 
 /** \author Jia Pan */
 
-
 #ifndef HPP_FCL_COLLISION_NODE_H
 #define HPP_FCL_COLLISION_NODE_H
 
-#include <hpp/fcl/traversal/traversal_node_base.h>
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
-#include <hpp/fcl/BVH/BVH_front.h>
-
+/// @cond INTERNAL
 
+#include <hpp/fcl/BVH/BVH_front.h>
+#include <hpp/fcl/internal/traversal_node_base.h>
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
 
 /// @brief collision and distance function on traversal nodes. these functions provide a higher level abstraction for collision functions provided in collision_func_matrix
 namespace hpp
@@ -54,15 +53,14 @@ namespace fcl
 
 /// collision on collision traversal node
 /// 
-/// \param node node containing both objects to test,
-/// \retval squared lower bound to the distance between the objects if they
+/// @param node node containing both objects to test,
+/// @retval squared lower bound to the distance between the objects if they
 ///         do not collide.
-/// \param front_list list of nodes visited by the query, can be used to
+/// @param front_list list of nodes visited by the query, can be used to
 ///        accelerate computation
-  void collide(CollisionTraversalNodeBase* node,
-               const CollisionRequest& request,
-               CollisionResult& result,
-	       BVHFrontList* front_list = NULL);
+void collide(CollisionTraversalNodeBase* node, const CollisionRequest& request,
+             CollisionResult& result, BVHFrontList* front_list = NULL,
+             bool recursive = true);
 
 /// @brief distance computation on distance traversal node; can use front list to accelerate
 void distance(DistanceTraversalNodeBase* node, BVHFrontList* front_list = NULL, int qsize = 2);
@@ -70,4 +68,6 @@ void distance(DistanceTraversalNodeBase* node, BVHFrontList* front_list = NULL,
 
 } // namespace hpp
 
+/// @endcond
+
 #endif
diff --git a/src/distance.cpp b/src/distance.cpp
index efda1c8ccb0c79483b0951aa43e86b7125b039d1..95c4a8b2ee9cd2ae4d1ef757939dbe83b5d19322 100644
--- a/src/distance.cpp
+++ b/src/distance.cpp
@@ -46,32 +46,22 @@ namespace hpp
 namespace fcl
 {
 
-template<typename GJKSolver>
-DistanceFunctionMatrix<GJKSolver>& getDistanceFunctionLookTable()
+DistanceFunctionMatrix& getDistanceFunctionLookTable()
 {
-  static DistanceFunctionMatrix<GJKSolver> table;
+  static DistanceFunctionMatrix table;
   return table;
 }
 
-template<typename NarrowPhaseSolver>
-FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const NarrowPhaseSolver* nsolver,
-                  const DistanceRequest& request, DistanceResult& result)
-{
-  return distance<NarrowPhaseSolver>(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), nsolver,
-                                     request, result);
-}
-
-template<typename NarrowPhaseSolver>
 FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, 
                   const CollisionGeometry* o2, const Transform3f& tf2,
-                  const NarrowPhaseSolver* nsolver_,
+                  const GJKSolver* nsolver_,
                   const DistanceRequest& request, DistanceResult& result)
 {
-  const NarrowPhaseSolver* nsolver = nsolver_;
+  const GJKSolver* nsolver = nsolver_;
   if(!nsolver_) 
-    nsolver = new NarrowPhaseSolver();
+    nsolver = new GJKSolver();
 
-  const DistanceFunctionMatrix<NarrowPhaseSolver>& looktable = getDistanceFunctionLookTable<NarrowPhaseSolver>();
+  const DistanceFunctionMatrix& looktable = getDistanceFunctionLookTable();
 
   OBJECT_TYPE object_type1 = o1->getObjectType();
   NODE_TYPE node_type1 = o1->getNodeType();
@@ -118,6 +108,12 @@ FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1,
   return res;
 }
 
+FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const GJKSolver* nsolver,
+                  const DistanceRequest& request, DistanceResult& result)
+{
+  return distance(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), nsolver,
+                                     request, result);
+}
 
 FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const DistanceRequest& request, DistanceResult& result)
 {
@@ -125,8 +121,8 @@ FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const Di
   {
   case GST_INDEP:
     {
-      GJKSolver_indep solver;
-      return distance<GJKSolver_indep>(o1, o2, &solver, request, result);
+      GJKSolver solver;
+      return distance(o1, o2, &solver, request, result);
     }
   default:
     return -1; // error
@@ -141,8 +137,8 @@ FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1,
   {
   case GST_INDEP:
     {
-      GJKSolver_indep solver;
-      return distance<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result);
+      GJKSolver solver;
+      return distance(o1, tf1, o2, tf2, &solver, request, result);
     }
   default:
     return -1;
diff --git a/src/distance_box_halfspace.cpp b/src/distance_box_halfspace.cpp
index 629aa4caad9f970a5998416baecaef6ff3b14743..191cf09bcb86f2c04b7ae9aeb8b78ee11cae41b9 100644
--- a/src/distance_box_halfspace.cpp
+++ b/src/distance_box_halfspace.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Box, Halfspace, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Box, Halfspace>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Box& s1 = static_cast <const Box&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Halfspace, Box, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Halfspace, Box>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Halfspace& s1 = static_cast <const Halfspace&> (*o1);
diff --git a/src/distance_box_plane.cpp b/src/distance_box_plane.cpp
index 389d62b7786dcbcd212d52f352cc1620ac1c0cb3..d63879225374473452c6aa0387b9cd323508c2c2 100644
--- a/src/distance_box_plane.cpp
+++ b/src/distance_box_plane.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Box, Plane, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Box, Plane>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Box& s1 = static_cast <const Box&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Plane, Box, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Plane, Box>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Plane& s1 = static_cast <const Plane&> (*o1);
diff --git a/src/distance_box_sphere.cpp b/src/distance_box_sphere.cpp
index 7d56b9902ed5402e1c787bdedea255943f2d3721..f35030e308a3342788832a944ac6f0877640423c 100644
--- a/src/distance_box_sphere.cpp
+++ b/src/distance_box_sphere.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Box, Sphere, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Box, Sphere>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Box& s1 = static_cast <const Box&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Sphere, Box, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Sphere, Box>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Sphere& s1 = static_cast <const Sphere&> (*o1);
diff --git a/src/distance_capsule_capsule.cpp b/src/distance_capsule_capsule.cpp
index 3e80e7b63d2416f6696f3d487a4bf475023f6e5f..029c23680cddf7b9771990228e93dd909077f3b4 100644
--- a/src/distance_capsule_capsule.cpp
+++ b/src/distance_capsule_capsule.cpp
@@ -10,7 +10,7 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
+#include <../src/distance_func_matrix.h>
 
 // Note that partial specialization of template functions is not allowed.
 // Therefore, two implementations with the default narrow phase solvers are
@@ -23,13 +23,13 @@
 namespace hpp
 {
 namespace fcl {
-  class GJKSolver_indep;
+  class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Capsule, Capsule, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Capsule, Capsule>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest& request,
+   const GJKSolver*, const DistanceRequest& request,
    DistanceResult& result)
   {
     const Capsule* c1 = static_cast <const Capsule*> (o1);
@@ -41,8 +41,8 @@ namespace fcl {
     // We assume that capsules are oriented along z-axis.
     Matrix3f::ConstColXpr direction1 = tf1.getRotation ().col (2);
     Matrix3f::ConstColXpr direction2 = tf2.getRotation ().col (2);
-    FCL_REAL halfLength1 = 0.5*c1->lz;
-    FCL_REAL halfLength2 = 0.5*c2->lz;
+    FCL_REAL halfLength1 = c1->halfLength;
+    FCL_REAL halfLength2 = c2->halfLength;
 
     Vec3f diff = center1 - center2;
     FCL_REAL a01 = -direction1.dot (direction2);
@@ -321,17 +321,17 @@ namespace fcl {
   }
 
   template <>
-  std::size_t ShapeShapeCollide <Capsule, Capsule, GJKSolver_indep>
+  std::size_t ShapeShapeCollide <Capsule, Capsule>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const CollisionRequest& request,
+   const GJKSolver*, const CollisionRequest& request,
    CollisionResult& result)
   {
-    GJKSolver_indep* unused = 0x0;
+    GJKSolver* unused = 0x0;
     DistanceResult distanceResult;
     DistanceRequest distanceRequest (request.enable_contact);
 
-    FCL_REAL distance = ShapeShapeDistance <Capsule, Capsule, GJKSolver_indep>
+    FCL_REAL distance = ShapeShapeDistance <Capsule, Capsule>
       (o1, tf1, o2, tf2, unused, distanceRequest, distanceResult);
 
     if (distance <= 0) {
diff --git a/src/distance_capsule_halfspace.cpp b/src/distance_capsule_halfspace.cpp
index acd08f74a868effbefb50b20fca0cecb7fcc2d7a..f33fc5175999bacab4c1223243074d8356b6f278 100644
--- a/src/distance_capsule_halfspace.cpp
+++ b/src/distance_capsule_halfspace.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Capsule, Halfspace, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Capsule, Halfspace>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Capsule& s1 = static_cast <const Capsule&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Halfspace, Capsule, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Halfspace, Capsule>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Halfspace& s1 = static_cast <const Halfspace&> (*o1);
diff --git a/src/distance_capsule_plane.cpp b/src/distance_capsule_plane.cpp
index 504d2fec1f5d8f0485e8263f3409af0c556a6a90..beb862d065661df9a52cd813083ad2893230c917 100644
--- a/src/distance_capsule_plane.cpp
+++ b/src/distance_capsule_plane.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Capsule, Plane, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Capsule, Plane>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Capsule& s1 = static_cast <const Capsule&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Plane, Capsule, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Plane, Capsule>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Plane& s1 = static_cast <const Plane&> (*o1);
diff --git a/src/distance_cone_halfspace.cpp b/src/distance_cone_halfspace.cpp
index 0d4d4a1844e4dcdf9f5cd3e6af34bdf350adf549..0191f6530d5e6c4b1ee2014c223bc92c721d2b62 100644
--- a/src/distance_cone_halfspace.cpp
+++ b/src/distance_cone_halfspace.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Cone, Halfspace, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Cone, Halfspace>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Cone& s1 = static_cast <const Cone&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Halfspace, Cone, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Halfspace, Cone>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Halfspace& s1 = static_cast <const Halfspace&> (*o1);
diff --git a/src/distance_cone_plane.cpp b/src/distance_cone_plane.cpp
index 754498da8920f07365fbce02cc7cb5c338776b56..bc66f953b9ae9e4db6fa17d2e70a3c74ef8e31a1 100644
--- a/src/distance_cone_plane.cpp
+++ b/src/distance_cone_plane.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Cone, Plane, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Cone, Plane>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Cone& s1 = static_cast <const Cone&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Plane, Cone, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Plane, Cone>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Plane& s1 = static_cast <const Plane&> (*o1);
diff --git a/src/distance_cylinder_halfspace.cpp b/src/distance_cylinder_halfspace.cpp
index 4e6163a65c3d8b5597ca3cc8009dd89ba7b65586..dd469a6c4378999c390795d9b5a59d18e3d8dd39 100644
--- a/src/distance_cylinder_halfspace.cpp
+++ b/src/distance_cylinder_halfspace.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Cylinder, Halfspace, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Cylinder, Halfspace>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Cylinder& s1 = static_cast <const Cylinder&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Halfspace, Cylinder, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Halfspace, Cylinder>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Halfspace& s1 = static_cast <const Halfspace&> (*o1);
diff --git a/src/distance_cylinder_plane.cpp b/src/distance_cylinder_plane.cpp
index 729f99eb859e7a5ed906741443d6b16a323b50b2..e8be52cb7c2e938b92bec2ed900cd919f8c65add 100644
--- a/src/distance_cylinder_plane.cpp
+++ b/src/distance_cylinder_plane.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Cylinder, Plane, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Cylinder, Plane>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Cylinder& s1 = static_cast <const Cylinder&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Plane, Cylinder, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Plane, Cylinder>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Plane& s1 = static_cast <const Plane&> (*o1);
diff --git a/src/distance_func_matrix.cpp b/src/distance_func_matrix.cpp
index 423d8d62e52306a70bf19559e5a5020479ee8c30..68dab3ff569ee0348fd5a3a76c72c01fb4a96210 100644
--- a/src/distance_func_matrix.cpp
+++ b/src/distance_func_matrix.cpp
@@ -37,9 +37,9 @@
 
 #include <hpp/fcl/distance_func_matrix.h>
 
-#include <hpp/fcl/collision_node.h>
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-#include <hpp/fcl/narrowphase/narrowphase.h>
+#include <../src/collision_node.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include <../src/traits_traversal.h>
 
 namespace hpp
 {
@@ -47,31 +47,16 @@ namespace fcl
 {
 
 #ifdef HPP_FCL_HAVE_OCTOMAP
-template<typename T_SH, typename NarrowPhaseSolver>
-FCL_REAL ShapeOcTreeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
-                             const DistanceRequest& request, DistanceResult& result)
-{
-  if(request.isSatisfied(result)) return result.min_distance;
-  ShapeOcTreeDistanceTraversalNode<T_SH, NarrowPhaseSolver> node;
-  const T_SH* obj1 = static_cast<const T_SH*>(o1);
-  const OcTree* obj2 = static_cast<const OcTree*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
 
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result);
-  distance(&node);
-  
-  return result.min_distance;
-}
-
-template<typename T_SH, typename NarrowPhaseSolver>
-FCL_REAL OcTreeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+template<typename TypeA, typename TypeB>
+FCL_REAL Distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                              const DistanceRequest& request, DistanceResult& result)
 {
   if(request.isSatisfied(result)) return result.min_distance;
-  OcTreeShapeDistanceTraversalNode<T_SH, NarrowPhaseSolver> node;
-  const OcTree* obj1 = static_cast<const OcTree*>(o1);
-  const T_SH* obj2 = static_cast<const T_SH*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
+  typename TraversalTraitsDistance<TypeA, TypeB>::CollisionTraversal_t node;
+  const TypeA* obj1 = static_cast<const TypeA*>(o1);
+  const TypeB* obj2 = static_cast<const TypeB*>(o2);
+  OcTreeSolver otsolver(nsolver);
 
   initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result);
   distance(&node);
@@ -79,62 +64,14 @@ FCL_REAL OcTreeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1
   return result.min_distance;
 }
 
-template<typename NarrowPhaseSolver>
-FCL_REAL OcTreeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
-                        const DistanceRequest& request, DistanceResult& result)
-{
-  if(request.isSatisfied(result)) return result.min_distance;
-  OcTreeDistanceTraversalNode<NarrowPhaseSolver> node;
-  const OcTree* obj1 = static_cast<const OcTree*>(o1);
-  const OcTree* obj2 = static_cast<const OcTree*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
-
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result);
-  distance(&node);
-
-  return result.min_distance;
-}
-
-template<typename T_BVH, typename NarrowPhaseSolver>
-FCL_REAL BVHOcTreeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
-                           const DistanceRequest& request, DistanceResult& result)
-{
-  if(request.isSatisfied(result)) return result.min_distance;
-  MeshOcTreeDistanceTraversalNode<T_BVH, NarrowPhaseSolver> node;
-  const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>*>(o1);
-  const OcTree* obj2 = static_cast<const OcTree*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
-
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result);
-  distance(&node);
-
-  return result.min_distance;
-}
-
-template<typename T_BVH, typename NarrowPhaseSolver>
-FCL_REAL OcTreeBVHDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
-                       const DistanceRequest& request, DistanceResult& result)
-{
-  if(request.isSatisfied(result)) return result.min_distance;
-  OcTreeMeshDistanceTraversalNode<T_BVH, NarrowPhaseSolver> node;
-  const OcTree* obj1 = static_cast<const OcTree*>(o1);
-  const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>*>(o2);
-  OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver);
-
-  initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result);
-  distance(&node);
-
-  return result.min_distance;
-}
-
 #endif
 
-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,
+template<typename T_SH1, typename T_SH2>
+FCL_REAL ShapeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                         const DistanceRequest& request, DistanceResult& result)
 {
   if(request.isSatisfied(result)) return result.min_distance;
-  ShapeDistanceTraversalNode<T_SH1, T_SH2, NarrowPhaseSolver> node;
+  ShapeDistanceTraversalNode<T_SH1, T_SH2> node;
   const T_SH1* obj1 = static_cast<const T_SH1*>(o1);
   const T_SH2* obj2 = static_cast<const T_SH2*>(o2);
 
@@ -144,14 +81,14 @@ FCL_REAL ShapeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1,
   return result.min_distance;
 }
 
-template<typename T_BVH, typename T_SH, typename NarrowPhaseSolver>
+template<typename T_BVH, typename T_SH>
 struct BVHShapeDistancer
 {
-  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                            const DistanceRequest& request, DistanceResult& result)
   {
     if(request.isSatisfied(result)) return result.min_distance;
-    MeshShapeDistanceTraversalNode<T_BVH, T_SH, NarrowPhaseSolver> node;
+    MeshShapeDistanceTraversalNode<T_BVH, T_SH> node;
     const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1);
     BVHModel<T_BVH>* obj1_tmp = new BVHModel<T_BVH>(*obj1);
     Transform3f tf1_tmp = tf1;
@@ -168,8 +105,8 @@ struct BVHShapeDistancer
 namespace details
 {
 
-template<typename OrientedMeshShapeDistanceTraversalNode, typename T_BVH, typename T_SH, typename NarrowPhaseSolver>
-FCL_REAL orientedBVHShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+template<typename OrientedMeshShapeDistanceTraversalNode, typename T_BVH, typename T_SH>
+FCL_REAL orientedBVHShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                                   const DistanceRequest& request, DistanceResult& result)
 {
   if(request.isSatisfied(result)) return result.min_distance;
@@ -185,34 +122,34 @@ FCL_REAL orientedBVHShapeDistance(const CollisionGeometry* o1, const Transform3f
 
 }
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeDistancer<RSS, T_SH, NarrowPhaseSolver>
+template<typename T_SH>
+struct BVHShapeDistancer<RSS, T_SH>
 {
-  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                            const DistanceRequest& request, DistanceResult& result)
   {
-    return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeRSS<T_SH, NarrowPhaseSolver>, RSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeRSS<T_SH>, RSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   }
 };
 
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeDistancer<kIOS, T_SH, NarrowPhaseSolver>
+template<typename T_SH>
+struct BVHShapeDistancer<kIOS, T_SH>
 {
-  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                        const DistanceRequest& request, DistanceResult& result)
   {
-    return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodekIOS<T_SH, NarrowPhaseSolver>, kIOS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodekIOS<T_SH>, kIOS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   }
 };
 
-template<typename T_SH, typename NarrowPhaseSolver>
-struct BVHShapeDistancer<OBBRSS, T_SH, NarrowPhaseSolver>
+template<typename T_SH>
+struct BVHShapeDistancer<OBBRSS, T_SH>
 {
-  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver,
+  static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver,
                            const DistanceRequest& request, DistanceResult& result)
   {
-    return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeOBBRSS<T_SH, NarrowPhaseSolver>, OBBRSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result);
+    return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeOBBRSS<T_SH>, OBBRSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result);
   }
 };
 
@@ -280,16 +217,15 @@ FCL_REAL BVHDistance<OBBRSS>(const CollisionGeometry* o1, const Transform3f& tf1
 }
 
 
-template<typename T_BVH, typename NarrowPhaseSolver>
+template<typename T_BVH>
 FCL_REAL BVHDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2,
-                     const NarrowPhaseSolver* /*nsolver*/,
+                     const GJKSolver* /*nsolver*/,
                      const DistanceRequest& request, DistanceResult& result)
 {
   return BVHDistance<T_BVH>(o1, tf1, o2, tf2, request, result);
 }
 
-template<typename NarrowPhaseSolver>
-DistanceFunctionMatrix<NarrowPhaseSolver>::DistanceFunctionMatrix()
+DistanceFunctionMatrix::DistanceFunctionMatrix()
 {
   for(int i = 0; i < NODE_COUNT; ++i)
   {
@@ -297,205 +233,205 @@ DistanceFunctionMatrix<NarrowPhaseSolver>::DistanceFunctionMatrix()
       distance_matrix[i][j] = NULL;
   }
 
-  distance_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeDistance<Box, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeDistance<Box, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeDistance<Box, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeDistance<Box, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeDistance<Box, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeDistance<Box, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeDistance<Box, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeDistance<Box, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeDistance<Sphere, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeDistance<Sphere, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeDistance<Sphere, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeDistance<Sphere, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeDistance<Sphere, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeDistance<Sphere, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeDistance<Sphere, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeDistance<Sphere, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeDistance<Capsule, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeDistance<Capsule, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeDistance<Capsule, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeDistance<Capsule, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeDistance<Capsule, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeDistance<Capsule, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeDistance<Capsule, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeDistance<Capsule, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeDistance<Cone, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeDistance<Cone, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeDistance<Cone, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeDistance<Cone, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeDistance<Cone, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeDistance<Cone, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeDistance<Cone, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeDistance<Cone, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeDistance<Cylinder, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeDistance<Cylinder, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeDistance<Cylinder, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeDistance<Cylinder, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeDistance<Cylinder, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeDistance<Cylinder, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeDistance<Cylinder, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeDistance<Cylinder, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeDistance<Convex, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeDistance<Convex, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeDistance<Convex, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeDistance<Convex, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeDistance<Convex, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeDistance<Convex, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeDistance<Convex, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeDistance<Convex, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeDistance<Plane, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeDistance<Plane, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeDistance<Plane, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeDistance<Plane, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeDistance<Plane, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeDistance<Plane, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeDistance<Plane, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeDistance<Plane, Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeDistance<Halfspace, Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeDistance<Halfspace, Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeDistance<Halfspace, Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeDistance<Halfspace, Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeDistance<Halfspace, Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeDistance<Halfspace, Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeDistance<Halfspace, Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeDistance<Halfspace, Halfspace, NarrowPhaseSolver>;
+  distance_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeDistance<Box, Box>;
+  distance_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeDistance<Box, Sphere>;
+  distance_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeDistance<Box, Capsule>;
+  distance_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeDistance<Box, Cone>;
+  distance_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeDistance<Box, Cylinder>;
+  distance_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeDistance<Box, ConvexBase>;
+  distance_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeDistance<Box, Plane>;
+  distance_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeDistance<Box, Halfspace>;
+
+  distance_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeDistance<Sphere, Box>;
+  distance_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeDistance<Sphere, Sphere>;
+  distance_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeDistance<Sphere, Capsule>;
+  distance_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeDistance<Sphere, Cone>;
+  distance_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeDistance<Sphere, Cylinder>;
+  distance_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeDistance<Sphere, ConvexBase>;
+  distance_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeDistance<Sphere, Plane>;
+  distance_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeDistance<Sphere, Halfspace>;
+
+  distance_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeDistance<Capsule, Box>;
+  distance_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeDistance<Capsule, Sphere>;
+  distance_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeDistance<Capsule, Capsule>;
+  distance_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeDistance<Capsule, Cone>;
+  distance_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeDistance<Capsule, Cylinder>;
+  distance_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeDistance<Capsule, ConvexBase>;
+  distance_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeDistance<Capsule, Plane>;
+  distance_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeDistance<Capsule, Halfspace>;
+
+  distance_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeDistance<Cone, Box>;
+  distance_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeDistance<Cone, Sphere>;
+  distance_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeDistance<Cone, Capsule>;
+  distance_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeDistance<Cone, Cone>;
+  distance_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeDistance<Cone, Cylinder>;
+  distance_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeDistance<Cone, ConvexBase>;
+  distance_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeDistance<Cone, Plane>;
+  distance_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeDistance<Cone, Halfspace>;
+
+  distance_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeDistance<Cylinder, Box>;
+  distance_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeDistance<Cylinder, Sphere>;
+  distance_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeDistance<Cylinder, Capsule>;
+  distance_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeDistance<Cylinder, Cone>;
+  distance_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeDistance<Cylinder, Cylinder>;
+  distance_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeDistance<Cylinder, ConvexBase>;
+  distance_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeDistance<Cylinder, Plane>;
+  distance_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeDistance<Cylinder, Halfspace>;
+
+  distance_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeDistance<ConvexBase, Box>;
+  distance_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeDistance<ConvexBase, Sphere>;
+  distance_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeDistance<ConvexBase, Capsule>;
+  distance_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeDistance<ConvexBase, Cone>;
+  distance_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeDistance<ConvexBase, Cylinder>;
+  distance_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeDistance<ConvexBase, ConvexBase>;
+  distance_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeDistance<ConvexBase, Plane>;
+  distance_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeDistance<ConvexBase, Halfspace>;
+
+  distance_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeDistance<Plane, Box>;
+  distance_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeDistance<Plane, Sphere>;
+  distance_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeDistance<Plane, Capsule>;
+  distance_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeDistance<Plane, Cone>;
+  distance_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeDistance<Plane, Cylinder>;
+  distance_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeDistance<Plane, ConvexBase>;
+  distance_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeDistance<Plane, Plane>;
+  distance_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeDistance<Plane, Halfspace>;
+
+  distance_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeDistance<Halfspace, Box>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeDistance<Halfspace, Sphere>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeDistance<Halfspace, Capsule>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeDistance<Halfspace, Cone>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeDistance<Halfspace, Cylinder>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeDistance<Halfspace, ConvexBase>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeDistance<Halfspace, Plane>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeDistance<Halfspace, Halfspace>;
 
   /* AABB distance not implemented */
   /*
-  distance_matrix[BV_AABB][GEOM_BOX] = &BVHShapeDistancer<AABB, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeDistancer<AABB, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeDistancer<AABB, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_CONE] = &BVHShapeDistancer<AABB, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeDistancer<AABB, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeDistancer<AABB, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeDistancer<AABB, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeDistancer<AABB, Halfspace, NarrowPhaseSolver>::distance;
+  distance_matrix[BV_AABB][GEOM_BOX] = &BVHShapeDistancer<AABB, Box>::distance;
+  distance_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeDistancer<AABB, Sphere>::distance;
+  distance_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeDistancer<AABB, Capsule>::distance;
+  distance_matrix[BV_AABB][GEOM_CONE] = &BVHShapeDistancer<AABB, Cone>::distance;
+  distance_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeDistancer<AABB, Cylinder>::distance;
+  distance_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeDistancer<AABB, ConvexBase>::distance;
+  distance_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeDistancer<AABB, Plane>::distance;
+  distance_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeDistancer<AABB, Halfspace>::distance;
   */
 
-  distance_matrix[BV_OBB][GEOM_BOX] = &BVHShapeDistancer<OBB, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeDistancer<OBB, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeDistancer<OBB, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_CONE] = &BVHShapeDistancer<OBB, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeDistancer<OBB, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeDistancer<OBB, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeDistancer<OBB, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeDistancer<OBB, Halfspace, NarrowPhaseSolver>::distance;
-
-  distance_matrix[BV_RSS][GEOM_BOX] = &BVHShapeDistancer<RSS, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeDistancer<RSS, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeDistancer<RSS, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_CONE] = &BVHShapeDistancer<RSS, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeDistancer<RSS, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeDistancer<RSS, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeDistancer<RSS, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeDistancer<RSS, Halfspace, NarrowPhaseSolver>::distance;
+  distance_matrix[BV_OBB][GEOM_BOX] = &BVHShapeDistancer<OBB, Box>::distance;
+  distance_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeDistancer<OBB, Sphere>::distance;
+  distance_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeDistancer<OBB, Capsule>::distance;
+  distance_matrix[BV_OBB][GEOM_CONE] = &BVHShapeDistancer<OBB, Cone>::distance;
+  distance_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeDistancer<OBB, Cylinder>::distance;
+  distance_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeDistancer<OBB, ConvexBase>::distance;
+  distance_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeDistancer<OBB, Plane>::distance;
+  distance_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeDistancer<OBB, Halfspace>::distance;
+
+  distance_matrix[BV_RSS][GEOM_BOX] = &BVHShapeDistancer<RSS, Box>::distance;
+  distance_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeDistancer<RSS, Sphere>::distance;
+  distance_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeDistancer<RSS, Capsule>::distance;
+  distance_matrix[BV_RSS][GEOM_CONE] = &BVHShapeDistancer<RSS, Cone>::distance;
+  distance_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeDistancer<RSS, Cylinder>::distance;
+  distance_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeDistancer<RSS, ConvexBase>::distance;
+  distance_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeDistancer<RSS, Plane>::distance;
+  distance_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeDistancer<RSS, Halfspace>::distance;
 
   /* KDOP distance not implemented */
   /*
-  distance_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeDistancer<KDOP<16>, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<16>, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<16>, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeDistancer<KDOP<16>, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<16>, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<16>, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeDistancer<KDOP<16>, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<16>, Halfspace, NarrowPhaseSolver>::distance;
-
-  distance_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeDistancer<KDOP<18>, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<18>, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<18>, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeDistancer<KDOP<18>, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<18>, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<18>, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeDistancer<KDOP<18>, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<18>, Halfspace, NarrowPhaseSolver>::distance;
-
-  distance_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeDistancer<KDOP<24>, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<24>, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<24>, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeDistancer<KDOP<24>, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<24>, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<24>, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeDistancer<KDOP<24>, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<24>, Halfspace, NarrowPhaseSolver>::distance;
+  distance_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeDistancer<KDOP<16>, Box>::distance;
+  distance_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<16>, Sphere>::distance;
+  distance_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<16>, Capsule>::distance;
+  distance_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeDistancer<KDOP<16>, Cone>::distance;
+  distance_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<16>, Cylinder>::distance;
+  distance_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<16>, ConvexBase>::distance;
+  distance_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeDistancer<KDOP<16>, Plane>::distance;
+  distance_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<16>, Halfspace>::distance;
+
+  distance_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeDistancer<KDOP<18>, Box>::distance;
+  distance_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<18>, Sphere>::distance;
+  distance_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<18>, Capsule>::distance;
+  distance_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeDistancer<KDOP<18>, Cone>::distance;
+  distance_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<18>, Cylinder>::distance;
+  distance_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<18>, ConvexBase>::distance;
+  distance_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeDistancer<KDOP<18>, Plane>::distance;
+  distance_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<18>, Halfspace>::distance;
+
+  distance_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeDistancer<KDOP<24>, Box>::distance;
+  distance_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<24>, Sphere>::distance;
+  distance_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<24>, Capsule>::distance;
+  distance_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeDistancer<KDOP<24>, Cone>::distance;
+  distance_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<24>, Cylinder>::distance;
+  distance_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<24>, ConvexBase>::distance;
+  distance_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeDistancer<KDOP<24>, Plane>::distance;
+  distance_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<24>, Halfspace>::distance;
   */
 
-  distance_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeDistancer<kIOS, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeDistancer<kIOS, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeDistancer<kIOS, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeDistancer<kIOS, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeDistancer<kIOS, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeDistancer<kIOS, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeDistancer<kIOS, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeDistancer<kIOS, Halfspace, NarrowPhaseSolver>::distance;
-
-  distance_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeDistancer<OBBRSS, Box, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeDistancer<OBBRSS, Sphere, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeDistancer<OBBRSS, Capsule, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeDistancer<OBBRSS, Cone, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeDistancer<OBBRSS, Cylinder, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeDistancer<OBBRSS, Convex, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeDistancer<OBBRSS, Plane, NarrowPhaseSolver>::distance;
-  distance_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeDistancer<OBBRSS, Halfspace, NarrowPhaseSolver>::distance;
-
-  distance_matrix[BV_AABB][BV_AABB] = &BVHDistance<AABB, NarrowPhaseSolver>;
-  distance_matrix[BV_OBB][BV_OBB] = &BVHDistance<OBB, NarrowPhaseSolver>;
-  distance_matrix[BV_RSS][BV_RSS] = &BVHDistance<RSS, NarrowPhaseSolver>;
-  distance_matrix[BV_kIOS][BV_kIOS] = &BVHDistance<kIOS, NarrowPhaseSolver>;
-  distance_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHDistance<OBBRSS, NarrowPhaseSolver>;
+  distance_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeDistancer<kIOS, Box>::distance;
+  distance_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeDistancer<kIOS, Sphere>::distance;
+  distance_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeDistancer<kIOS, Capsule>::distance;
+  distance_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeDistancer<kIOS, Cone>::distance;
+  distance_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeDistancer<kIOS, Cylinder>::distance;
+  distance_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeDistancer<kIOS, ConvexBase>::distance;
+  distance_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeDistancer<kIOS, Plane>::distance;
+  distance_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeDistancer<kIOS, Halfspace>::distance;
+
+  distance_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeDistancer<OBBRSS, Box>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeDistancer<OBBRSS, Sphere>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeDistancer<OBBRSS, Capsule>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeDistancer<OBBRSS, Cone>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeDistancer<OBBRSS, Cylinder>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeDistancer<OBBRSS, ConvexBase>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeDistancer<OBBRSS, Plane>::distance;
+  distance_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeDistancer<OBBRSS, Halfspace>::distance;
+
+  distance_matrix[BV_AABB][BV_AABB] = &BVHDistance<AABB>;
+  distance_matrix[BV_OBB][BV_OBB] = &BVHDistance<OBB>;
+  distance_matrix[BV_RSS][BV_RSS] = &BVHDistance<RSS>;
+  distance_matrix[BV_kIOS][BV_kIOS] = &BVHDistance<kIOS>;
+  distance_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHDistance<OBBRSS>;
 
 #ifdef HPP_FCL_HAVE_OCTOMAP
-  distance_matrix[GEOM_OCTREE][GEOM_BOX] = &OcTreeShapeDistance<Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_SPHERE] = &OcTreeShapeDistance<Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &OcTreeShapeDistance<Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_CONE] = &OcTreeShapeDistance<Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &OcTreeShapeDistance<Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_CONVEX] = &OcTreeShapeDistance<Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_PLANE] = &OcTreeShapeDistance<Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &OcTreeShapeDistance<Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_BOX][GEOM_OCTREE] = &ShapeOcTreeDistance<Box, NarrowPhaseSolver>;
-  distance_matrix[GEOM_SPHERE][GEOM_OCTREE] = &ShapeOcTreeDistance<Sphere, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &ShapeOcTreeDistance<Capsule, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONE][GEOM_OCTREE] = &ShapeOcTreeDistance<Cone, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &ShapeOcTreeDistance<Cylinder, NarrowPhaseSolver>;
-  distance_matrix[GEOM_CONVEX][GEOM_OCTREE] = &ShapeOcTreeDistance<Convex, NarrowPhaseSolver>;
-  distance_matrix[GEOM_PLANE][GEOM_OCTREE] = &ShapeOcTreeDistance<Plane, NarrowPhaseSolver>;
-  distance_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &ShapeOcTreeDistance<Halfspace, NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_OCTREE][GEOM_OCTREE] = &OcTreeDistance<NarrowPhaseSolver>;
-
-  distance_matrix[GEOM_OCTREE][BV_AABB] = &OcTreeBVHDistance<AABB, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_OBB] = &OcTreeBVHDistance<OBB, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_RSS] = &OcTreeBVHDistance<RSS, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_OBBRSS] = &OcTreeBVHDistance<OBBRSS, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_kIOS] = &OcTreeBVHDistance<kIOS, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_KDOP16] = &OcTreeBVHDistance<KDOP<16>, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_KDOP18] = &OcTreeBVHDistance<KDOP<18>, NarrowPhaseSolver>;
-  distance_matrix[GEOM_OCTREE][BV_KDOP24] = &OcTreeBVHDistance<KDOP<24>, NarrowPhaseSolver>;
-
-  distance_matrix[BV_AABB][GEOM_OCTREE] = &BVHOcTreeDistance<AABB, NarrowPhaseSolver>;
-  distance_matrix[BV_OBB][GEOM_OCTREE] = &BVHOcTreeDistance<OBB, NarrowPhaseSolver>;
-  distance_matrix[BV_RSS][GEOM_OCTREE] = &BVHOcTreeDistance<RSS, NarrowPhaseSolver>;
-  distance_matrix[BV_OBBRSS][GEOM_OCTREE] = &BVHOcTreeDistance<OBBRSS, NarrowPhaseSolver>;
-  distance_matrix[BV_kIOS][GEOM_OCTREE] = &BVHOcTreeDistance<kIOS, NarrowPhaseSolver>;
-  distance_matrix[BV_KDOP16][GEOM_OCTREE] = &BVHOcTreeDistance<KDOP<16>, NarrowPhaseSolver>;
-  distance_matrix[BV_KDOP18][GEOM_OCTREE] = &BVHOcTreeDistance<KDOP<18>, NarrowPhaseSolver>;
-  distance_matrix[BV_KDOP24][GEOM_OCTREE] = &BVHOcTreeDistance<KDOP<24>, NarrowPhaseSolver>;
+  distance_matrix[GEOM_OCTREE][GEOM_BOX] = &Distance<OcTree, Box>;
+  distance_matrix[GEOM_OCTREE][GEOM_SPHERE] = &Distance<OcTree, Sphere>;
+  distance_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &Distance<OcTree, Capsule>;
+  distance_matrix[GEOM_OCTREE][GEOM_CONE] = &Distance<OcTree, Cone>;
+  distance_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &Distance<OcTree, Cylinder>;
+  distance_matrix[GEOM_OCTREE][GEOM_CONVEX] = &Distance<OcTree, ConvexBase>;
+  distance_matrix[GEOM_OCTREE][GEOM_PLANE] = &Distance<OcTree, Plane>;
+  distance_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &Distance<OcTree, Halfspace>;
+
+  distance_matrix[GEOM_BOX][GEOM_OCTREE] = &Distance<Box, OcTree>;
+  distance_matrix[GEOM_SPHERE][GEOM_OCTREE] = &Distance<Sphere, OcTree>;
+  distance_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &Distance<Capsule, OcTree>;
+  distance_matrix[GEOM_CONE][GEOM_OCTREE] = &Distance<Cone, OcTree>;
+  distance_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &Distance<Cylinder, OcTree>;
+  distance_matrix[GEOM_CONVEX][GEOM_OCTREE] = &Distance<ConvexBase, OcTree>;
+  distance_matrix[GEOM_PLANE][GEOM_OCTREE] = &Distance<Plane, OcTree>;
+  distance_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &Distance<Halfspace, OcTree>;
+
+  distance_matrix[GEOM_OCTREE][GEOM_OCTREE] = &Distance<OcTree, OcTree>;
+
+  distance_matrix[GEOM_OCTREE][BV_AABB  ] = &Distance<OcTree, BVHModel<AABB     > >;
+  distance_matrix[GEOM_OCTREE][BV_OBB   ] = &Distance<OcTree, BVHModel<OBB      > >;
+  distance_matrix[GEOM_OCTREE][BV_RSS   ] = &Distance<OcTree, BVHModel<RSS      > >;
+  distance_matrix[GEOM_OCTREE][BV_OBBRSS] = &Distance<OcTree, BVHModel<OBBRSS   > >;
+  distance_matrix[GEOM_OCTREE][BV_kIOS  ] = &Distance<OcTree, BVHModel<kIOS     > >;
+  distance_matrix[GEOM_OCTREE][BV_KDOP16] = &Distance<OcTree, BVHModel<KDOP<16> > >;
+  distance_matrix[GEOM_OCTREE][BV_KDOP18] = &Distance<OcTree, BVHModel<KDOP<18> > >;
+  distance_matrix[GEOM_OCTREE][BV_KDOP24] = &Distance<OcTree, BVHModel<KDOP<24> > >;
+
+  distance_matrix[BV_AABB][GEOM_OCTREE  ] = &Distance<BVHModel<AABB     >, OcTree>;
+  distance_matrix[BV_OBB][GEOM_OCTREE   ] = &Distance<BVHModel<OBB      >, OcTree>;
+  distance_matrix[BV_RSS][GEOM_OCTREE   ] = &Distance<BVHModel<RSS      >, OcTree>;
+  distance_matrix[BV_OBBRSS][GEOM_OCTREE] = &Distance<BVHModel<OBBRSS   >, OcTree>;
+  distance_matrix[BV_kIOS][GEOM_OCTREE  ] = &Distance<BVHModel<kIOS     >, OcTree>;
+  distance_matrix[BV_KDOP16][GEOM_OCTREE] = &Distance<BVHModel<KDOP<16> >, OcTree>;
+  distance_matrix[BV_KDOP18][GEOM_OCTREE] = &Distance<BVHModel<KDOP<18> >, OcTree>;
+  distance_matrix[BV_KDOP24][GEOM_OCTREE] = &Distance<BVHModel<KDOP<24> >, OcTree>;
 #endif
 
 
 }
-template struct DistanceFunctionMatrix<GJKSolver_indep>;
+//template struct DistanceFunctionMatrix;
 }
 
 } // namespace hpp
diff --git a/src/distance_func_matrix.h b/src/distance_func_matrix.h
index 5cb194384daf982f891d858de1297038277673ba..3a142614f523f3a9e35b285c248a46852edebd6f 100644
--- a/src/distance_func_matrix.h
+++ b/src/distance_func_matrix.h
@@ -34,24 +34,35 @@
 
 /** \author Florent Lamiraux */
 
+#ifndef HPP_FCL_DISTANCE_FUNC_MATRIX_H
+#define HPP_FCL_DISTANCE_FUNC_MATRIX_H
+
+/// @cond INTERNAL
+
 #include <hpp/fcl/collision_data.h>
+#include <hpp/fcl/narrowphase/narrowphase.h>
 
 namespace hpp
 {
-namespace fcl {
-  template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver>
+namespace fcl
+{
+  template<typename T_SH1, typename T_SH2>
     FCL_REAL ShapeShapeDistance
     (const CollisionGeometry* o1, const Transform3f& tf1,
      const CollisionGeometry* o2, const Transform3f& tf2,
-     const NarrowPhaseSolver* nsolver, const DistanceRequest& request,
+     const GJKSolver* nsolver, const DistanceRequest& request,
      DistanceResult& result);
 
-  template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver>
+  template<typename T_SH1, typename T_SH2>
     std::size_t ShapeShapeCollide
     (const CollisionGeometry* o1, const Transform3f& tf1,
      const CollisionGeometry* o2, const Transform3f& tf2, 
-     const NarrowPhaseSolver* nsolver, const CollisionRequest& request,
+     const GJKSolver* nsolver, const CollisionRequest& request,
      CollisionResult& result);
 }
 
 } // namespace hpp
+
+/// @endcond
+
+#endif
\ No newline at end of file
diff --git a/src/distance_sphere_cylinder.cpp b/src/distance_sphere_cylinder.cpp
index 4b7387c30f4a728df647b5a53ffb07c86d9726d6..993933d98c11437394116540f907edf0ba0c8300 100644
--- a/src/distance_sphere_cylinder.cpp
+++ b/src/distance_sphere_cylinder.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Sphere, Cylinder, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Sphere, Cylinder>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Sphere& s1 = static_cast <const Sphere&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Cylinder, Sphere, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Cylinder, Sphere>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Cylinder& s1 = static_cast <const Cylinder&> (*o1);
diff --git a/src/distance_sphere_halfspace.cpp b/src/distance_sphere_halfspace.cpp
index 80c3bd95f1ebef818f448d0eaad851c6c036a3db..6c7b9b7435a01e4785b401640f1f35064103295f 100644
--- a/src/distance_sphere_halfspace.cpp
+++ b/src/distance_sphere_halfspace.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Sphere, Halfspace, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Sphere, Halfspace>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Sphere& s1 = static_cast <const Sphere&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Halfspace, Sphere, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Halfspace, Sphere>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Halfspace& s1 = static_cast <const Halfspace&> (*o1);
diff --git a/src/distance_sphere_plane.cpp b/src/distance_sphere_plane.cpp
index 7d0487629644113960e97fac60a7b85a9c74f095..28754534852fc053ed52621d8cedae1298ac8d22 100644
--- a/src/distance_sphere_plane.cpp
+++ b/src/distance_sphere_plane.cpp
@@ -40,19 +40,19 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
-#include "../src/narrowphase/details.h"
+#include <../src/distance_func_matrix.h>
+#include "narrowphase/details.h"
 
 namespace hpp
 {
 namespace fcl {
-    class GJKSolver_indep;
+    class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Sphere, Plane, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Sphere, Plane>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Sphere& s1 = static_cast <const Sphere&> (*o1);
@@ -65,10 +65,10 @@ namespace fcl {
   }
 
   template <>
-  FCL_REAL ShapeShapeDistance <Plane, Sphere, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Plane, Sphere>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     const Plane& s1 = static_cast <const Plane&> (*o1);
diff --git a/src/distance_sphere_sphere.cpp b/src/distance_sphere_sphere.cpp
index 40b383fde5bd4e96c36de2c7d74227bc458c3ceb..646ebe591b8e696690f6e94ee79d657df7851dd6 100644
--- a/src/distance_sphere_sphere.cpp
+++ b/src/distance_sphere_sphere.cpp
@@ -37,7 +37,7 @@
 #include <limits>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "distance_func_matrix.h"
+#include <../src/distance_func_matrix.h>
 
 // Note that partial specialization of template functions is not allowed.
 // Therefore, two implementations with the default narrow phase solvers are
@@ -50,13 +50,13 @@
 namespace hpp
 {
 namespace fcl {
-  class GJKSolver_indep;
+  class GJKSolver;
 
   template <>
-  FCL_REAL ShapeShapeDistance <Sphere, Sphere, GJKSolver_indep>
+  FCL_REAL ShapeShapeDistance <Sphere, Sphere>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const DistanceRequest&,
+   const GJKSolver*, const DistanceRequest&,
    DistanceResult& result)
   {
     FCL_REAL epsilon = 1e-7;
@@ -97,10 +97,10 @@ namespace fcl {
   }
 
   template <>
-  std::size_t ShapeShapeCollide <Sphere, Sphere, GJKSolver_indep>
+  std::size_t ShapeShapeCollide <Sphere, Sphere>
   (const CollisionGeometry* o1, const Transform3f& tf1,
    const CollisionGeometry* o2, const Transform3f& tf2,
-   const GJKSolver_indep*, const CollisionRequest& request,
+   const GJKSolver*, const CollisionRequest& request,
    CollisionResult& result)
   {
     FCL_REAL epsilon = 1e-7;
diff --git a/src/intersect.cpp b/src/intersect.cpp
index e2bdab97bebe1319b7165ca8b2119f6a65df90c0..8cbfdda4a15cf66485de4ab22342000cb00563e6 100644
--- a/src/intersect.cpp
+++ b/src/intersect.cpp
@@ -35,144 +35,17 @@
 
 /** \author Jia Pan */
 
-#include <hpp/fcl/intersect.h>
+#include <hpp/fcl/internal/intersect.h>
 #include <iostream>
 #include <limits>
 #include <vector>
 #include <boost/math/special_functions/fpclassify.hpp>
+#include <hpp/fcl/internal/tools.h>
 
 namespace hpp
 {
 namespace fcl
 {
-const FCL_REAL PolySolver::NEAR_ZERO_THRESHOLD = 1e-9;
-
-
-bool PolySolver::isZero(FCL_REAL v)
-{
-  return (v < NEAR_ZERO_THRESHOLD) && (v > -NEAR_ZERO_THRESHOLD);
-}
-
-bool PolySolver::cbrt(FCL_REAL v)
-{
-  return powf((float) v, (float) (1.0 / 3.0));
-}
-
-int PolySolver::solveLinear(FCL_REAL c[2], FCL_REAL s[1])
-{
-  if(isZero(c[1]))
-    return 0;
-  s[0] = - c[0] / c[1];
-  return 1;
-}
-
-int PolySolver::solveQuadric(FCL_REAL c[3], FCL_REAL s[2])
-{
-  FCL_REAL p, q, D;
-
-  // make sure we have a d2 equation
-
-  if(isZero(c[2]))
-    return solveLinear(c, s);
-
-  // normal for: x^2 + px + q
-  p = c[1] / (2.0 * c[2]);
-  q = c[0] / c[2];
-  D = p * p - q;
-
-  if(isZero(D))
-  {
-    // one FCL_REAL root
-    s[0] = s[1] = -p;
-    return 1;
-  }
-
-  if(D < 0.0)
-    // no real root
-    return 0;
-  else
-  {
-    // two real roots
-    FCL_REAL sqrt_D = sqrt(D);
-    s[0] = sqrt_D - p;
-    s[1] = -sqrt_D - p;
-    return 2;
-  }
-}
-
-int PolySolver::solveCubic(FCL_REAL c[4], FCL_REAL s[3])
-{
-  int i, num;
-  FCL_REAL sub, A, B, C, sq_A, p, q, cb_p, D;
-  const FCL_REAL ONE_OVER_THREE = 1 / 3.0;
-  const FCL_REAL PI = 3.14159265358979323846;
-
-  // make sure we have a d2 equation
-  if(isZero(c[3]))
-    return solveQuadric(c, s);
-
-  // normalize the equation:x ^ 3 + Ax ^ 2 + Bx  + C = 0
-  A = c[2] / c[3];
-  B = c[1] / c[3];
-  C = c[0] / c[3];
-
-  // substitute x = y - A / 3 to eliminate the quadratic term: x^3 + px + q = 0
-  sq_A = A * A;
-  p = (-ONE_OVER_THREE * sq_A + B) * ONE_OVER_THREE;
-  q = 0.5 * (2.0 / 27.0 * A * sq_A - ONE_OVER_THREE * A * B + C);
-
-  // use Cardano's formula
-  cb_p = p * p * p;
-  D = q * q + cb_p;
-
-  if(isZero(D))
-  {
-    if(isZero(q))
-    {
-      // one triple solution
-      s[0] = 0.0;
-      num = 1;
-    }
-    else
-    {
-      // one single and one FCL_REAL solution
-      FCL_REAL u = cbrt(-q);
-      s[0] = 2.0 * u;
-      s[1] = -u;
-      num = 2;
-    }
-  }
-  else
-  {
-    if(D < 0.0)
-    {
-      // three real solutions
-      FCL_REAL phi = ONE_OVER_THREE * acos(-q / sqrt(-cb_p));
-      FCL_REAL t = 2.0 * sqrt(-p);
-      s[0] = t * cos(phi);
-      s[1] = -t * cos(phi + PI / 3.0);
-      s[2] = -t * cos(phi - PI / 3.0);
-      num = 3;
-    }
-    else
-    {
-      // one real solution
-      FCL_REAL sqrt_D = sqrt(D);
-      FCL_REAL u = cbrt(sqrt_D + fabs(q));
-      if(q > 0.0)
-        s[0] = - u + p / u ;
-      else
-        s[0] = u - p / u;
-      num = 1;
-    }
-  }
-
-  // re-substitute
-  sub = ONE_OVER_THREE * A;
-  for(i = 0; i < num; i++)
-    s[i] -= sub;
-  return num;
-}
 
 bool Intersect::buildTrianglePlane
 (const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, FCL_REAL* t)
diff --git a/src/math/transform.cpp b/src/math/transform.cpp
index 9e6b31c8e7ad71672ba495bd39c1873655003b4f..1e8c15bf81b195fffa2d8ab9aba555c77e7fb5a3 100644
--- a/src/math/transform.cpp
+++ b/src/math/transform.cpp
@@ -44,36 +44,17 @@ namespace hpp
 namespace fcl
 {
 
-const Matrix3f& Transform3f::getRotationInternal() const
-{
-  if(!matrix_set)
-  {
-    R = q.toRotationMatrix();
-    matrix_set = true;
-  }
-
-  return R;
-}
-
-Transform3f inverse(const Transform3f& tf)
-{
-  Transform3f res(tf);
-  return res.inverse();
-}
-
 void relativeTransform(const Transform3f& tf1, const Transform3f& tf2,
                        Transform3f& tf)
 {
-  const Quaternion3f& q1_inv = tf1.getQuatRotation().conjugate();
-  tf = Transform3f(q1_inv * tf2.getQuatRotation(), q1_inv * (tf2.getTranslation() - tf1.getTranslation()));
+  tf = tf1.inverseTimes (tf2);
 }
 
 void relativeTransform2(const Transform3f& tf1, const Transform3f& tf2,
                        Transform3f& tf)
 {
-  const Quaternion3f& q1inv = tf1.getQuatRotation().conjugate();
-  const Quaternion3f& q2_q1inv = tf2.getQuatRotation() * q1inv;
-  tf = Transform3f(q2_q1inv, tf2.getTranslation() - q2_q1inv * tf1.getTranslation());
+  Matrix3f R (tf2.getRotation() * tf1.getRotation().transpose());
+  tf = Transform3f(R, tf2.getTranslation() - R * tf1.getTranslation());
 }
 
 
diff --git a/src/mesh_loader/assimp.cpp b/src/mesh_loader/assimp.cpp
index 7e58853a73f8bdf86b1202e1e08b62cb933f3ca8..2645a4be2e07729b069eabe4bf8d00647a09e352 100644
--- a/src/mesh_loader/assimp.cpp
+++ b/src/mesh_loader/assimp.cpp
@@ -34,16 +34,102 @@
 
 #include <hpp/fcl/mesh_loader/assimp.h>
 
+// Assimp >= 5.0 is forcing the use of C++11 keywords. A fix has been submitted https://github.com/assimp/assimp/pull/2758.
+// The next lines fixes the bug for current version of hpp-fcl.
+#include <assimp/defs.h>
+#if __cplusplus < 201103L && defined(AI_NO_EXCEPT)
+  #undef AI_NO_EXCEPT
+  #define AI_NO_EXCEPT
+#endif
+
+#ifdef HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES
+  #include <assimp/DefaultLogger.hpp>
+  #include <assimp/IOStream.hpp>
+  #include <assimp/IOSystem.hpp>
+  #include <assimp/Importer.hpp>
+  #include <assimp/postprocess.h>
+  #include <assimp/scene.h>
+#else
+  #include <assimp/DefaultLogger.h>
+  #include <assimp/assimp.hpp>
+  #include <assimp/IOStream.h>
+  #include <assimp/IOSystem.h>
+  #include <assimp/aiPostProcess.h>
+  #include <assimp/aiScene.h>
+#endif
+
 namespace hpp
 {
 namespace fcl
 {
   
-unsigned buildMesh (const fcl::Vec3f & scale,
-                    const aiScene* scene,
-                    const aiNode* node,
-                    unsigned vertices_offset,
-                    TriangleAndVertices & tv)
+namespace internal
+{
+
+Loader::Loader () : importer (new Assimp::Importer())
+{
+  // set list of ignored parameters (parameters used for rendering)
+  importer->SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
+      aiComponent_TANGENTS_AND_BITANGENTS|
+      aiComponent_COLORS |
+      aiComponent_BONEWEIGHTS |
+      aiComponent_ANIMATIONS |
+      aiComponent_LIGHTS |
+      aiComponent_CAMERAS|
+      aiComponent_TEXTURES |
+      aiComponent_TEXCOORDS |
+      aiComponent_MATERIALS |
+      aiComponent_NORMALS
+      );
+
+}
+
+Loader::~Loader ()
+{
+ if (importer) delete importer;
+}
+
+void Loader::load (const std::string & resource_path)
+{
+  scene = importer->ReadFile(resource_path.c_str(),
+      aiProcess_SortByPType |
+      aiProcess_Triangulate |
+      aiProcess_RemoveComponent |
+      aiProcess_ImproveCacheLocality |
+      // TODO: I (Joseph Mirabel) have no idea whether degenerated triangles are
+      // properly handled. Enabling aiProcess_FindDegenerates would throw an
+      // exception when that happens. Is it too conservative ?
+      // aiProcess_FindDegenerates |
+      aiProcess_JoinIdenticalVertices
+      );
+
+  if (!scene)
+  {
+    const std::string exception_message (std::string ("Could not load resource ") + resource_path + std::string("\n") +
+                                         importer->GetErrorString () + std::string("\n") +
+                                         "Hint: the mesh directory may be wrong.");
+    throw std::invalid_argument(exception_message);
+  }
+
+  if (!scene->HasMeshes())
+    throw std::invalid_argument (std::string ("No meshes found in file ")+resource_path);
+}
+
+/**
+ * @brief      Recursive procedure for building a mesh
+ *
+ * @param[in]  scale           Scale to apply when reading the ressource
+ * @param[in]  scene           Pointer to the assimp scene
+ * @param[in]  node            Current node of the scene
+ * @param[in]  vertices_offset Current number of vertices in the model
+ * @param      tv              Triangles and Vertices of the mesh submodels
+ */
+unsigned recurseBuildMesh (
+    const fcl::Vec3f & scale,
+    const aiScene* scene,
+    const aiNode* node,
+    unsigned vertices_offset,
+    TriangleAndVertices & tv)
 {
   if (!node) return 0;
   
@@ -100,12 +186,20 @@ unsigned buildMesh (const fcl::Vec3f & scale,
   
   for (uint32_t i=0; i < node->mNumChildren; ++i)
   {
-    nbVertices += buildMesh(scale, scene, node->mChildren[i], nbVertices, tv);
+    nbVertices += recurseBuildMesh(scale, scene, node->mChildren[i], nbVertices, tv);
   }
 
   return nbVertices;
 }
 
+void buildMesh (const fcl::Vec3f & scale,
+                    const aiScene* scene,
+                    unsigned vertices_offset,
+                    TriangleAndVertices & tv)
+{
+  recurseBuildMesh (scale, scene, scene->mRootNode, vertices_offset, tv);
 }
 
+} // namespace internal
+} // namespace fcl
 } // namespace hpp
diff --git a/src/mesh_loader/loader.cpp b/src/mesh_loader/loader.cpp
index d2e9b36a2f7ded1cc9922ff8896365870d717477..4646a8bb603ebbe5b064439a7980706527ea25f8 100644
--- a/src/mesh_loader/loader.cpp
+++ b/src/mesh_loader/loader.cpp
@@ -53,14 +53,14 @@ namespace fcl {
   }
 
   template <typename BV>
-  CollisionGeometryPtr_t _load (const std::string& filename, const Vec3f& scale)
+  BVHModelPtr_t _load (const std::string& filename, const Vec3f& scale)
   {
     boost::shared_ptr < BVHModel<BV> > polyhedron (new BVHModel<BV>);
     loadPolyhedronFromResource (filename, scale, polyhedron);
     return polyhedron;
   }
 
-  CollisionGeometryPtr_t MeshLoader::load (const std::string& filename,
+  BVHModelPtr_t MeshLoader::load (const std::string& filename,
       const Vec3f& scale)
   {
     switch (bvType_) {
@@ -77,13 +77,13 @@ namespace fcl {
     }
   }
 
-  CollisionGeometryPtr_t CachedMeshLoader::load (const std::string& filename,
+  BVHModelPtr_t CachedMeshLoader::load (const std::string& filename,
       const Vec3f& scale)
   {
     Key key (filename, scale);
     Cache_t::const_iterator _cached = cache_.find (key);
     if (_cached == cache_.end()) {
-      CollisionGeometryPtr_t geom = MeshLoader::load (filename, scale);
+      BVHModelPtr_t geom = MeshLoader::load (filename, scale);
       cache_.insert (std::make_pair(key, geom));
       return geom;
     } else {
diff --git a/src/narrowphase/details.h b/src/narrowphase/details.h
index ee654943ab14cf258533fecef8366f6ba74f66f2..58036184bf7a6e40b6d75fbb9e73ac39e19f6375 100644
--- a/src/narrowphase/details.h
+++ b/src/narrowphase/details.h
@@ -38,8 +38,7 @@
 #ifndef HPP_FCL_SRC_NARROWPHASE_DETAILS_H
 # define HPP_FCL_SRC_NARROWPHASE_DETAILS_H
 
-#include <hpp/fcl/collision_node.h>
-#include <hpp/fcl/traversal/traversal_node_setup.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
 #include <hpp/fcl/narrowphase/narrowphase.h>
 
 namespace hpp
@@ -74,11 +73,8 @@ namespace fcl {
        const Capsule& s2, const Transform3f& tf2,
        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal_)
     {
-      Transform3f tf2_inv (tf2);
-      tf2_inv.inverse();
-
-      Vec3f pos1 (tf2.transform (Vec3f (0., 0., 0.5 * s2.lz))); // from distance function
-      Vec3f pos2 (tf2.transform (Vec3f (0., 0., -0.5 * s2.lz)));
+      Vec3f pos1 (tf2.transform (Vec3f (0., 0.,  s2.halfLength))); // from distance function
+      Vec3f pos2 (tf2.transform (Vec3f (0., 0., -s2.halfLength)));
       Vec3f s_c = tf1.getTranslation ();
 
       Vec3f segment_point;
@@ -112,11 +108,8 @@ namespace fcl {
        const Capsule& s2, const Transform3f& tf2,
        FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal)
     {
-      Transform3f tf2_inv(tf2);
-      tf2_inv.inverse();
-
-      Vec3f pos1 (tf2.transform (Vec3f (0., 0., 0.5 * s2.lz)));
-      Vec3f pos2 (tf2.transform (Vec3f (0., 0., -0.5 * s2.lz)));
+      Vec3f pos1 (tf2.transform (Vec3f (0., 0.,  s2.halfLength)));
+      Vec3f pos2 (tf2.transform (Vec3f (0., 0., -s2.halfLength)));
       Vec3f s_c = tf1.getTranslation ();
 
       Vec3f segment_point;
@@ -126,7 +119,7 @@ namespace fcl {
       FCL_REAL norm (normal.norm());
       dist = norm - s1.radius - s2.radius;
 
-      FCL_REAL eps (std::numeric_limits<FCL_REAL>::epsilon());
+      static const FCL_REAL eps (std::numeric_limits<FCL_REAL>::epsilon());
       if (norm > eps) {
         normal.normalize();
       } else {
@@ -147,10 +140,10 @@ namespace fcl {
        const Cylinder& s2, const Transform3f& tf2,
        FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal)
     {
-      FCL_REAL eps (sqrt (std::numeric_limits <FCL_REAL>::epsilon ()));
+      static const FCL_REAL eps (sqrt (std::numeric_limits <FCL_REAL>::epsilon ()));
       FCL_REAL r1 (s1.radius);
       FCL_REAL r2 (s2.radius);
-      FCL_REAL lz2 (.5*s2.lz);
+      FCL_REAL lz2 (s2.halfLength);
       // boundaries of the cylinder axis
       Vec3f A (tf2.transform (Vec3f (0, 0, -lz2)));
       Vec3f B (tf2.transform (Vec3f (0, 0,  lz2)));
@@ -158,7 +151,7 @@ namespace fcl {
       Vec3f S (tf1.getTranslation ());
       // axis of the cylinder
       Vec3f u (tf2.getRotation ().col (2));
-      assert ((B - A - s2.lz * u).norm () < eps);
+      assert ((B - A - (s2.halfLength * 2) * u).norm () < eps);
       Vec3f AS (S - A);
       // abscissa of S on cylinder axis with A as the origin
       FCL_REAL s (u.dot (AS));
@@ -193,7 +186,7 @@ namespace fcl {
             dist = -r1;
           }
         }
-      } else if (s <= s2.lz) {
+      } else if (s <= (s2.halfLength * 2)) {
         // 0 < s <= s2.lz
         normal = -v;
         dist = dPS - r1 - r2;
@@ -207,7 +200,7 @@ namespace fcl {
         // lz < s
         if (dPS <= r2) {
           // closest point on cylinder is on cylinder disc basis
-          dist = s - s2.lz - r1; p1 = S - r1 * u; p2 = B + dPS * v; normal = -u;
+          dist = s - (s2.halfLength * 2) - r1; p1 = S - r1 * u; p2 = B + dPS * v; normal = -u;
         } else {
           // closest point on cylinder is on cylinder circle basis
           p2 = B + r2 * v;
@@ -280,7 +273,7 @@ namespace fcl {
       return (dist >=0);
     }
 
-    /** \brief the minimum distance from a point to a line */
+    /** @brief the minimum distance from a point to a line */
     inline FCL_REAL segmentSqrDistance
       (const Vec3f& from, const Vec3f& to,const Vec3f& p, Vec3f& nearest)
     {
@@ -860,8 +853,8 @@ namespace fcl {
 
 
 
-    inline int boxBox2(const Vec3f& side1, const Matrix3f& R1, const Vec3f& T1,
-                       const Vec3f& side2, const Matrix3f& R2, const Vec3f& T2,
+    inline int boxBox2(const Vec3f& halfSide1, const Matrix3f& R1, const Vec3f& T1,
+                       const Vec3f& halfSide2, const Matrix3f& R2, const Vec3f& T2,
                        Vec3f& normal, FCL_REAL* depth, int* return_code,
                        int maxc, std::vector<ContactPoint>& contacts)
     {
@@ -874,8 +867,8 @@ namespace fcl {
       Vec3f pp (R1.transpose() * p); // get pp = p relative to body 1
 
       // get side lengths / 2
-      Vec3f A (side1 * 0.5);
-      Vec3f B (side2 * 0.5);
+      const Vec3f& A (halfSide1);
+      const Vec3f& B (halfSide2);
 
       // Rij is R1'*R2, i.e. the relative rotation between R1 and R2
       Matrix3f R (R1.transpose() * R2);
@@ -979,7 +972,7 @@ namespace fcl {
       Q.array() += fudge2;
 
       Vec3f n;
-      FCL_REAL eps = std::numeric_limits<FCL_REAL>::epsilon();
+      static const FCL_REAL eps = std::numeric_limits<FCL_REAL>::epsilon();
 
       // separating axis = u1 x (v1,v2,v3)
       tmp = pp[2] * R(1, 0) - pp[1] * R(2, 0);
@@ -1443,8 +1436,8 @@ namespace fcl {
       int return_code;
       Vec3f normal;
       FCL_REAL depth;
-      /* int cnum = */ boxBox2(s1.side, tf1.getRotation(), tf1.getTranslation(),
-                               s2.side, tf2.getRotation(), tf2.getTranslation(),
+      /* int cnum = */ boxBox2(s1.halfSide, tf1.getRotation(), tf1.getTranslation(),
+                               s2.halfSide, tf2.getRotation(), tf2.getTranslation(),
                                normal, &depth, &return_code,
                                4, contacts);
 
@@ -1518,11 +1511,9 @@ namespace fcl {
       const Matrix3f& R = tf1.getRotation();
       const Vec3f& T = tf1.getTranslation();
 
-      Vec3f Q = R.transpose() * new_s2.n;
-      Vec3f A(Q[0] * s1.side[0], Q[1] * s1.side[1], Q[2] * s1.side[2]);
-      Vec3f B = A.cwiseAbs();
+      Vec3f Q (R.transpose() * new_s2.n);
 
-      FCL_REAL depth = 0.5 * (B[0] + B[1] + B[2]) - new_s2.signedDistance(T);
+      FCL_REAL depth = Q.cwiseProduct(s1.halfSide).lpNorm<1>() - new_s2.signedDistance(T);
       return (depth >= 0);
     }
 
@@ -1538,27 +1529,17 @@ namespace fcl {
       const Vec3f& T = tf1.getTranslation();
 
       // Q: plane normal expressed in box frame
-      Vec3f Q = R.transpose() * new_s2.n;
+      const Vec3f Q (R.transpose() * new_s2.n);
       // A: scalar products of each side with normal
-      Vec3f A(Q[0] * s1.side[0], Q[1] * s1.side[1], Q[2] * s1.side[2]);
-      Vec3f B = A.cwiseAbs();
+      const Vec3f A (Q.cwiseProduct(s1.halfSide));
 
-      distance = new_s2.signedDistance(T) - 0.5 * (B[0] + B[1] + B[2]);
+      distance = new_s2.signedDistance(T) - A.lpNorm<1>();
       if(distance > 0) {
-        p1 = T;
-        for (Vec3f::Index i=0; i<3; ++i) {
-          p1 -= A [i] > 0 ? (-.5 * s1.side [i] * R.col (i)) :
-            (.5 * s1.side [i] * R.col (i));
-        }
-        p2 = p1 - distance * new_s2.n;
+        p1.noalias() = T + R * (A.array() > 0).select (s1.halfSide, - s1.halfSide);
+        p2.noalias() = p1 - distance * new_s2.n;
         return false;
       }
 
-      Vec3f axis[3];
-      axis[0] = R.col(0);
-      axis[1] = R.col(1);
-      axis[2] = R.col(2);
-
       /// find deepest point
       Vec3f p(T);
       int sign = 0;
@@ -1566,25 +1547,21 @@ namespace fcl {
       if(std::abs(Q[0] - 1) < halfspaceIntersectTolerance<FCL_REAL>() || std::abs(Q[0] + 1) < halfspaceIntersectTolerance<FCL_REAL>())
         {
           sign = (A[0] > 0) ? -1 : 1;
-          p += axis[0] * (0.5 * s1.side[0] * sign);
+          p += R.col(0) * (s1.halfSide[0] * sign);
         }
       else if(std::abs(Q[1] - 1) < halfspaceIntersectTolerance<FCL_REAL>() || std::abs(Q[1] + 1) < halfspaceIntersectTolerance<FCL_REAL>())
         {
           sign = (A[1] > 0) ? -1 : 1;
-          p += axis[1] * (0.5 * s1.side[1] * sign);
+          p += R.col(1) * (s1.halfSide[1] * sign);
         }
       else if(std::abs(Q[2] - 1) < halfspaceIntersectTolerance<FCL_REAL>() || std::abs(Q[2] + 1) < halfspaceIntersectTolerance<FCL_REAL>())
         {
           sign = (A[2] > 0) ? -1 : 1;
-          p += axis[2] * (0.5 * s1.side[2] * sign);
+          p += R.col(2) * (s1.halfSide[2] * sign);
         }
       else
         {
-          for(std::size_t i = 0; i < 3; ++i)
-            {
-              sign = (A[i] > 0) ? -1 : 1;
-              p += axis[i] * (0.5 * s1.side[i] * sign);
-            }
+          p.noalias() += R * (A.array() > 0).select (-s1.halfSide, s1.halfSide);
         }
 
       /// compute the contact point from the deepest point
@@ -1628,7 +1605,7 @@ namespace fcl {
           int sign = (cosa > 0) ? -1 : 1;
           // closest capsule vertex to halfspace if no collision,
           // or deeper inside halspace if collision
-          Vec3f p = T + dir_z * (s1.lz * 0.5 * sign);
+          Vec3f p = T + dir_z * (s1.halfLength * sign);
 
           FCL_REAL signed_dist = new_s2.signedDistance(p);
           distance = signed_dist - s1.radius;
@@ -1689,7 +1666,7 @@ namespace fcl {
 
           int sign = (cosa > 0) ? -1 : 1;
           // deepest point
-          Vec3f p = T + dir_z * (s1.lz * 0.5 * sign) + C;
+          Vec3f p = T + dir_z * (s1.halfLength * sign) + C;
           distance = new_s2.signedDistance(p);
           if(distance > 0) {
             // TODO: compute closest points
@@ -1731,7 +1708,7 @@ namespace fcl {
           else
             {
               normal = -new_s2.n;
-              p1 = p2 = T - dir_z * (s1.lz * 0.5) -
+              p1 = p2 = T - dir_z * (s1.halfLength) -
                 new_s2.n * (0.5 * distance + s1.radius);
               return true;
             }
@@ -1749,8 +1726,8 @@ namespace fcl {
               C *= s;
             }
 
-          Vec3f a1 = T + dir_z * (0.5 * s1.lz);
-          Vec3f a2 = T - dir_z * (0.5 * s1.lz) + C;
+          Vec3f a1 = T + dir_z * (s1.halfLength);
+          Vec3f a2 = T - dir_z * (s1.halfLength) + C;
 
           FCL_REAL d1 = new_s2.signedDistance(a1);
           FCL_REAL d2 = new_s2.signedDistance(a2);
@@ -1767,7 +1744,7 @@ namespace fcl {
     }
 
     inline bool convexHalfspaceIntersect
-      (const Convex& s1, const Transform3f& tf1,
+      (const ConvexBase& s1, const Transform3f& tf1,
        const Halfspace& s2, const Transform3f& tf2,
        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal)
     {
@@ -2040,33 +2017,32 @@ namespace fcl {
     //                            Vec3f* contact_points,
     //                            FCL_REAL* penetration_depth, Vec3f* normal)
     {
-      FCL_REAL eps (sqrt (std::numeric_limits<FCL_REAL>::epsilon()));
+      static const FCL_REAL eps (sqrt (std::numeric_limits<FCL_REAL>::epsilon()));
       Plane new_s2 = transform(s2, tf2);
 
       const Matrix3f& R = tf1.getRotation();
       const Vec3f& T = tf1.getTranslation();
 
-      Vec3f Q = R.transpose() * new_s2.n;
-      Vec3f A(Q[0] * s1.side[0], Q[1] * s1.side[1], Q[2] * s1.side[2]);
-      Vec3f B = A.cwiseAbs();
+      const Vec3f Q (R.transpose() * new_s2.n);
+      const Vec3f A (Q.cwiseProduct(s1.halfSide));
 
       FCL_REAL signed_dist = new_s2.signedDistance(T);
-      distance = std::abs(signed_dist) - 0.5 * (B[0] + B[1] + B[2]);
+      distance = std::abs(signed_dist) - A.lpNorm<1>();
       if(distance > 0) {
         // Is the box above or below the plane
-        int sign = signed_dist > 0 ? 1 : -1;
+        const bool positive = signed_dist > 0;
         // Set p1 at the center of the box
         p1 = T;
         for (Vec3f::Index i=0; i<3; ++i) {
           // scalar product between box axis and plane normal
-          FCL_REAL alpha (R.col (i).dot (new_s2.n));
-          if (sign * alpha > eps) {
-            p1 -= .5 * R.col (i) * s1.side [i];
-          } else if (sign * alpha < -eps) {
-            p1 += .5 * R.col (i) * s1.side [i];
+          FCL_REAL alpha ((positive ? 1 : -1 ) * R.col (i).dot (new_s2.n));
+          if (alpha > eps) {
+            p1 -= R.col (i) * s1.halfSide [i];
+          } else if (alpha < -eps) {
+            p1 += R.col (i) * s1.halfSide [i];
           }
         }
-        p2 = p1 - sign * distance * new_s2.n;
+        p2 = p1 - ( positive ? distance : -distance) * new_s2.n;
         assert (new_s2.distance (p2) < 3 *eps);
         return false;
       }
@@ -2087,32 +2063,25 @@ namespace fcl {
       if(std::abs(Q[0] - 1) < planeIntersectTolerance<FCL_REAL>() ||
          std::abs(Q[0] + 1) < planeIntersectTolerance<FCL_REAL>())
         {
-          int sign2 = (A[0] > 0) ? -1 : 1;
-          sign2 *= sign;
-          p += axis[0] * (0.5 * s1.side[0] * sign2);
+          int sign2 = (A[0] > 0) ? -sign : sign;
+          p += R.col(0) * (s1.halfSide[0] * sign2);
         }
       else if(std::abs(Q[1] - 1) < planeIntersectTolerance<FCL_REAL>() ||
               std::abs(Q[1] + 1) < planeIntersectTolerance<FCL_REAL>())
         {
-          int sign2 = (A[1] > 0) ? -1 : 1;
-          sign2 *= sign;
-          p += axis[1] * (0.5 * s1.side[1] * sign2);
+          int sign2 = (A[1] > 0) ? -sign : sign;
+          p += R.col(1) * (s1.halfSide[1] * sign2);
         }
       else if(std::abs(Q[2] - 1) < planeIntersectTolerance<FCL_REAL>() ||
               std::abs(Q[2] + 1) < planeIntersectTolerance<FCL_REAL>())
         {
-          int sign2 = (A[2] > 0) ? -1 : 1;
-          sign2 *= sign;
-          p += axis[2] * (0.5 * s1.side[2] * sign2);
+          int sign2 = (A[2] > 0) ? -sign : sign;
+          p += R.col(2) * (s1.halfSide[2] * sign2);
         }
       else
         {
-          for(std::size_t i = 0; i < 3; ++i)
-            {
-              int sign2 = (A[i] > 0) ? -1 : 1;
-              sign2 *= sign;
-              p += axis[i] * (0.5 * s1.side[i] * sign2);
-            }
+          Vec3f tmp(sign * R * s1.halfSide);
+          p += (A.array() > 0).select (- tmp, tmp);
         }
 
       // compute the contact point by project the deepest point onto the plane
@@ -2123,11 +2092,11 @@ namespace fcl {
     }
 
     /// Taken from book Real Time Collision Detection, from Christer Ericson
-    /// \param pb the closest point to the sphere center on the box surface
-    /// \param ps when colliding, matches pb, which is inside the sphere.
+    /// @param pb the closest point to the sphere center on the box surface
+    /// @param ps when colliding, matches pb, which is inside the sphere.
     ///           when not colliding, the closest point on the sphere
-    /// \param normal direction of motion of the box
-    /// \return true if the distance is negative (the shape overlaps).
+    /// @param normal direction of motion of the box
+    /// @return true if the distance is negative (the shape overlaps).
     inline bool boxSphereDistance(const Box   & b, const Transform3f& tfb,
                                   const Sphere& s, const Transform3f& tfs,
                                   FCL_REAL& dist, Vec3f& pb, Vec3f& ps,
@@ -2143,7 +2112,7 @@ namespace fcl {
       bool inside = true;
       for (int i = 0; i < 3; ++i) {
         bool iinside = false;
-        FCL_REAL dist = Rb.col(i).dot(d), side_2 = b.side(i) / 2;
+        FCL_REAL dist = Rb.col(i).dot(d), side_2 = b.halfSide(i);
         if      (dist < -side_2) dist = -side_2; // outside
         else if (dist >  side_2) dist =  side_2; // outside
         else iinside = true;                     // inside
@@ -2184,8 +2153,8 @@ namespace fcl {
       Vec3f dir_z = R1.col(2);
 
       // ends of capsule inner segment
-      Vec3f a1 = T1 + dir_z * (0.5 * s1.lz);
-      Vec3f a2 = T1 - dir_z * (0.5 * s1.lz);
+      Vec3f a1 = T1 + dir_z * s1.halfLength;
+      Vec3f a2 = T1 - dir_z * s1.halfLength;
 
       FCL_REAL d1 = new_s2.signedDistance(a1);
       FCL_REAL d2 = new_s2.signedDistance(a2);
@@ -2309,8 +2278,8 @@ namespace fcl {
           C *= s;
         }
 
-        Vec3f a1 = T + dir_z * (0.5 * s1.lz);
-        Vec3f a2 = T - dir_z * (0.5 * s1.lz);
+        Vec3f a1 = T + dir_z * (s1.halfLength);
+        Vec3f a2 = T - dir_z * (s1.halfLength);
 
         Vec3f c1, c2;
         if(cosa > 0)
@@ -2377,8 +2346,8 @@ namespace fcl {
           else
             {
               if (d < 0) normal = new_s2.n; else normal = -new_s2.n;
-              p1 = p2 = T - dir_z * (0.5 * s1.lz) +
-                dir_z * (-0.5 * distance / s1.radius * s1.lz) - new_s2.n * d;
+              p1 = p2 = T - dir_z * (s1.halfLength) +
+                dir_z * (- distance / s1.radius * s1.halfLength) - new_s2.n * d;
               return true;
             }
         }
@@ -2396,9 +2365,9 @@ namespace fcl {
             }
 
           Vec3f c[3];
-          c[0] = T + dir_z * (0.5 * s1.lz);
-          c[1] = T - dir_z * (0.5 * s1.lz) + C;
-          c[2] = T - dir_z * (0.5 * s1.lz) - C;
+          c[0] = T + dir_z * (s1.halfLength);
+          c[1] = T - dir_z * (s1.halfLength) + C;
+          c[2] = T - dir_z * (s1.halfLength) - C;
 
           FCL_REAL d[3];
           d[0] = new_s2.signedDistance(c[0]);
@@ -2468,7 +2437,7 @@ namespace fcl {
     }
 
     inline bool convexPlaneIntersect
-      (const Convex& s1, const Transform3f& tf1,
+      (const ConvexBase& s1, const Transform3f& tf1,
        const Plane& s2, const Transform3f& tf2,
        Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal)
     {
@@ -2651,6 +2620,21 @@ namespace fcl {
 
       return true;
     }
+
+    /// See the prototype below
+    inline FCL_REAL computePenetration
+      (const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
+       const Vec3f& Q1, const Vec3f& Q2, const Vec3f& Q3,
+       Vec3f& normal)
+    {
+      Vec3f u ((P2-P1).cross (P3-P1));
+      normal = u.normalized ();
+      FCL_REAL depth1 ((P1-Q1).dot (normal));
+      FCL_REAL depth2 ((P1-Q2).dot (normal));
+      FCL_REAL depth3 ((P1-Q3).dot (normal));
+      return std::max (depth1, std::max (depth2, depth3));
+    }
+
     // Compute penetration distance and normal of two triangles in collision
     // Normal is normal of triangle 1 (P1, P2, P3), penetration depth is the
     // minimal distance (Q1, Q2, Q3) should be translated along the normal so
@@ -2669,14 +2653,8 @@ namespace fcl {
       Vec3f globalQ1 (tf2.transform (Q1));
       Vec3f globalQ2 (tf2.transform (Q2));
       Vec3f globalQ3 (tf2.transform (Q3));
-      Vec3f u ((globalP2-globalP1).cross (globalP3-globalP1));
-      normal = u.normalized ();
-      FCL_REAL depth;
-      FCL_REAL depth1 ((globalP1-globalQ1).dot (normal));
-      FCL_REAL depth2 ((globalP1-globalQ2).dot (normal));
-      FCL_REAL depth3 ((globalP1-globalQ3).dot (normal));
-      depth = std::max (depth1, std::max (depth2, depth3));
-      return depth;
+      return computePenetration (globalP1, globalP2, globalP3,
+          globalQ1, globalQ2, globalQ3, normal);
     }
   } // details
 } // namespace fcl
diff --git a/src/narrowphase/gjk.cpp b/src/narrowphase/gjk.cpp
index ed15725c4ca635d44ccb74a047248befb458e7bb..9f0b94db7e2a185edb8bda396a9c2bf7b60bfe5a 100644
--- a/src/narrowphase/gjk.cpp
+++ b/src/narrowphase/gjk.cpp
@@ -36,7 +36,8 @@
 /** \author Jia Pan */
 
 #include <hpp/fcl/narrowphase/gjk.h>
-#include <hpp/fcl/intersect.h>
+#include <hpp/fcl/internal/intersect.h>
+#include <hpp/fcl/internal/tools.h>
 
 namespace hpp
 {
@@ -46,159 +47,395 @@ namespace fcl
 namespace details
 {
 
-Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir)
+struct shape_traits_base
 {
-  FCL_REAL eps (sqrt(std::numeric_limits<FCL_REAL>::epsilon()));
-  switch(shape->getNodeType())
+  enum { NeedNormalizedDir = true
+  };
+};
+
+template <typename Shape> struct shape_traits : shape_traits_base {};
+
+template <> struct shape_traits<TriangleP> : shape_traits_base
+{
+  enum { NeedNormalizedDir = false
+  };
+};
+
+template <> struct shape_traits<Box> : shape_traits_base
+{
+  enum { NeedNormalizedDir = false
+  };
+};
+
+template <> struct shape_traits<Cone> : shape_traits_base
+{
+  enum { NeedNormalizedDir = false
+  };
+};
+
+template <> struct shape_traits<Cylinder> : shape_traits_base
+{
+  enum { NeedNormalizedDir = false
+  };
+};
+
+template <> struct shape_traits<ConvexBase> : shape_traits_base
+{
+  enum { NeedNormalizedDir = false
+  };
+};
+
+void getShapeSupport(const TriangleP* triangle, const Vec3f& dir, Vec3f& support)
+{
+  FCL_REAL dota = dir.dot(triangle->a);
+  FCL_REAL dotb = dir.dot(triangle->b);
+  FCL_REAL dotc = dir.dot(triangle->c);
+  if(dota > dotb)
   {
-  case GEOM_TRIANGLE:
-    {
-      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);
-      if(dota > dotb)
-      {
-        if(dotc > dota)
-          return triangle->c;
-        else
-          return triangle->a;
-      }
-      else
-      {
-        if(dotc > dotb)
-          return triangle->c;
-        else
-          return triangle->b;
+    if(dotc > dota)
+      support = triangle->c;
+    else
+      support = triangle->a;
+  }
+  else
+  {
+    if(dotc > dotb)
+      support = triangle->c;
+    else
+      support = triangle->b;
+  }
+}
+
+inline void getShapeSupport(const Box* box, const Vec3f& dir, Vec3f& support)
+{
+  support.noalias() = (dir.array() > 0).select(box->halfSide, -box->halfSide);
+}
+
+inline void getShapeSupport(const Sphere* sphere, const Vec3f& dir, Vec3f& support)
+{
+  support = dir * sphere->radius;
+}
+
+inline void getShapeSupport(const Capsule* capsule, const Vec3f& dir, Vec3f& support)
+{
+  support = capsule->radius * dir;
+  if (dir[2] > 0) support[2] += capsule->halfLength;
+  else            support[2] -= capsule->halfLength;
+}
+
+void getShapeSupport(const Cone* cone, const Vec3f& dir, Vec3f& support)
+{
+  // TODO (Joseph Mirabel)
+  // this assumes that the cone radius is, for -0.5 < z < 0.5:
+  // (lz/2 - z) * radius / lz
+  //
+  // I did not change the code myself. However, I think it should be revised.
+  // 1. It can be optimized.
+  // 2. I am not sure this is what conePlaneIntersect and coneHalfspaceIntersect
+  //    assumes...
+  FCL_REAL zdist = dir[0] * dir[0] + dir[1] * dir[1];
+  FCL_REAL len = zdist + dir[2] * dir[2];
+  zdist = std::sqrt(zdist);
+  len = std::sqrt(len);
+  FCL_REAL half_h = cone->halfLength;
+  FCL_REAL radius = cone->radius;
+
+  FCL_REAL sin_a = radius / std::sqrt(radius * radius + 4 * half_h * half_h);
+
+  if(dir[2] > len * sin_a)
+    support = Vec3f(0, 0, half_h);
+  else if(zdist > 0)
+  {
+    FCL_REAL rad = radius / zdist;
+    support = Vec3f(rad * dir[0], rad * dir[1], -half_h);
+  }
+  else
+    support = Vec3f(0, 0, -half_h);
+}
+
+void getShapeSupport(const Cylinder* cylinder, const Vec3f& dir, Vec3f& support)
+{
+  static const FCL_REAL eps (sqrt(std::numeric_limits<FCL_REAL>::epsilon()));
+  FCL_REAL half_h = cylinder->halfLength;
+  if      (dir [2] >  eps) support[2] =  half_h;
+  else if (dir [2] < -eps) support[2] = -half_h;
+  else                     support[2] = 0;
+  if (dir.head<2>().isZero())
+    support.head<2>().setZero();
+  else
+    support.head<2>() = dir.head<2>().normalized() * cylinder->radius;
+  assert (fabs (support [0] * dir [1] - support [1] * dir [0]) < eps);
+}
+
+void getShapeSupport(const ConvexBase* convex, const Vec3f& dir, Vec3f& support)
+{
+  const Vec3f* pts = convex->points;
+  const ConvexBase::Neighbors* nn = convex->neighbors;
+
+  int i = 0;
+  FCL_REAL maxdot = pts[i].dot(dir);
+  FCL_REAL dot;
+  bool found = true;
+  while (found)
+  {
+    const ConvexBase::Neighbors& n = nn[i];
+    found = false;
+    for (int in = 0; in < n.count(); ++in) {
+      dot = pts[n[in]].dot(dir);
+      if (dot > maxdot) {
+        maxdot = dot;
+        i = n[in];
+        found = true;
       }
     }
+  }
+
+  support = pts[i];
+}
+
+#define CALL_GET_SHAPE_SUPPORT(ShapeType)                                      \
+  getShapeSupport (static_cast<const ShapeType*>(shape),                       \
+      (shape_traits<ShapeType>::NeedNormalizedDir && !dirIsNormalized)         \
+      ? dir.normalized() : dir,                                                \
+      support)
+
+Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized)
+{
+  Vec3f support;
+  switch(shape->getNodeType())
+  {
+  case GEOM_TRIANGLE:
+    CALL_GET_SHAPE_SUPPORT(TriangleP);
     break;
   case GEOM_BOX:
-    {
-      const Box* box = static_cast<const Box*>(shape);
-      Vec3f res((dir[0]>0)?(box->side[0]/2):(-box->side[0]/2),
-                (dir[1]>0)?(box->side[1]/2):(-box->side[1]/2),
-                (dir[2]>0)?(box->side[2]/2):(-box->side[2]/2));
-      return res;
-    }
+    CALL_GET_SHAPE_SUPPORT(Box);
     break;
   case GEOM_SPHERE:
-    {
-      const Sphere* sphere = static_cast<const Sphere*>(shape);
-      return dir * sphere->radius;
-    }
+    CALL_GET_SHAPE_SUPPORT(Sphere);
     break;
   case GEOM_CAPSULE:
-    {
-      const Capsule* capsule = static_cast<const Capsule*>(shape);
-      FCL_REAL half_h = capsule->lz * 0.5;
-      Vec3f pos1(0, 0, half_h);
-      Vec3f pos2(0, 0, -half_h);
-      Vec3f v = dir * capsule->radius;
-      pos1 += v;
-      pos2 += v;
-      if(dir.dot(pos1) > dir.dot(pos2))
-        return pos1;
-      else return pos2;
-    }
+    CALL_GET_SHAPE_SUPPORT(Capsule);
     break;
   case GEOM_CONE:
-    {
-      const Cone* cone = static_cast<const Cone*>(shape);
-      FCL_REAL zdist = dir[0] * dir[0] + dir[1] * dir[1];
-      FCL_REAL len = zdist + dir[2] * dir[2];
-      zdist = std::sqrt(zdist);
-      len = std::sqrt(len);
-      FCL_REAL half_h = cone->lz * 0.5;
-      FCL_REAL radius = cone->radius;
-
-      FCL_REAL sin_a = radius / std::sqrt(radius * radius + 4 * half_h * half_h);
-
-      if(dir[2] > len * sin_a)
-        return Vec3f(0, 0, half_h);
-      else if(zdist > 0)
-      {
-        FCL_REAL rad = radius / zdist;
-        return Vec3f(rad * dir[0], rad * dir[1], -half_h);
-      }
-      else
-        return Vec3f(0, 0, -half_h);
-    }
+    CALL_GET_SHAPE_SUPPORT(Cone);
     break;
   case GEOM_CYLINDER:
-    {
-      const Cylinder* cylinder = static_cast<const Cylinder*>(shape);
-      FCL_REAL zdist = std::sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
-      FCL_REAL half_h = cylinder->lz * 0.5;
-      Vec3f res;
-      if(zdist == 0.0)
-      {
-        res =  Vec3f(0, 0, (dir[2]>0)? half_h:-half_h);
-      }
-      else
-      {
-        FCL_REAL d = cylinder->radius / zdist;
-        FCL_REAL z (0.);
-        if (dir [2] > eps) z = half_h;
-        else if (dir [2] < -eps) z = -half_h;
-        res =  Vec3f(d * dir[0], d * dir[1], z);
-      }
-      assert (fabs (res [0] * dir [1] - res [1] * dir [0]) < eps);
-      return res;
-    }
+    CALL_GET_SHAPE_SUPPORT(Cylinder);
     break;
   case GEOM_CONVEX:
-    {
-      const Convex* convex = static_cast<const Convex*>(shape);
-      FCL_REAL maxdot = - std::numeric_limits<FCL_REAL>::max();
-      Vec3f* curp = convex->points;
-      Vec3f bestv(0,0,0);
-      for(int i = 0; i < convex->num_points; ++i, curp+=1)
-      {
-        FCL_REAL dot = dir.dot(*curp);
-        if(dot > maxdot)
-        {
-          bestv = *curp;
-          maxdot = dot;
-        }
-      }
-      return bestv;
-    }
+    CALL_GET_SHAPE_SUPPORT(ConvexBase);
     break;
   case GEOM_PLANE:
-	break;
+  case GEOM_HALFSPACE:
   default:
+    support.setZero();
     ; // nothing
   }
 
-  return Vec3f(0, 0, 0);
+  return support;
+}
+
+#undef CALL_GET_SHAPE_SUPPORT
+
+template <typename Shape0, typename Shape1, bool TransformIsIdentity>
+void getSupportTpl (const Shape0* s0, const Shape1* s1,
+    const Matrix3f& oR1, const Vec3f& ot1,
+    const Vec3f& dir, Vec3f& support0, Vec3f& support1)
+{
+  getShapeSupport (s0, dir, support0);
+  if (TransformIsIdentity)
+    getShapeSupport (s1, - dir, support1);
+  else {
+    getShapeSupport (s1, - oR1.transpose() * dir, support1);
+    support1 = oR1 * support1 + ot1;
+  }
+}
+
+template <typename Shape0, typename Shape1, bool TransformIsIdentity>
+void getSupportFuncTpl (const MinkowskiDiff& md,
+    const Vec3f& dir, bool dirIsNormalized, Vec3f& support0, Vec3f& support1)
+{
+  enum { NeedNormalizedDir =
+    bool ( (bool)shape_traits<Shape0>::NeedNormalizedDir
+        || (bool)shape_traits<Shape1>::NeedNormalizedDir)
+  };
+#ifndef NDEBUG
+  // Need normalized direction and direction is normalized
+  assert(!NeedNormalizedDir || !dirIsNormalized || fabs(dir.squaredNorm() - 1) < 1e-6);
+  // Need normalized direction but direction is not normalized.
+  assert(!NeedNormalizedDir ||  dirIsNormalized || fabs(dir.normalized().squaredNorm() - 1) < 1e-6);
+  // Don't need normalized direction. Check that dir is not zero.
+  assert( NeedNormalizedDir || dir.cwiseAbs().maxCoeff() >= 1e-6);
+#endif
+  getSupportTpl<Shape0, Shape1, TransformIsIdentity> (
+      static_cast <const Shape0*>(md.shapes[0]),
+      static_cast <const Shape1*>(md.shapes[1]),
+      md.oR1, md.ot1,
+      (NeedNormalizedDir && !dirIsNormalized) ? dir.normalized() : dir,
+      support0, support1);
+}
+
+template <typename Shape0>
+MinkowskiDiff::GetSupportFunction makeGetSupportFunction1 (const ShapeBase* s1, bool identity)
+{
+  switch(s1->getNodeType())
+  {
+  case GEOM_TRIANGLE:
+    if (identity) return getSupportFuncTpl<Shape0, TriangleP, true >;
+    else          return getSupportFuncTpl<Shape0, TriangleP, false>;
+  case GEOM_BOX:
+    if (identity) return getSupportFuncTpl<Shape0, Box, true >;
+    else          return getSupportFuncTpl<Shape0, Box, false>;
+  case GEOM_SPHERE:
+    if (identity) return getSupportFuncTpl<Shape0, Sphere, true >;
+    else          return getSupportFuncTpl<Shape0, Sphere, false>;
+  case GEOM_CAPSULE:
+    if (identity) return getSupportFuncTpl<Shape0, Capsule, true >;
+    else          return getSupportFuncTpl<Shape0, Capsule, false>;
+  case GEOM_CONE:
+    if (identity) return getSupportFuncTpl<Shape0, Cone, true >;
+    else          return getSupportFuncTpl<Shape0, Cone, false>;
+  case GEOM_CYLINDER:
+    if (identity) return getSupportFuncTpl<Shape0, Cylinder, true >;
+    else          return getSupportFuncTpl<Shape0, Cylinder, false>;
+  case GEOM_CONVEX:
+    if (identity) return getSupportFuncTpl<Shape0, ConvexBase, true >;
+    else          return getSupportFuncTpl<Shape0, ConvexBase, false>;
+  default:
+    throw std::logic_error ("Unsupported geometric shape");
+  }
+}
+
+MinkowskiDiff::GetSupportFunction makeGetSupportFunction0 (const ShapeBase* s0, const ShapeBase* s1, bool identity)
+{
+  switch(s0->getNodeType())
+  {
+  case GEOM_TRIANGLE:
+    return makeGetSupportFunction1<TriangleP> (s1, identity);
+    break;
+  case GEOM_BOX:
+    return makeGetSupportFunction1<Box> (s1, identity);
+    break;
+  case GEOM_SPHERE:
+    return makeGetSupportFunction1<Sphere> (s1, identity);
+    break;
+  case GEOM_CAPSULE:
+    return makeGetSupportFunction1<Capsule> (s1, identity);
+    break;
+  case GEOM_CONE:
+    return makeGetSupportFunction1<Cone> (s1, identity);
+    break;
+  case GEOM_CYLINDER:
+    return makeGetSupportFunction1<Cylinder> (s1, identity);
+    break;
+  case GEOM_CONVEX:
+    return makeGetSupportFunction1<ConvexBase> (s1, identity);
+    break;
+  default:
+    throw std::logic_error ("Unsupported geometric shape");
+  }
+}
+
+void MinkowskiDiff::set (const ShapeBase* shape0, const ShapeBase* shape1,
+    const Transform3f& tf0, const Transform3f& tf1)
+{
+  shapes[0] = shape0;
+  shapes[1] = shape1;
+
+  oR1 = tf0.getRotation().transpose() * tf1.getRotation();
+  ot1 = tf0.getRotation().transpose() * (tf1.getTranslation() - tf0.getTranslation());
+
+  bool identity = (oR1.isIdentity() && ot1.isZero());
+
+  getSupportFunc = makeGetSupportFunction0 (shape0, shape1, identity);
+}
+
+void MinkowskiDiff::set (const ShapeBase* shape0, const ShapeBase* shape1)
+{
+  shapes[0] = shape0;
+  shapes[1] = shape1;
+
+  oR1.setIdentity();
+  ot1.setZero();
+
+  getSupportFunc = makeGetSupportFunction0 (shape0, shape1, true);
 }
 
 void GJK::initialize()
 {
-  ray = Vec3f::Zero();
   nfree = 0;
   status = Failed;
-  current = 0;
-  distance = 0.0;
+  distance_upper_bound = std::numeric_limits<FCL_REAL>::max();
   simplex = NULL;
 }
 
-
 Vec3f GJK::getGuessFromSimplex() const
 {
   return ray;
 }
 
+bool GJK::getClosestPoints (const Simplex& simplex, Vec3f& w0, Vec3f& w1)
+{
+  SimplexV* const* vs = simplex.vertex;
+
+  for (vertex_id_t i = 0; i < simplex.rank; ++i) {
+    assert (vs[i]->w.isApprox (vs[i]->w0 - vs[i]->w1));
+  }
+
+  Project::ProjectResult projection;
+  switch (simplex.rank) {
+    case 1:
+      w0 = vs[0]->w0;
+      w1 = vs[0]->w1;
+      return true;
+    case 2:
+      {
+        const Vec3f& a  = vs[0]->w, a0 = vs[0]->w0, a1 = vs[0]->w1,
+                     b  = vs[1]->w, b0 = vs[1]->w0, b1 = vs[1]->w1;
+        FCL_REAL la, lb;
+        Vec3f N (b - a);
+        la = N.dot(-a);
+        if (la <= 0) {
+          w0 = a0;
+          w1 = a1;
+        } else {
+          lb = N.squaredNorm();
+          if (la > lb) {
+            w0 = b0;
+            w1 = b1;
+          } else {
+            lb = la / lb;
+            la = 1 - lb;
+            w0 = la * a0 + lb * b0;
+            w1 = la * a1 + lb * b1;
+          }
+        }
+      }
+      return true;
+    case 3:
+      // TODO avoid the reprojection
+      projection = Project::projectTriangleOrigin   (vs[0]->w, vs[1]->w, vs[2]->w);
+      break;
+    case 4: // We are in collision.
+      projection = Project::projectTetrahedraOrigin (vs[0]->w, vs[1]->w, vs[2]->w, vs[3]->w);
+      break;
+    default:
+      throw std::logic_error ("The simplex rank must be in [ 1, 4 ]");
+  }
+  w0.setZero();
+  w1.setZero();
+  for (vertex_id_t i = 0; i < simplex.rank; ++i) {
+    w0 += projection.parameterization[i] * vs[i]->w0;
+    w1 += projection.parameterization[i] * vs[i]->w1;
+  }
+  return true;
+}
 
 GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
 {
   size_t iterations = 0;
   FCL_REAL alpha = 0;
-  Vec3f lastw[4];
-  size_t clastw = 0;
-  Project::ProjectResult project_res;
-    
+
   free_v[0] = &store_v[0];
   free_v[1] = &store_v[1];
   free_v[2] = &store_v[2];
@@ -207,21 +444,18 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
   nfree = 4;
   current = 0;
   status = Valid;
-  shape = shape_;
+  shape = &shape_;
   distance = 0.0;
   simplices[0].rank = 0;
   ray = guess;
 
-  // appendVertex(simplices[0], (ray.squaredNorm() > 0) ? -ray : Vec3f(1, 0, 0));
   if (ray.squaredNorm() > 0) appendVertex(simplices[0], -ray);
-  else                       appendVertex(simplices[0], Vec3f(1, 0, 0));
-  simplices[0].coefficient[0] = 1;
+  else                       appendVertex(simplices[0], Vec3f(1, 0, 0), true);
   ray = simplices[0].vertex[0]->w;
-  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;
+    vertex_id_t next = (vertex_id_t)(1 - current);
     Simplex& curr_simplex = simplices[current];
     Simplex& next_simplex = simplices[next];
 
@@ -230,65 +464,52 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
     if(rl < tolerance) // mean origin is near the face of original simplex, return touch
     {
       status = Inside;
+      distance = 0; // rl ?
       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)
+    // check removed (by ?): when the new support point is close to previous support points, stop (as the new simplex is degenerated)
     const Vec3f& w = curr_simplex.vertex[curr_simplex.rank - 1]->w;
-    lastw[clastw = (clastw+1)&3] = w;
 
-    // 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)
+    // check B: no collision if omega > 0
     FCL_REAL omega = ray.dot(w) / rl;
+    if (omega > distance_upper_bound)
+    {
+      distance = omega;
+      break;
+    }
+
+    // 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)
     alpha = std::max(alpha, omega);
     if((rl - alpha) - tolerance * rl <= 0)
     {
       removeVertex(simplices[current]);
+      distance = rl;
       break;
     }
 
+    // This has been rewritten thanks to the excellent video:
+    // https://youtu.be/Qupqu1xe7Io
+    bool inside;
     switch(curr_simplex.rank)
     {
     case 2:
-      project_res = Project::projectLineOrigin(curr_simplex.vertex[0]->w,
-                                               curr_simplex.vertex[1]->w);
+      inside = projectLineOrigin (curr_simplex, next_simplex);
       break;
     case 3:
-      project_res = Project::projectTriangleOrigin(curr_simplex.vertex[0]->w,
-                                                   curr_simplex.vertex[1]->w,
-                                                   curr_simplex.vertex[2]->w); break;
+      inside = projectTriangleOrigin (curr_simplex, next_simplex);
+      break;
     case 4:
-      project_res = Project::projectTetrahedraOrigin(curr_simplex.vertex[0]->w,
-                                                     curr_simplex.vertex[1]->w,
-                                                     curr_simplex.vertex[2]->w,
-                                                     curr_simplex.vertex[3]->w);
+      inside = projectTetrahedraOrigin (curr_simplex, next_simplex);
       break;
     }
-    if(project_res.sqr_distance >= 0)
-    {
-      next_simplex.rank = 0;
-      ray = Vec3f(0,0,0);
-      current = next;
-      for(size_t i = 0; i < curr_simplex.rank; ++i)
-      {
-        if(project_res.encode & (1 << i))
-        {
-          next_simplex.vertex[next_simplex.rank] = curr_simplex.vertex[i];
-          // weights[i]
-          next_simplex.coefficient[next_simplex.rank++] =
-            project_res.parameterization[i];
-          // weights[i]
-          ray += curr_simplex.vertex[i]->w * project_res.parameterization[i];
-        }
-        else
-          free_v[nfree++] = curr_simplex.vertex[i];
-      }
-      if(project_res.encode == 15) status = Inside; // the origin is within the 4-simplex, collision
-    }
-    else
-    {
-      removeVertex(simplices[current]);
+    assert (nfree+next_simplex.rank == 4);
+    current = next;
+    if(inside) {
+      status = Inside;
+      distance = 0;
       break;
     }
 
@@ -297,52 +518,37 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
   } while(status == Valid);
 
   simplex = &simplices[current];
-  switch(status)
-  {
-  case Valid: distance = ray.norm(); break;
-  case Inside: distance = 0; break;
-  default:
-    distance = sqrt (project_res.sqr_distance);
-    break;
-  }
   return status;
 }
 
-void GJK::getSupport(const Vec3f& d, SimplexV& sv) const
-{
-  sv.d.noalias() = d.normalized();
-  sv.w.noalias() = shape.support(sv.d);
-}
-
-void GJK::removeVertex(Simplex& simplex)
+inline void GJK::removeVertex(Simplex& simplex)
 {
   free_v[nfree++] = simplex.vertex[--simplex.rank];
 }
 
-void GJK::appendVertex(Simplex& simplex, const Vec3f& v)
+inline void GJK::appendVertex(Simplex& simplex, const Vec3f& v, bool isNormalized)
 {
-  simplex.coefficient[simplex.rank] = 0; // initial weight 0
   simplex.vertex[simplex.rank] = free_v[--nfree]; // set the memory
-  getSupport(v, *simplex.vertex[simplex.rank++]);
+  getSupport (v, isNormalized, *simplex.vertex[simplex.rank++]);
 }
 
 bool GJK::encloseOrigin()
 {
+  Vec3f axis(Vec3f::Zero());
   switch(simplex->rank)
   {
   case 1:
+    for(size_t i = 0; i < 3; ++i)
     {
-      for(size_t i = 0; i < 3; ++i)
-      {
-        Vec3f axis(Vec3f::Zero());
-        axis[i] = 1;
-        appendVertex(*simplex, axis);
-        if(encloseOrigin()) return true;
-        removeVertex(*simplex);
-        appendVertex(*simplex, -axis);
-        if(encloseOrigin()) return true;
-        removeVertex(*simplex);
-      }
+      axis[i] = 1;
+      appendVertex(*simplex, axis, true);
+      if(encloseOrigin()) return true;
+      removeVertex(*simplex);
+      axis[i] = -1;
+      appendVertex(*simplex, -axis, true);
+      if(encloseOrigin()) return true;
+      removeVertex(*simplex);
+      axis[i] = 0;
     }
     break;
   case 2:
@@ -350,10 +556,9 @@ bool GJK::encloseOrigin()
       Vec3f d = simplex->vertex[1]->w - simplex->vertex[0]->w;
       for(size_t i = 0; i < 3; ++i)
       {
-        Vec3f axis(0,0,0);
         axis[i] = 1;
         Vec3f p = d.cross(axis);
-        if(p.squaredNorm() > 0)
+        if(!p.isZero())
         {
           appendVertex(*simplex, p);
           if(encloseOrigin()) return true;
@@ -362,37 +567,482 @@ bool GJK::encloseOrigin()
           if(encloseOrigin()) return true;
           removeVertex(*simplex);
         }
+        axis[i] = 0;
       }
     }
     break;
   case 3:
+    axis.noalias() =
+      (simplex->vertex[1]->w - simplex->vertex[0]->w).cross
+      (simplex->vertex[2]->w - simplex->vertex[0]->w);
+    if(!axis.isZero())
     {
-      Vec3f n = (simplex->vertex[1]->w - simplex->vertex[0]->w).cross
-        (simplex->vertex[2]->w - simplex->vertex[0]->w);
-      if(n.squaredNorm() > 0)
-      {
-        appendVertex(*simplex, n);
-        if(encloseOrigin()) return true;
-        removeVertex(*simplex);
-        appendVertex(*simplex, -n);
-        if(encloseOrigin()) return true;
-        removeVertex(*simplex);
-      }
+      appendVertex(*simplex, axis);
+      if(encloseOrigin()) return true;
+      removeVertex(*simplex);
+      appendVertex(*simplex, -axis);
+      if(encloseOrigin()) return true;
+      removeVertex(*simplex);
     }
     break;
   case 4:
-    {
-      if(std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w,
-                         simplex->vertex[1]->w - simplex->vertex[3]->w,
-                         simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0)
-        return true;
-    }
+    if(std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w,
+                       simplex->vertex[1]->w - simplex->vertex[3]->w,
+                       simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0)
+      return true;
     break;
   }
 
   return false;
 }
 
+inline void originToPoint (
+    const GJK::Simplex& current, GJK::vertex_id_t a,
+    const Vec3f& A,
+    GJK::Simplex& next,
+    Vec3f& ray)
+{
+    // A is the closest to the origin
+    ray = A;
+    next.vertex[0] = current.vertex[a];
+    next.rank = 1;
+}
+
+inline void originToSegment (
+    const GJK::Simplex& current, GJK::vertex_id_t a, GJK::vertex_id_t b,
+    const Vec3f& A, const Vec3f& B,
+    const Vec3f& AB,
+    const FCL_REAL& ABdotAO,
+    GJK::Simplex& next,
+    Vec3f& ray)
+{
+    // ray = - ( AB ^ AO ) ^ AB = (AB.B) A + (-AB.A) B
+    ray = AB.dot(B) * A + ABdotAO * B;
+
+    next.vertex[0] = current.vertex[b];
+    next.vertex[1] = current.vertex[a];
+    next.rank = 2;
+
+    // To ensure backward compatibility
+    ray /= AB.squaredNorm();
+}
+
+inline void originToTriangle (
+    const GJK::Simplex& current,
+    GJK::vertex_id_t a, GJK::vertex_id_t b, GJK::vertex_id_t c,
+    const Vec3f& ABC,
+    const FCL_REAL& ABCdotAO,
+    GJK::Simplex& next,
+    Vec3f& ray)
+{
+  bool aboveTri (ABCdotAO >= 0);
+  ray = ABC;
+
+  if (aboveTri) {
+    next.vertex[0] = current.vertex[c];
+    next.vertex[1] = current.vertex[b];
+  } else {
+    next.vertex[0] = current.vertex[b];
+    next.vertex[1] = current.vertex[c];
+  }
+  next.vertex[2] = current.vertex[a];
+  next.rank = 3;
+
+  // To ensure backward compatibility
+  ray *= -ABCdotAO / ABC.squaredNorm();
+}
+
+bool GJK::projectLineOrigin(const Simplex& current, Simplex& next)
+{
+  const vertex_id_t a = 1, b = 0;
+  // A is the last point we added.
+  const Vec3f& A = current.vertex[a]->w;
+  const Vec3f& B = current.vertex[b]->w;
+
+  const Vec3f AB = B - A;
+  const FCL_REAL d = AB.dot(-A);
+  assert (d <= AB.squaredNorm());
+
+  if (d <= 0) {
+    // A is the closest to the origin
+    originToPoint (current, a, A, next, ray);
+    free_v[nfree++] = current.vertex[b];
+  } else
+    originToSegment (current, a, b, A, B, AB, d, next, ray);
+  return false;
+}
+
+bool GJK::projectTriangleOrigin(const Simplex& current, Simplex& next)
+{
+  const vertex_id_t a = 2, b = 1, c = 0;
+  // A is the last point we added.
+  const Vec3f& A = current.vertex[a]->w,
+               B = current.vertex[b]->w,
+               C = current.vertex[c]->w;
+
+  const Vec3f AB = B - A,
+              AC = C - A,
+              ABC = AB.cross(AC);
+
+  FCL_REAL edgeAC2o = ABC.cross(AC).dot (-A);
+  if (edgeAC2o >= 0) {
+    FCL_REAL towardsC = AC.dot (-A);
+    if (towardsC >= 0) { // Region 1
+      originToSegment (current, a, c, A, C, AC, towardsC, next, ray);
+      free_v[nfree++] = current.vertex[b];
+    } else { // Region 4 or 5
+      FCL_REAL towardsB = AB.dot(-A);
+      if (towardsB < 0) { // Region 5
+        // A is the closest to the origin
+        originToPoint (current, a, A, next, ray);
+        free_v[nfree++] = current.vertex[b];
+      } else // Region 4
+        originToSegment (current, a, b, A, B, AB, towardsB, next, ray);
+      free_v[nfree++] = current.vertex[c];
+    }
+  } else {
+    FCL_REAL edgeAB2o = AB.cross(ABC).dot (-A);
+    if (edgeAB2o >= 0) { // Region 4 or 5
+      FCL_REAL towardsB = AB.dot(-A);
+      if (towardsB < 0) { // Region 5
+        // A is the closest to the origin
+        originToPoint (current, a, A, next, ray);
+        free_v[nfree++] = current.vertex[b];
+      } else // Region 4
+        originToSegment (current, a, b, A, B, AB, towardsB, next, ray);
+      free_v[nfree++] = current.vertex[c];
+    } else {
+      originToTriangle (current, a, b, c, ABC, ABC.dot(-A), next, ray);
+    }
+  }
+  return false;
+}
+
+bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)
+{
+  // The code of this function was generated using doc/gjk.py
+  const vertex_id_t a = 3, b = 2, c = 1, d = 0;
+  const Vec3f& A (current.vertex[a]->w);
+  const Vec3f& B (current.vertex[b]->w);
+  const Vec3f& C (current.vertex[c]->w);
+  const Vec3f& D (current.vertex[d]->w);
+  const FCL_REAL aa = A.squaredNorm();
+  const FCL_REAL da    = D.dot(A);
+  const FCL_REAL db    = D.dot(B);
+  const FCL_REAL dc    = D.dot(C);
+  const FCL_REAL dd    = D.dot(D);
+  const FCL_REAL da_aa = da - aa;
+  const FCL_REAL ca    = C.dot(A);
+  const FCL_REAL cb    = C.dot(B);
+  const FCL_REAL cc    = C.dot(C);
+  const FCL_REAL& cd    = dc;
+  const FCL_REAL ca_aa = ca - aa;
+  const FCL_REAL ba    = B.dot(A);
+  const FCL_REAL bb    = B.dot(B);
+  const FCL_REAL& bc    = cb;
+  const FCL_REAL& bd    = db;
+  const FCL_REAL ba_aa = ba - aa;
+  const FCL_REAL ba_ca = ba - ca;
+  const FCL_REAL ca_da = ca - da;
+  const FCL_REAL da_ba = da - ba;
+  const Vec3f a_cross_b = A.cross(B);
+  const Vec3f a_cross_c = A.cross(C);
+
+#define REGION_INSIDE()                 \
+    ray.setZero();                      \
+    next.vertex[0] = current.vertex[d]; \
+    next.vertex[1] = current.vertex[c]; \
+    next.vertex[2] = current.vertex[b]; \
+    next.vertex[3] = current.vertex[a]; \
+    next.rank=4;                        \
+    return true;
+
+  if (ba_aa <= 0) { // if AB.AO >= 0 / a10
+    if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / a10.a3
+      if (ba * da_ba + bd * ba_aa - bb * da_aa <= 0) { // if (ADB ^ AB).AO >= 0 / a10.a3.a9
+        if (da_aa <= 0) { // if AD.AO >= 0 / a10.a3.a9.a12
+          assert(da * da_ba + dd * ba_aa - db * da_aa <= 0); // (ADB ^ AD).AO >= 0 / a10.a3.a9.a12.a8
+          if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.a4
+            // Region ABC
+            originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+            free_v[nfree++] = current.vertex[d];
+          } else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.!a4
+            // Region AB
+            originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
+            free_v[nfree++] = current.vertex[c];
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AB).AO >= 0
+        } else { // not AD.AO >= 0 / a10.a3.a9.!a12
+          if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.a4
+            if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5
+              if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.a6
+                // Region ACD
+                originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+                free_v[nfree++] = current.vertex[b];
+              } else { // not (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.!a6
+                // Region AC
+                originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+                free_v[nfree++] = current.vertex[b];
+                free_v[nfree++] = current.vertex[d];
+              } // end of (ACD ^ AC).AO >= 0
+            } else { // not (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.!a5
+              // Region ABC
+              originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ABC ^ AC).AO >= 0
+          } else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.!a4
+            // Region AB
+            originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
+            free_v[nfree++] = current.vertex[c];
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AB).AO >= 0
+        } // end of AD.AO >= 0
+      } else { // not (ADB ^ AB).AO >= 0 / a10.a3.!a9
+        if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / a10.a3.!a9.a8
+          // Region ADB
+          originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+          free_v[nfree++] = current.vertex[c];
+        } else { // not (ADB ^ AD).AO >= 0 / a10.a3.!a9.!a8
+          if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.a6
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.a7
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.!a7
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.!a6
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.a7
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.!a7
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ACD ^ AD).AO >= 0
+          } // end of (ACD ^ AC).AO >= 0
+        } // end of (ADB ^ AD).AO >= 0
+      } // end of (ADB ^ AB).AO >= 0
+    } else { // not ADB.AO >= 0 / a10.!a3
+      if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / a10.!a3.a1
+        if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0 / a10.!a3.a1.a4
+          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.a5
+            if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.a6
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } else { // not (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.!a6
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ACD ^ AC).AO >= 0
+          } else { // not (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.!a5
+            // Region ABC
+            originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AC).AO >= 0
+        } else { // not (ABC ^ AB).AO >= 0 / a10.!a3.a1.!a4
+          // Region AB
+          originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
+          free_v[nfree++] = current.vertex[c];
+          free_v[nfree++] = current.vertex[d];
+        } // end of (ABC ^ AB).AO >= 0
+      } else { // not ABC.AO >= 0 / a10.!a3.!a1
+        if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / a10.!a3.!a1.a2
+          if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.a6
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.a7
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.!a7
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.!a6
+            if (ca_aa <= 0) { // if AC.AO >= 0 / a10.!a3.!a1.a2.!a6.a11
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } else { // not AC.AO >= 0 / a10.!a3.!a1.a2.!a6.!a11
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } // end of AC.AO >= 0
+          } // end of (ACD ^ AC).AO >= 0
+        } else { // not ACD.AO >= 0 / a10.!a3.!a1.!a2
+          // Region Inside
+          REGION_INSIDE()
+        } // end of ACD.AO >= 0
+      } // end of ABC.AO >= 0
+    } // end of ADB.AO >= 0
+  } else { // not AB.AO >= 0 / !a10
+    if (ca_aa <= 0) { // if AC.AO >= 0 / !a10.a11
+      if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.a11.a2
+        if (da_aa <= 0) { // if AD.AO >= 0 / !a10.a11.a2.a12
+          if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.a6
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7
+              if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.a8
+                // Region ADB
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+                free_v[nfree++] = current.vertex[c];
+              } else { // not (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.!a8
+                // Region AD
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+                free_v[nfree++] = current.vertex[b];
+                free_v[nfree++] = current.vertex[c];
+              } // end of (ADB ^ AD).AO >= 0
+            } else { // not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.!a7
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6
+            assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.!a6.!a7
+            if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.a5
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.!a5
+              // Region ABC
+              originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ABC ^ AC).AO >= 0
+          } // end of (ACD ^ AC).AO >= 0
+        } else { // not AD.AO >= 0 / !a10.a11.a2.!a12
+          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5
+            if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.a6
+              assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0 / !a10.a11.a2.!a12.a5.a6.!a7
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.!a6
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ACD ^ AC).AO >= 0
+          } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.!a5
+            if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.a1
+              assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0); // (ABC ^ AB).AO >= 0 / !a10.a11.a2.!a12.!a5.a1.a4
+              // Region ABC
+              originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[d];
+            } else { // not ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.!a1
+              assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0 / !a10.a11.a2.!a12.!a5.!a1.!a7
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } // end of ABC.AO >= 0
+          } // end of (ABC ^ AC).AO >= 0
+        } // end of AD.AO >= 0
+      } else { // not ACD.AO >= 0 / !a10.a11.!a2
+        if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.a11.!a2.a1
+          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.a5
+            // Region AC
+            originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+            free_v[nfree++] = current.vertex[b];
+            free_v[nfree++] = current.vertex[d];
+          } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.!a5
+            assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0); // (ABC ^ AB).AO >= 0 / !a10.a11.!a2.a1.!a5.a4
+            // Region ABC
+            originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AC).AO >= 0
+        } else { // not ABC.AO >= 0 / !a10.a11.!a2.!a1
+          if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.a11.!a2.!a1.a3
+            if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.a8
+              // Region ADB
+              originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.!a8
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } // end of (ADB ^ AD).AO >= 0
+          } else { // not ADB.AO >= 0 / !a10.a11.!a2.!a1.!a3
+            // Region Inside
+            REGION_INSIDE()
+          } // end of ADB.AO >= 0
+        } // end of ABC.AO >= 0
+      } // end of ACD.AO >= 0
+    } else { // not AC.AO >= 0 / !a10.!a11
+      if (da_aa <= 0) { // if AD.AO >= 0 / !a10.!a11.a12
+        if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.!a11.a12.a3
+          if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7
+            if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.a8
+              assert(!(ba * da_ba + bd * ba_aa - bb * da_aa <= 0)); // Not (ADB ^ AB).AO >= 0 / !a10.!a11.a12.a3.a7.a8.!a9
+              // Region ADB
+              originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.!a8
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } // end of (ADB ^ AD).AO >= 0
+          } else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.!a7
+            if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.a2
+              assert(ca * ca_da + cc * da_aa - cd * ca_aa <= 0); // (ACD ^ AC).AO >= 0 / !a10.!a11.a12.a3.!a7.a2.a6
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } else { // not ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2
+              if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1
+                assert(!(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0)); // Not (ABC ^ AB).AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1.!a4
+                // Region ADB
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+                free_v[nfree++] = current.vertex[c];
+              } else { // not ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.!a1
+                // Region ADB
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+                free_v[nfree++] = current.vertex[c];
+              } // end of ABC.AO >= 0
+            } // end of ACD.AO >= 0
+          } // end of (ACD ^ AD).AO >= 0
+        } else { // not ADB.AO >= 0 / !a10.!a11.a12.!a3
+          if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.!a11.a12.!a3.a2
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.a7
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7
+              assert(ca * ca_da + cc * da_aa - cd * ca_aa <= 0); // (ACD ^ AC).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7.a6
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not ACD.AO >= 0 / !a10.!a11.a12.!a3.!a2
+            // Region Inside
+            REGION_INSIDE()
+          } // end of ACD.AO >= 0
+        } // end of ADB.AO >= 0
+      } else { // not AD.AO >= 0 / !a10.!a11.!a12
+        // Region A
+        originToPoint (current, a, A, next, ray);
+        free_v[nfree++] = current.vertex[b];
+        free_v[nfree++] = current.vertex[c];
+        free_v[nfree++] = current.vertex[d];
+      } // end of AD.AO >= 0
+    } // end of AC.AO >= 0
+  } // end of AB.AO >= 0
+
+#undef REGION_INSIDE
+  return false;
+}
 
 void EPA::initialize()
 {
@@ -476,7 +1126,7 @@ EPA::SimplexF* EPA::newFace(SimplexV* a, SimplexV* b, SimplexV* c, bool forced)
   return NULL;
 }
 
-/** \brief Find the best polytope face to split */
+/** @brief Find the best polytope face to split */
 EPA::SimplexF* EPA::findBest()
 {
   SimplexF* minf = hull.root;
@@ -515,10 +1165,6 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess)
       SimplexV* tmp = simplex.vertex[0];
       simplex.vertex[0] = simplex.vertex[1];
       simplex.vertex[1] = tmp;
-
-      FCL_REAL tmpv = simplex.coefficient[0];
-      simplex.coefficient[0] = simplex.coefficient[1];
-      simplex.coefficient[1] = tmpv;
     }
 
     SimplexF* tetrahedron[] = {newFace(simplex.vertex[0], simplex.vertex[1],
@@ -554,7 +1200,8 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess)
           SimplexV* w = &sv_store[nextsv++];
           bool valid = true;
           best->pass = ++pass;
-          gjk.getSupport(best->n, *w);
+          // At the moment, SimplexF.n is always normalized. This could be revised in the future...
+          gjk.getSupport(best->n, true, *w);
           FCL_REAL wdist = best->n.dot(w->w) - best->d;
           if(wdist > tolerance)
           {
@@ -589,25 +1236,12 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess)
         }
       }
 
-      Vec3f projection = outer.n * outer.d;
       normal = outer.n;
       depth = outer.d;
       result.rank = 3;
       result.vertex[0] = outer.vertex[0];
       result.vertex[1] = outer.vertex[1];
       result.vertex[2] = outer.vertex[2];
-      result.coefficient[0] = ((outer.vertex[1]->w - projection).cross
-                               (outer.vertex[2]->w - projection)).norm();
-      result.coefficient[1] = ((outer.vertex[2]->w - projection).cross
-                               (outer.vertex[0]->w - projection)).norm();
-      result.coefficient[2] = ((outer.vertex[0]->w - projection).cross
-                               (outer.vertex[1]->w - projection)).norm();
-
-      FCL_REAL sum = result.coefficient[0] + result.coefficient[1] +
-        result.coefficient[2];
-      result.coefficient[0] /= sum;
-      result.coefficient[1] /= sum;
-      result.coefficient[2] /= sum;
       return status;
     }
   }
@@ -620,12 +1254,11 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess)
   depth = 0;
   result.rank = 1;
   result.vertex[0] = simplex.vertex[0];
-  result.coefficient[0] = 1;
   return status;
 }
 
 
-/** \brief the goal is to add a face connecting vertex w and face edge f[e] */
+/** @brief the goal is to add a face connecting vertex w and face edge f[e] */
 bool EPA::expand(size_t pass, SimplexV* w, SimplexF* f, size_t e, SimplexHorizon& horizon)
 {
   static const size_t nexti[] = {1, 2, 0};
diff --git a/src/narrowphase/narrowphase.cpp b/src/narrowphase/narrowphase.cpp
index 00897891297baf99acae855225edf3d9711c982f..829855fbf5eaddd55deb8529d8f01229e21ce851 100644
--- a/src/narrowphase/narrowphase.cpp
+++ b/src/narrowphase/narrowphase.cpp
@@ -36,11 +36,13 @@
 /** \author Jia Pan */
 
 #include <hpp/fcl/narrowphase/narrowphase.h>
-#include <hpp/fcl/shape/geometric_shapes_utility.h>
-#include <hpp/fcl/intersect.h>
-#include <boost/math/constants/constants.hpp>
+
 #include <vector>
-#include "../src/narrowphase/details.h"
+#include <boost/math/constants/constants.hpp>
+
+#include <hpp/fcl/shape/geometric_shapes_utility.h>
+#include <hpp/fcl/internal/intersect.h>
+#include "details.h"
 
 namespace hpp
 {
@@ -71,7 +73,7 @@ namespace fcl
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1,
+bool GJKSolver::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
 {
@@ -79,7 +81,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Tr
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1,
+bool GJKSolver::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1,
                                                       const Sphere &s2, const Transform3f& tf2,
                                                       Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
@@ -89,7 +91,7 @@ bool GJKSolver_indep::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const T
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
+bool GJKSolver::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
                                                      const Sphere& s2, const Transform3f& tf2,
                                                      Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
@@ -97,7 +99,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Tra
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Box, Sphere>(const Box   & s1, const Transform3f& tf1,
+bool GJKSolver::shapeIntersect<Box, Sphere>(const Box   & s1, const Transform3f& tf1,
                                                   const Sphere& s2, const Transform3f& tf2,
                                                   Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
@@ -112,7 +114,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Sphere>(const Box   & s1, const Transf
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Sphere, Box>(const Sphere& s1, const Transform3f& tf1,
+bool GJKSolver::shapeIntersect<Sphere, Box>(const Sphere& s1, const Transform3f& tf1,
                                                   const Box   & s2, const Transform3f& tf2,
                                                   Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
@@ -127,7 +129,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Box>(const Sphere& s1, const Transf
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1,
+bool GJKSolver::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1,
                                                const Box& s2, const Transform3f& tf2,
                                                Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
@@ -135,7 +137,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f&
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace>
+bool GJKSolver::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
@@ -150,7 +152,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1,
+bool GJKSolver::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1,
                                                         const Sphere& s2, const Transform3f& tf2,
                                                         Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
 {
@@ -165,7 +167,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, con
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Box, Halfspace>
+bool GJKSolver::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
@@ -180,7 +182,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Halfspace>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Box>
+bool GJKSolver::shapeIntersect<Halfspace, Box>
 (const Halfspace& s1, const Transform3f& tf1,
  const Box& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -196,7 +198,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Box>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Capsule, Halfspace>
+bool GJKSolver::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
@@ -211,7 +213,7 @@ bool GJKSolver_indep::shapeIntersect<Capsule, Halfspace>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Capsule>
+bool GJKSolver::shapeIntersect<Halfspace, Capsule>
 (const Halfspace& s1, const Transform3f& tf1,
  const Capsule& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -227,7 +229,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Capsule>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Cylinder, Halfspace>
+bool GJKSolver::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
@@ -242,7 +244,7 @@ bool GJKSolver_indep::shapeIntersect<Cylinder, Halfspace>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Cylinder>
+bool GJKSolver::shapeIntersect<Halfspace, Cylinder>
 (const Halfspace& s1, const Transform3f& tf1,
  const Cylinder& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -258,7 +260,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Cylinder>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Cone, Halfspace>
+bool GJKSolver::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
@@ -273,7 +275,7 @@ bool GJKSolver_indep::shapeIntersect<Cone, Halfspace>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Cone>
+bool GJKSolver::shapeIntersect<Halfspace, Cone>
 (const Halfspace& s1, const Transform3f& tf1,
  const Cone& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -289,7 +291,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Cone>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, const Transform3f& tf1,
+bool GJKSolver::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
 {
@@ -301,7 +303,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1,
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1,
+bool GJKSolver::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
 {
@@ -313,7 +315,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Tr
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1,
+bool GJKSolver::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
 {
@@ -325,7 +327,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, cons
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Sphere, Plane>
+bool GJKSolver::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
@@ -340,7 +342,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Plane>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Sphere>
+bool GJKSolver::shapeIntersect<Plane, Sphere>
 (const Plane& s1, const Transform3f& tf1,
  const Sphere& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -356,7 +358,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Sphere>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Box, Plane>
+bool GJKSolver::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
@@ -371,7 +373,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Plane>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Box>
+bool GJKSolver::shapeIntersect<Plane, Box>
 (const Plane& s1, const Transform3f& tf1,
  const Box& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -387,7 +389,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Box>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Capsule, Plane>
+bool GJKSolver::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
@@ -402,7 +404,7 @@ bool GJKSolver_indep::shapeIntersect<Capsule, Plane>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Capsule>
+bool GJKSolver::shapeIntersect<Plane, Capsule>
 (const Plane& s1, const Transform3f& tf1,
  const Capsule& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -418,7 +420,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Capsule>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Cylinder, Plane>
+bool GJKSolver::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
@@ -433,7 +435,7 @@ bool GJKSolver_indep::shapeIntersect<Cylinder, Plane>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Cylinder>
+bool GJKSolver::shapeIntersect<Plane, Cylinder>
 (const Plane& s1, const Transform3f& tf1,
  const Cylinder& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -449,7 +451,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Cylinder>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Cone, Plane>
+bool GJKSolver::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
@@ -464,7 +466,7 @@ bool GJKSolver_indep::shapeIntersect<Cone, Plane>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Cone>
+bool GJKSolver::shapeIntersect<Plane, Cone>
 (const Plane& s1, const Transform3f& tf1,
  const Cone& s2, const Transform3f& tf2,
  Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
@@ -480,7 +482,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Cone>
 }
 
 template<>
-bool GJKSolver_indep::shapeIntersect<Plane, Plane>(const Plane& s1, const Transform3f& tf1,
+bool GJKSolver::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
 {
@@ -491,7 +493,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Plane>(const Plane& s1, const Transf
 
 
 template<>
-bool GJKSolver_indep::shapeTriangleInteraction
+bool GJKSolver::shapeTriangleInteraction
 (const Sphere& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
  const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance,
  Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -502,7 +504,7 @@ bool GJKSolver_indep::shapeTriangleInteraction
 }
 
 template<>
-bool GJKSolver_indep::shapeTriangleInteraction
+bool GJKSolver::shapeTriangleInteraction
 (const Halfspace& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
  const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance,
  Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -512,7 +514,7 @@ bool GJKSolver_indep::shapeTriangleInteraction
 }
 
 template<>
-bool GJKSolver_indep::shapeTriangleInteraction
+bool GJKSolver::shapeTriangleInteraction
 (const Plane& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2,
  const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance,
  Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -526,9 +528,9 @@ bool GJKSolver_indep::shapeTriangleInteraction
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
 // |            | box | sphere | capsule | cone | cylinder | plane | half-space | triangle |
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
-// | box        |     |        |         |      |          |       |            |          |
+// | box        |     |   O    |         |      |          |       |            |          |
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
-// | sphere     |/////|   O    |    O    |      |          |       |            |    O     |
+// | sphere     |/////|   O    |    O    |      |          |       |            |          |
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
 // | capsule    |/////|////////|    O    |      |          |       |            |          |
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
@@ -544,7 +546,7 @@ bool GJKSolver_indep::shapeTriangleInteraction
 // +------------+-----+--------+---------+------+----------+-------+------------+----------+
 
 template<>
-bool GJKSolver_indep::shapeDistance<Sphere, Capsule>
+bool GJKSolver::shapeDistance<Sphere, Capsule>
 (const Sphere& s1, const Transform3f& tf1,
  const Capsule& s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -553,7 +555,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Capsule>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Capsule, Sphere>
+bool GJKSolver::shapeDistance<Capsule, Sphere>
 (const Capsule& s1, const Transform3f& tf1,
  const Sphere& s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -562,7 +564,7 @@ bool GJKSolver_indep::shapeDistance<Capsule, Sphere>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Sphere, Cylinder>
+bool GJKSolver::shapeDistance<Sphere, Cylinder>
 (const Sphere& s1, const Transform3f& tf1,
  const Cylinder& s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -572,7 +574,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Cylinder>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Box, Sphere>
+bool GJKSolver::shapeDistance<Box, Sphere>
 (const Box   & s1, const Transform3f& tf1,
  const Sphere& s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -581,7 +583,7 @@ bool GJKSolver_indep::shapeDistance<Box, Sphere>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Sphere, Box>
+bool GJKSolver::shapeDistance<Sphere, Box>
 (const Sphere& s1, const Transform3f& tf1,
  const Box   & s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -592,7 +594,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Box>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Cylinder, Sphere>
+bool GJKSolver::shapeDistance<Cylinder, Sphere>
 (const Cylinder& s1, const Transform3f& tf1,
  const Sphere& s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -602,7 +604,7 @@ bool GJKSolver_indep::shapeDistance<Cylinder, Sphere>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Sphere, Sphere>
+bool GJKSolver::shapeDistance<Sphere, Sphere>
 (const Sphere& s1, const Transform3f& tf1,
  const Sphere& s2, const Transform3f& tf2,
  FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
@@ -611,7 +613,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Sphere>
 }
 
 template<>
-bool GJKSolver_indep::shapeDistance<Capsule, Capsule>
+bool GJKSolver::shapeDistance<Capsule, Capsule>
 (const Capsule& /*s1*/, const Transform3f& /*tf1*/,
  const Capsule& /*s2*/, const Transform3f& /*tf2*/,
  FCL_REAL& /*dist*/, Vec3f& /*p1*/, Vec3f& /*p2*/, Vec3f& /*normal*/) const
@@ -620,58 +622,49 @@ bool GJKSolver_indep::shapeDistance<Capsule, Capsule>
 }
 
   template<>
-    bool GJKSolver_indep::shapeDistance<TriangleP, TriangleP>
+    bool GJKSolver::shapeDistance<TriangleP, TriangleP>
     (const TriangleP& s1, const Transform3f& tf1,
      const TriangleP& s2, const Transform3f& tf2,
      FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const
   {
-    Vec3f guess(1, 0, 0);
+    const TriangleP
+      t1 (tf1.transform(s1.a), tf1.transform(s1.b), tf1.transform(s1.c)),
+      t2 (tf2.transform(s2.a), tf2.transform(s2.b), tf2.transform(s2.c));
+
+    Vec3f guess;
     if(enable_cached_guess) guess = cached_guess;
+    else guess = (t1.a + t1.b + t1.c - t2.a - t2.b - t2.c) / 3;
     bool enable_penetration (true);
 
     details::MinkowskiDiff shape;
-    shape.shapes[0] = &s1;
-    shape.shapes[1] = &s2;
-    shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation();
-    shape.toshape0 = tf1.inverseTimes(tf2);
-
-    const Vec3f& P1 (s1.a);
-    const Vec3f& P2 (s1.b);
-    const Vec3f& P3 (s1.c);
-    const Vec3f& Q1 (s2.a);
-    const Vec3f& Q2 (s2.b);
-    const Vec3f& Q3 (s2.c);
+    shape.set (&t1, &t2);
 
     details::GJK gjk((unsigned int) gjk_max_iterations, gjk_tolerance);
     details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
     if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
 
-    Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
-    for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
-    {
-      FCL_REAL p = gjk.getSimplex()->coefficient[i];
-      w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p;
-      w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p;
-    }
+    details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2);
+
     if((gjk_status == details::GJK::Valid) ||
        (gjk_status == details::GJK::Failed))
     {
-      dist = (w0 - w1).norm();
-      p1 = tf1.transform (w0);
-      p2 = tf1.transform (w1);
+      // TODO On degenerated case, the closest point may be wrong
+      // (i.e. an object face normal is colinear to gjk.ray
+      // assert (dist == (w0 - w1).norm());
+      dist = gjk.distance;
 
       return true;
     }
     else if (gjk_status == details::GJK::Inside)
     {
-      p1 = tf1.transform (w0);
-      p2 = tf1.transform (w1);
-
       if (enable_penetration) {
         FCL_REAL penetrationDepth = details::computePenetration
-          (P1, P2, P3, Q1, Q2, Q3, tf1, tf2, normal);
+          (t1.a, t1.b, t1.c, t2.a, t2.b, t2.c, normal);
         dist = -penetrationDepth;
         assert (dist <= 1e-6);
+        // GJK says Inside when below GJK.tolerance. So non intersecting
+        // triangle may trigger "Inside" and have no penetration.
+        return penetrationDepth < 0;
       }
       dist = 0;
       return false;
diff --git a/src/shape/geometric_shapes.cpp b/src/shape/geometric_shapes.cpp
index 5f7e4f189f07abc8100372b842425c64667c518f..ddf0cb4febe3b12f963e78f612fc98d082d3ee0b 100644
--- a/src/shape/geometric_shapes.cpp
+++ b/src/shape/geometric_shapes.cpp
@@ -44,60 +44,49 @@ namespace hpp
 namespace fcl
 {
 
-void Convex::fillEdges()
+ConvexBase::ConvexBase(bool own_storage, Vec3f* points_, int num_points_) :
+  ShapeBase(),
+  points       (points_),
+  num_points   (num_points_),
+  own_storage_ (own_storage)
 {
-  int* points_in_poly = polygons;
-  if(edges) delete [] edges;
+  computeCenter();
+}
 
-  int num_edges_alloc = 0;
-  for(int i = 0; i < num_polygons; ++i)
-  {
-    num_edges_alloc += *points_in_poly;
-    points_in_poly += (*points_in_poly + 1);
+ConvexBase::ConvexBase(const ConvexBase& other) :
+  ShapeBase    (other),
+  points       (other.points),
+  num_points   (other.num_points),
+  center       (other.center),
+  own_storage_ (other.own_storage_)
+{
+  if (own_storage_) {
+    points = new Vec3f[num_points];
+    memcpy(points, other.points, sizeof(Vec3f) * num_points);
   }
 
-  edges = new Edge[num_edges_alloc];
+  neighbors = new Neighbors[num_points];
+  memcpy(neighbors, other.neighbors, sizeof(Neighbors) * num_points);
 
-  points_in_poly = polygons;
-  int* index = polygons + 1;
-  num_edges = 0;
-  Edge e;
-  bool isinset;
-  for(int i = 0; i < num_polygons; ++i)
-  {
-    for(int j = 0; j < *points_in_poly; ++j)
-    {
-      e.first = std::min(index[j], index[(j+1)%*points_in_poly]);
-      e.second = std::max(index[j], index[(j+1)%*points_in_poly]);
-      isinset = false;
-      for(int k = 0; k < num_edges; ++k)
-      {
-        if((edges[k].first == e.first) && (edges[k].second == e.second))
-        {
-          isinset = true;
-          break;
-        }
-      }
-
-      if(!isinset)
-      {
-        edges[num_edges].first = e.first;
-        edges[num_edges].second = e.second;
-        ++num_edges;
-      }
-    }
-
-    points_in_poly += (*points_in_poly + 1);
-    index = points_in_poly + 1;
-  }
+  int c_nneighbors = 0;
+  for (int i = 0; i < num_points; ++i) c_nneighbors += neighbors[i].count();
+  nneighbors_ = new unsigned int[c_nneighbors];
+  memcpy(nneighbors_, other.nneighbors_, sizeof(unsigned int) * c_nneighbors);
+}
 
-  if(num_edges < num_edges_alloc)
-  {
-    Edge* tmp = new Edge[num_edges];
-    memcpy(tmp, edges, num_edges * sizeof(Edge));
-    delete [] edges;
-    edges = tmp;
-  }
+ConvexBase::~ConvexBase ()
+{
+  delete [] neighbors;
+  delete [] nneighbors_;
+  if (own_storage_) delete [] points;
+}
+
+void ConvexBase::computeCenter()
+{
+  center.setZero();
+  for(int i = 0; i < num_points; ++i)
+    center += points[i];
+  center /= num_points;
 }
 
 void Halfspace::unitNormalTest()
@@ -132,7 +121,6 @@ void Plane::unitNormalTest()
   }
 }
 
-
 void Box::computeLocalAABB()
 {
   computeBV<AABB>(*this, Transform3f(), aabb_local);
@@ -168,7 +156,7 @@ void Cylinder::computeLocalAABB()
   aabb_radius = (aabb_local.min_ - aabb_center).norm();
 }
 
-void Convex::computeLocalAABB()
+void ConvexBase::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 acf9fb335f56bd66b48cfdc77c2de8cee172432a..c0aba4929503b4948ed397f71a74ff2ceb51c460 100644
--- a/src/shape/geometric_shapes_utility.cpp
+++ b/src/shape/geometric_shapes_utility.cpp
@@ -37,7 +37,8 @@
 
 
 #include <hpp/fcl/shape/geometric_shapes_utility.h>
-#include <hpp/fcl/BVH/BV_fitter.h>
+#include <hpp/fcl/internal/BV_fitter.h>
+#include <hpp/fcl/internal/tools.h>
 
 namespace hpp
 {
@@ -50,16 +51,16 @@ namespace details
 std::vector<Vec3f> getBoundVertices(const Box& box, const Transform3f& tf)
 {
   std::vector<Vec3f> result(8);
-  FCL_REAL a = box.side[0] / 2;
-  FCL_REAL b = box.side[1] / 2;
-  FCL_REAL c = box.side[2] / 2;
-  result[0] = tf.transform(Vec3f(a, b, c));
-  result[1] = tf.transform(Vec3f(a, b, -c));
-  result[2] = tf.transform(Vec3f(a, -b, c));
-  result[3] = tf.transform(Vec3f(a, -b, -c));
-  result[4] = tf.transform(Vec3f(-a, b, c));
-  result[5] = tf.transform(Vec3f(-a, b, -c));
-  result[6] = tf.transform(Vec3f(-a, -b, c));
+  FCL_REAL a = box.halfSide[0];
+  FCL_REAL b = box.halfSide[1];
+  FCL_REAL c = box.halfSide[2];
+  result[0] = tf.transform(Vec3f( a,  b,  c));
+  result[1] = tf.transform(Vec3f( a,  b, -c));
+  result[2] = tf.transform(Vec3f( a, -b,  c));
+  result[3] = tf.transform(Vec3f( a, -b, -c));
+  result[4] = tf.transform(Vec3f(-a,  b,  c));
+  result[5] = tf.transform(Vec3f(-a,  b, -c));
+  result[6] = tf.transform(Vec3f(-a, -b,  c));
   result[7] = tf.transform(Vec3f(-a, -b, -c));
   
   return result;
@@ -95,7 +96,7 @@ std::vector<Vec3f> getBoundVertices(const Capsule& capsule, const Transform3f& t
   std::vector<Vec3f> result(36);
   const FCL_REAL m = (1 + sqrt(5.0)) / 2.0;
 
-  FCL_REAL hl = capsule.lz * 0.5;
+  FCL_REAL hl = capsule.halfLength;
   FCL_REAL edge_size = capsule.radius * 6 / (sqrt(27.0) + sqrt(15.0));
   FCL_REAL a = edge_size;
   FCL_REAL b = m * edge_size;
@@ -152,7 +153,7 @@ std::vector<Vec3f> getBoundVertices(const Cone& cone, const Transform3f& tf)
 {
   std::vector<Vec3f> result(7);
   
-  FCL_REAL hl = cone.lz * 0.5;
+  FCL_REAL hl = cone.halfLength;
   FCL_REAL r2 = cone.radius * 2 / sqrt(3.0);
   FCL_REAL a = 0.5 * r2;
   FCL_REAL b = cone.radius;
@@ -173,7 +174,7 @@ std::vector<Vec3f> getBoundVertices(const Cylinder& cylinder, const Transform3f&
 {
   std::vector<Vec3f> result(12);
 
-  FCL_REAL hl = cylinder.lz * 0.5;
+  FCL_REAL hl = cylinder.halfLength;
   FCL_REAL r2 = cylinder.radius * 2 / sqrt(3.0);
   FCL_REAL a = 0.5 * r2;
   FCL_REAL b = cylinder.radius;
@@ -195,7 +196,7 @@ std::vector<Vec3f> getBoundVertices(const Cylinder& cylinder, const Transform3f&
   return result;
 }
 
-std::vector<Vec3f> getBoundVertices(const Convex& convex, const Transform3f& tf)
+std::vector<Vec3f> getBoundVertices(const ConvexBase& convex, const Transform3f& tf)
 {
   std::vector<Vec3f> result(convex.num_points);
   for(int i = 0; i < convex.num_points; ++i)
@@ -226,7 +227,7 @@ Halfspace transform(const Halfspace& a, const Transform3f& tf)
   /// where n' = R * n
   ///   and d' = d + n' * T
 
-  Vec3f n = tf.getQuatRotation() * a.n;
+  Vec3f n = tf.getRotation() * a.n;
   FCL_REAL d = a.d + n.dot(tf.getTranslation());
 
   return Halfspace(n, d);
@@ -241,7 +242,7 @@ Plane transform(const Plane& a, const Transform3f& tf)
   /// where n' = R * n
   ///   and d' = d + n' * T
 
-  Vec3f n = tf.getQuatRotation() * a.n;
+  Vec3f n = tf.getRotation() * a.n;
   FCL_REAL d = a.d + n.dot(tf.getTranslation());
 
   return Plane(n, d);
@@ -255,7 +256,7 @@ void computeBV<AABB, Box>(const Box& s, const Transform3f& tf, AABB& bv)
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
 
-  Vec3f v_delta (0.5 * R.cwiseAbs() * s.side);
+  Vec3f v_delta (R.cwiseAbs() * s.halfSide);
   bv.max_ = T + v_delta;
   bv.min_ = T - v_delta;
 }
@@ -276,7 +277,7 @@ void computeBV<AABB, Capsule>(const Capsule& s, const Transform3f& tf, AABB& bv)
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
 
-  Vec3f v_delta(0.5 * (R.col(2)*s.lz).cwiseAbs() + Vec3f::Constant(s.radius));
+  Vec3f v_delta(R.col(2).cwiseAbs() * s.halfLength + Vec3f::Constant(s.radius));
   bv.max_ = T + v_delta;
   bv.min_ = T - v_delta;
 }
@@ -287,9 +288,9 @@ void computeBV<AABB, Cone>(const Cone& s, const Transform3f& tf, AABB& bv)
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
 
-  FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + 0.5 * fabs(R(0, 2) * s.lz);
-  FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + 0.5 * fabs(R(1, 2) * s.lz);
-  FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + 0.5 * fabs(R(2, 2) * s.lz);
+  FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + fabs(R(0, 2) * s.halfLength);
+  FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + fabs(R(1, 2) * s.halfLength);
+  FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + fabs(R(2, 2) * s.halfLength);
 
   Vec3f v_delta(x_range, y_range, z_range);
   bv.max_ = T + v_delta;
@@ -302,9 +303,9 @@ void computeBV<AABB, Cylinder>(const Cylinder& s, const Transform3f& tf, AABB& b
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
 
-  FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + 0.5 * fabs(R(0, 2) * s.lz);
-  FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + 0.5 * fabs(R(1, 2) * s.lz);
-  FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + 0.5 * fabs(R(2, 2) * s.lz);
+  FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + fabs(R(0, 2) * s.halfLength);
+  FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + fabs(R(1, 2) * s.halfLength);
+  FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + fabs(R(2, 2) * s.halfLength);
 
   Vec3f v_delta(x_range, y_range, z_range);
   bv.max_ = T + v_delta;
@@ -312,7 +313,7 @@ void computeBV<AABB, Cylinder>(const Cylinder& s, const Transform3f& tf, AABB& b
 }
 
 template<>
-void computeBV<AABB, Convex>(const Convex& s, const Transform3f& tf, AABB& bv)
+void computeBV<AABB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, AABB& bv)
 {
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
@@ -405,9 +406,9 @@ void computeBV<OBB, Box>(const Box& s, const Transform3f& tf, OBB& bv)
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
 
-  bv.To.noalias() = T;
-  bv.axes.noalias() = R;
-  bv.extent = s.side * (FCL_REAL)0.5;
+  bv.To = T;
+  bv.axes = R;
+  bv.extent = s.halfSide;
 }
 
 template<>
@@ -428,7 +429,7 @@ void computeBV<OBB, Capsule>(const Capsule& s, const Transform3f& tf, OBB& bv)
 
   bv.To.noalias() = T;
   bv.axes.noalias() = R;
-  bv.extent << s.radius, s.radius, s.lz / 2 + s.radius;
+  bv.extent << s.radius, s.radius, s.halfLength + s.radius;
 }
 
 template<>
@@ -439,7 +440,7 @@ void computeBV<OBB, Cone>(const Cone& s, const Transform3f& tf, OBB& bv)
 
   bv.To.noalias() = T;
   bv.axes.noalias() = R;
-  bv.extent << s.radius, s.radius, s.lz / 2;
+  bv.extent << s.radius, s.radius, s.halfLength;
 }
 
 template<>
@@ -450,11 +451,11 @@ void computeBV<OBB, Cylinder>(const Cylinder& s, const Transform3f& tf, OBB& bv)
 
   bv.To.noalias() = T;
   bv.axes.noalias() = R;
-  bv.extent << s.radius, s.radius, s.lz / 2;
+  bv.extent << s.radius, s.radius, s.halfLength;
 }
 
 template<>
-void computeBV<OBB, Convex>(const Convex& s, const Transform3f& tf, OBB& bv)
+void computeBV<OBB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, OBB& bv)
 {
   const Matrix3f& R = tf.getRotation();
   const Vec3f& T = tf.getTranslation();
@@ -481,7 +482,7 @@ void computeBV<RSS, Halfspace>(const Halfspace&, const Transform3f&, RSS& bv)
   /// Half space can only have very rough RSS
   bv.axes.setIdentity();
   bv.Tr.setZero();
-  bv.l[0] = bv.l[1] = bv.r = std::numeric_limits<FCL_REAL>::max();
+  bv.length[0] = bv.length[1] = bv.radius = std::numeric_limits<FCL_REAL>::max();
 }
 
 template<>
@@ -697,7 +698,7 @@ void computeBV<KDOP<24>, Halfspace>(const Halfspace& s, const Transform3f& tf, K
 template<>
 void computeBV<OBB, Plane>(const Plane& s, const Transform3f& tf, OBB& bv)
 {
-  Vec3f n = tf.getQuatRotation() * s.n;
+  Vec3f n = tf.getRotation() * s.n;
   generateCoordinateSystem(n, bv.axes.col(1), bv.axes.col(2));
   bv.axes.col(0).noalias() = n;
 
@@ -710,15 +711,15 @@ void computeBV<OBB, Plane>(const Plane& s, const Transform3f& tf, OBB& bv)
 template<>
 void computeBV<RSS, Plane>(const Plane& s, const Transform3f& tf, RSS& bv)
 {
-  Vec3f n = tf.getQuatRotation() * s.n;
+  Vec3f n = tf.getRotation() * s.n;
 
   generateCoordinateSystem(n, bv.axes.col(1), bv.axes.col(2));
   bv.axes.col(0).noalias() = n;
 
-  bv.l[0] = std::numeric_limits<FCL_REAL>::max();
-  bv.l[1] = std::numeric_limits<FCL_REAL>::max();
+  bv.length[0] = std::numeric_limits<FCL_REAL>::max();
+  bv.length[1] = std::numeric_limits<FCL_REAL>::max();
 
-  bv.r = 0;
+  bv.radius = 0;
   
   Vec3f p = s.n * s.d;
   bv.Tr = tf.transform(p);
diff --git a/src/traits_traversal.h b/src/traits_traversal.h
new file mode 100644
index 0000000000000000000000000000000000000000..c296ac8fd1068d251f17d5c905d94497c8e2907c
--- /dev/null
+++ b/src/traits_traversal.h
@@ -0,0 +1,105 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2019, CNRS-LAAS
+ *  All rights reserved.
+ */
+
+/** \author Lucile Remigy, Joseph Mirabel */
+
+#include <hpp/fcl/collision_func_matrix.h>
+#include <hpp/fcl/narrowphase/narrowphase.h>
+#include <../src/collision_node.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include <../src/distance_func_matrix.h>
+
+namespace hpp
+{
+namespace fcl
+{
+
+// TraversalTraitsCollision for collision_func_matrix.cpp
+
+template <typename TypeA, typename TypeB>
+struct TraversalTraitsCollision
+{
+};
+
+#ifdef HPP_FCL_HAVE_OCTOMAP
+
+template <typename T_SH>
+struct TraversalTraitsCollision <T_SH, OcTree>
+{
+  typedef ShapeOcTreeCollisionTraversalNode<T_SH> CollisionTraversal_t;
+};
+
+template <typename T_SH>
+struct TraversalTraitsCollision <OcTree, T_SH>
+{
+  typedef OcTreeShapeCollisionTraversalNode<T_SH> CollisionTraversal_t;
+};
+
+template <>
+struct TraversalTraitsCollision <OcTree, OcTree>
+{
+  typedef OcTreeCollisionTraversalNode CollisionTraversal_t;
+};
+
+template <typename T_BVH>
+struct TraversalTraitsCollision <OcTree, BVHModel<T_BVH> >
+{
+  typedef OcTreeMeshCollisionTraversalNode<T_BVH> CollisionTraversal_t;
+};
+
+template <typename T_BVH>
+struct TraversalTraitsCollision <BVHModel<T_BVH>, OcTree>
+{
+  typedef MeshOcTreeCollisionTraversalNode<T_BVH> CollisionTraversal_t;
+};
+
+#endif
+
+// TraversalTraitsDistance for distance_func_matrix.cpp
+
+template <typename TypeA, typename TypeB>
+struct TraversalTraitsDistance
+{
+};
+
+#ifdef HPP_FCL_HAVE_OCTOMAP
+
+template <typename T_SH>
+struct TraversalTraitsDistance <T_SH, OcTree>
+{
+  typedef ShapeOcTreeDistanceTraversalNode<T_SH> CollisionTraversal_t;
+};
+
+template <typename T_SH>
+struct TraversalTraitsDistance <OcTree, T_SH>
+{
+  typedef OcTreeShapeDistanceTraversalNode<T_SH> CollisionTraversal_t;
+};
+
+template <>
+struct TraversalTraitsDistance <OcTree, OcTree>
+{
+  typedef OcTreeDistanceTraversalNode CollisionTraversal_t;
+};
+
+template <typename T_BVH>
+struct TraversalTraitsDistance <OcTree, BVHModel<T_BVH> >
+{
+  typedef OcTreeMeshDistanceTraversalNode<T_BVH> CollisionTraversal_t;
+};
+
+template <typename T_BVH>
+struct TraversalTraitsDistance <BVHModel<T_BVH>, OcTree>
+{
+  typedef MeshOcTreeDistanceTraversalNode<T_BVH> CollisionTraversal_t;
+};
+
+#endif
+
+}
+
+} //hpp
\ No newline at end of file
diff --git a/src/traversal/traversal_node_base.cpp b/src/traversal/traversal_node_base.cpp
index a4bc4eac9dedfa7ecef2ede85ec0ed51ce8f6f68..7ae6ab13286f29f06c8035d2f117a933255d9f7e 100644
--- a/src/traversal/traversal_node_base.cpp
+++ b/src/traversal/traversal_node_base.cpp
@@ -36,7 +36,7 @@
 /** \author Jia Pan */
 
 
-#include <hpp/fcl/traversal/traversal_node_base.h>
+#include <hpp/fcl/internal/traversal_node_base.h>
 #include <limits>
 
 namespace hpp
@@ -97,7 +97,7 @@ DistanceTraversalNodeBase::~DistanceTraversalNodeBase()
 {
 }
 
-  FCL_REAL DistanceTraversalNodeBase::BVTesting(int /*b1*/, int /*b2*/) const
+  FCL_REAL DistanceTraversalNodeBase::BVDistanceLowerBound(int /*b1*/, int /*b2*/) const
 {
   return std::numeric_limits<FCL_REAL>::max();
 }
diff --git a/src/traversal/traversal_node_bvhs.cpp b/src/traversal/traversal_node_bvhs.cpp
index 5fe97fa5a0eaf8b892e77971b24ca2854e8b02d2..cdaeddbecf728bc79ff218f7b12114786eb23f4d 100644
--- a/src/traversal/traversal_node_bvhs.cpp
+++ b/src/traversal/traversal_node_bvhs.cpp
@@ -36,7 +36,7 @@
 /** \author Jia Pan */
 
 
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
 
 namespace hpp
 {
@@ -46,7 +46,7 @@ namespace fcl
 namespace details
 {
 template<typename BV>
-static inline void meshDistanceOrientedNodeLeafTesting(int b1, int b2,
+static inline void meshDistanceOrientedNodeleafComputeDistance(int b1, int b2,
                                                        const BVHModel<BV>* model1, const BVHModel<BV>* model2,
                                                        Vec3f* vertices1, Vec3f* vertices2, 
                                                        Triangle* tri_indices1, Triangle* tri_indices2,
@@ -152,15 +152,15 @@ void MeshDistanceTraversalNodeRSS::postprocess()
   details::distancePostprocessOrientedNode(model1, model2, tf1, request, *result);
 }
 
-FCL_REAL MeshDistanceTraversalNodeRSS::BVTesting(int b1, int b2) const
+FCL_REAL MeshDistanceTraversalNodeRSS::BVDistanceLowerBound(int b1, int b2) const
 {
   if(enable_statistics) num_bv_tests++;
   return distance(R, T, model1->getBV(b1).bv, model2->getBV(b2).bv);
 }
 
-void MeshDistanceTraversalNodeRSS::leafTesting(int b1, int b2) const
+void MeshDistanceTraversalNodeRSS::leafComputeDistance(int b1, int b2) const
 {
-  details::meshDistanceOrientedNodeLeafTesting(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, 
+  details::meshDistanceOrientedNodeleafComputeDistance(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, 
                                                R, T, enable_statistics, num_leaf_tests, 
                                                request, *result);
 }
@@ -180,15 +180,15 @@ void MeshDistanceTraversalNodekIOS::postprocess()
   details::distancePostprocessOrientedNode(model1, model2, tf1, request, *result);
 }
 
-FCL_REAL MeshDistanceTraversalNodekIOS::BVTesting(int b1, int b2) const
+FCL_REAL MeshDistanceTraversalNodekIOS::BVDistanceLowerBound(int b1, int b2) const
 {
   if(enable_statistics) num_bv_tests++;
   return distance(R, T, model1->getBV(b1).bv, model2->getBV(b2).bv);
 }
 
-void MeshDistanceTraversalNodekIOS::leafTesting(int b1, int b2) const
+void MeshDistanceTraversalNodekIOS::leafComputeDistance(int b1, int b2) const
 {
-  details::meshDistanceOrientedNodeLeafTesting(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, 
+  details::meshDistanceOrientedNodeleafComputeDistance(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, 
                                                R, T, enable_statistics, num_leaf_tests, 
                                                request, *result);
 }
@@ -208,15 +208,15 @@ void MeshDistanceTraversalNodeOBBRSS::postprocess()
   details::distancePostprocessOrientedNode(model1, model2, tf1, request, *result);
 }
 
-FCL_REAL MeshDistanceTraversalNodeOBBRSS::BVTesting(int b1, int b2) const
+FCL_REAL MeshDistanceTraversalNodeOBBRSS::BVDistanceLowerBound(int b1, int b2) const
 {
   if(enable_statistics) num_bv_tests++;
   return distance(R, T, model1->getBV(b1).bv, model2->getBV(b2).bv);
 }
 
-void MeshDistanceTraversalNodeOBBRSS::leafTesting(int b1, int b2) const
+void MeshDistanceTraversalNodeOBBRSS::leafComputeDistance(int b1, int b2) const
 {
-  details::meshDistanceOrientedNodeLeafTesting(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, 
+  details::meshDistanceOrientedNodeleafComputeDistance(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, 
                                                R, T, enable_statistics, num_leaf_tests, 
                                                request, *result);
 }
diff --git a/src/traversal/traversal_node_setup.cpp b/src/traversal/traversal_node_setup.cpp
index 7275286062ab008bbba9dcb3abbb7f5d3053bb87..b0d13e489e719ee648d1e17f6a62236bcbbee824 100644
--- a/src/traversal/traversal_node_setup.cpp
+++ b/src/traversal/traversal_node_setup.cpp
@@ -36,81 +36,13 @@
 /** \author Jia Pan */
 
 
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include <hpp/fcl/internal/tools.h>
 namespace hpp
 {
 namespace fcl
 {
 
-
-namespace details
-{
-template<typename BV, typename OrientedNode>
-static inline bool setupMeshCollisionOrientedNode(OrientedNode& node,
-                                                  const BVHModel<BV>& model1, const Transform3f& tf1,
-                                                  const BVHModel<BV>& model2, const Transform3f& tf2,
-                                                  CollisionResult& result)
-{
-  if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
-    return false;
-
-  node.vertices1 = model1.vertices;
-  node.vertices2 = model2.vertices;
-
-  node.tri_indices1 = model1.tri_indices;
-  node.tri_indices2 = model2.tri_indices;
-
-  node.model1 = &model1;
-  node.tf1 = tf1;
-  node.model2 = &model2;
-  node.tf2 = tf2;
-
-  node.result = &result;
-
-  relativeTransform(tf1.getRotation(), tf1.getTranslation(), tf2.getRotation(), tf2.getTranslation(), node.RT.R, node.RT.T);
-
-  return true;
-}
-
-}
-
-
-bool initialize(MeshCollisionTraversalNodeOBB& node,
-                const BVHModel<OBB>& model1, const Transform3f& tf1,
-                const BVHModel<OBB>& model2, const Transform3f& tf2,
-                CollisionResult& result)
-{
-  return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result);
-}
-
-
-bool initialize(MeshCollisionTraversalNodeRSS& node,
-                const BVHModel<RSS>& model1, const Transform3f& tf1,
-                const BVHModel<RSS>& model2, const Transform3f& tf2,
-                CollisionResult& result)
-{
-  return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result);
-}
-
-
-bool initialize(MeshCollisionTraversalNodekIOS& node,
-                const BVHModel<kIOS>& model1, const Transform3f& tf1,
-                const BVHModel<kIOS>& model2, const Transform3f& tf2,
-                CollisionResult& result)
-{
-  return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result);
-}
-
-bool initialize(MeshCollisionTraversalNodeOBBRSS& node,
-                const BVHModel<OBBRSS>& model1, const Transform3f& tf1,
-                const BVHModel<OBBRSS>& model2, const Transform3f& tf2,
-                CollisionResult& result)
-{
-  return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result);
-}
-
-
 namespace details
 {
 template<typename BV, typename OrientedNode>
diff --git a/src/traversal/traversal_recurse.cpp b/src/traversal/traversal_recurse.cpp
index 050c76f0695e4e7a04f27cba1b45b3d32eb6eb60..cf4c822780e59276c4af07fd2fa8e1ae3730a0e0 100644
--- a/src/traversal/traversal_recurse.cpp
+++ b/src/traversal/traversal_recurse.cpp
@@ -36,7 +36,9 @@
 /** \author Jia Pan */
 
 
-#include <hpp/fcl/traversal/traversal_recurse.h>
+#include <hpp/fcl/internal/traversal_recurse.h>
+
+#include <vector>
 
 namespace hpp
 {
@@ -52,12 +54,12 @@ void collisionRecurse(CollisionTraversalNodeBase* node, int b1, int b2,
   {
     updateFrontList(front_list, b1, b2);
 
-    if(node->BVTesting(b1, b2, sqrDistLowerBound)) return;
-    node->leafTesting(b1, b2, sqrDistLowerBound);
+   // if(node->BVDisjoints(b1, b2, sqrDistLowerBound)) return;
+    node->leafCollides(b1, b2, sqrDistLowerBound);
     return;
   }
 
-  if(node->BVTesting(b1, b2, sqrDistLowerBound)) {
+  if(node->BVDisjoints(b1, b2, sqrDistLowerBound)) {
     updateFrontList(front_list, b1, b2);
     return;
   }
@@ -89,18 +91,70 @@ void collisionRecurse(CollisionTraversalNodeBase* node, int b1, int b2,
   }
 }
 
-  void collisionRecurse(MeshCollisionTraversalNodeOBB* /*node*/, int /*b1*/,
-                        int /*b2*/, const Matrix3f& /*R*/, const Vec3f& /*T*/,
-                        BVHFrontList* /*front_list*/)
+void collisionNonRecurse(CollisionTraversalNodeBase* node,
+		         BVHFrontList* front_list, FCL_REAL& sqrDistLowerBound)
 {
-  throw std::runtime_error ("Not implemented.");
-}
+  typedef std::pair<int, int> BVPair_t;
+  //typedef std::stack<BVPair_t, std::vector<BVPair_t> > Stack_t;
+  typedef std::vector<BVPair_t> Stack_t;
+
+  Stack_t pairs;
+  pairs.reserve (1000);
+  sqrDistLowerBound = std::numeric_limits<FCL_REAL>::infinity();
+  FCL_REAL sdlb = std::numeric_limits<FCL_REAL>::infinity();
+
+  pairs.push_back (BVPair_t (0, 0));
+
+  while (!pairs.empty()) {
+    int a = pairs.back().first,
+        b = pairs.back().second;
+    pairs.pop_back();
+
+    bool la = node->isFirstNodeLeaf(a);
+    bool lb = node->isSecondNodeLeaf(b);
+
+    // Leaf / Leaf case
+    if (la && lb) {
+      updateFrontList(front_list, a, b);
+
+      // TODO should we test the BVs ?
+      //if(node->BVDijsoints(a, b, sdlb)) {
+        //if (sdlb < sqrDistLowerBound) sqrDistLowerBound = sdlb;
+        //continue;
+      //}
+      node->leafCollides(a, b, sdlb);
+      if (sdlb < sqrDistLowerBound) sqrDistLowerBound = sdlb;
+      if (node->canStop() && !front_list) return;
+      continue;
+    }
 
-  void collisionRecurse(MeshCollisionTraversalNodeRSS* /*node*/, int /*b1*/,
-                        int /*b2*/, const Matrix3f& /*R*/, const Vec3f& /*T*/,
-                        BVHFrontList* /*front_list*/)
-{
-  throw std::runtime_error ("Not implemented.");
+    // TODO shouldn't we test the leaf triangle against BV is la != lb
+    // if (la && !lb) { // leaf triangle 1 against BV 2
+    // } else if (!la && lb) { // BV 1 against leaf triangle 2
+    // }
+
+    // Check the BV
+    if(node->BVDisjoints(a, b, sdlb)) {
+      if (sdlb < sqrDistLowerBound) sqrDistLowerBound = sdlb;
+      updateFrontList(front_list, a, b);
+      continue;
+    }
+
+    if(node->firstOverSecond(a, b))
+    {
+      int c1 = node->getFirstLeftChild(a);
+      int c2 = node->getFirstRightChild(a);
+      pairs.push_back (BVPair_t (c2, b));
+      pairs.push_back (BVPair_t (c1, b));
+    }
+    else
+    {
+      int c1 = node->getSecondLeftChild(b);
+      int c2 = node->getSecondRightChild(b);
+      pairs.push_back (BVPair_t (a, c2));
+      pairs.push_back (BVPair_t (a, c1));
+    }
+  }
 }
 
 /** Recurse function for self collision
@@ -115,7 +169,7 @@ void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontLi
   {
     updateFrontList(front_list, b1, b2);
 
-    node->leafTesting(b1, b2);
+    node->leafComputeDistance(b1, b2);
     return;
   }
 
@@ -136,8 +190,8 @@ void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontLi
     c2 = node->getSecondRightChild(b2);
   }
 
-  FCL_REAL d1 = node->BVTesting(a1, a2);
-  FCL_REAL d2 = node->BVTesting(c1, c2);
+  FCL_REAL d1 = node->BVDistanceLowerBound(a1, a2);
+  FCL_REAL d2 = node->BVDistanceLowerBound(c1, c2);
 
   if(d2 < d1)
   {
@@ -166,17 +220,17 @@ void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontLi
 }
 
 
-/** \brief Bounding volume test structure */
+/** @brief Bounding volume test structure */
 struct BVT
 {
-  /** \brief distance between bvs */
+  /** @brief distance between bvs */
   FCL_REAL d;
 
-  /** \brief bv indices for a pair of bvs in two models */
+  /** @brief bv indices for a pair of bvs in two models */
   int b1, b2;
 };
 
-/** \brief Comparer between two BVT */
+/** @brief Comparer between two BVT */
 struct BVT_Comparer
 {
   bool operator() (const BVT& lhs, const BVT& rhs) const
@@ -221,7 +275,7 @@ struct BVTQ
 
   std::priority_queue<BVT, std::vector<BVT>, BVT_Comparer> pq;
 
-  /** \brief Queue size */
+  /** @brief Queue size */
   unsigned int qsize;
 };
 
@@ -244,7 +298,7 @@ void distanceQueueRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFr
     {
       updateFrontList(front_list, min_test.b1, min_test.b2);
 
-      node->leafTesting(min_test.b1, min_test.b2);
+      node->leafComputeDistance(min_test.b1, min_test.b2);
     }
     else if(bvtq.full())
     {
@@ -263,11 +317,11 @@ void distanceQueueRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFr
         int c2 = node->getFirstRightChild(min_test.b1);
         bvt1.b1 = c1;
         bvt1.b2 = min_test.b2;
-        bvt1.d = node->BVTesting(bvt1.b1, bvt1.b2);
+        bvt1.d = node->BVDistanceLowerBound(bvt1.b1, bvt1.b2);
 
         bvt2.b1 = c2;
         bvt2.b2 = min_test.b2;
-        bvt2.d = node->BVTesting(bvt2.b1, bvt2.b2);
+        bvt2.d = node->BVDistanceLowerBound(bvt2.b1, bvt2.b2);
       }
       else
       {
@@ -275,11 +329,11 @@ void distanceQueueRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFr
         int c2 = node->getSecondRightChild(min_test.b2);
         bvt1.b1 = min_test.b1;
         bvt1.b2 = c1;
-        bvt1.d = node->BVTesting(bvt1.b1, bvt1.b2);
+        bvt1.d = node->BVDistanceLowerBound(bvt1.b1, bvt1.b2);
 
         bvt2.b1 = min_test.b1;
         bvt2.b2 = c2;
-        bvt2.d = node->BVTesting(bvt2.b1, bvt2.b2);
+        bvt2.d = node->BVDistanceLowerBound(bvt2.b1, bvt2.b2);
       }
 
       bvtq.push(bvt1);
@@ -324,11 +378,11 @@ void propagateBVHFrontListCollisionRecurse
     }
     else
     {
-      if(!node->BVTesting(b1, b2, sqrDistLowerBound)) {
+      if(!node->BVDisjoints(b1, b2, sqrDistLowerBound)) {
         front_iter->valid = false;
         if(node->firstOverSecond(b1, b2)) {
           int c1 = node->getFirstLeftChild(b1);
-          int c2 = node->getFirstRightChild(b2);
+          int c2 = node->getFirstRightChild(b1);
 
           collisionRecurse(node, c1, b2, front_list, sqrDistLowerBound1);
           collisionRecurse(node, c2, b2, front_list, sqrDistLowerBound2);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 88ae18961a525dfdac3b4727a41c883faf384d17..2db77cc854e5afe7f8d759de2a459e4149a9338e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -13,44 +13,52 @@ macro(add_fcl_test test_name)
   target_link_libraries(${test_name}
     hpp-fcl
     ${Boost_LIBRARIES}
+    utility
     )
+  PKG_CONFIG_USE_DEPENDENCY(${test_name} assimp)
   add_test(${test_name} ${EXECUTABLE_OUTPUT_PATH}/${test_name})
 endmacro(add_fcl_test)
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
 
+add_library(utility STATIC utility.cpp)
 
-add_fcl_test(test_fcl_math test_fcl_math.cpp)
+add_fcl_test(math math.cpp)
 
-add_fcl_test(test_fcl_collision test_fcl_collision.cpp test_fcl_utility.cpp)
-add_fcl_test(test_fcl_distance test_fcl_distance.cpp test_fcl_utility.cpp)
-add_fcl_test(test_fcl_distance_lower_bound test_fcl_distance_lower_bound.cpp
-  test_fcl_utility.cpp)
-add_fcl_test(test_fcl_geometric_shapes test_fcl_geometric_shapes.cpp test_fcl_utility.cpp)
-#add_fcl_test(test_fcl_broadphase test_fcl_broadphase.cpp test_fcl_utility.cpp)
-#add_fcl_test(test_fcl_shape_mesh_consistency test_fcl_shape_mesh_consistency.cpp test_fcl_utility.cpp)
-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(collision collision.cpp)
+add_fcl_test(distance distance.cpp)
+add_fcl_test(distance_lower_bound distance_lower_bound.cpp)
+add_fcl_test(geometric_shapes geometric_shapes.cpp)
+#add_fcl_test(broadphase broadphase.cpp)
+#add_fcl_test(shape_mesh_consistency shape_mesh_consistency.cpp)
+add_fcl_test(frontlist frontlist.cpp)
+#add_fcl_test(math math.cpp)
 
-# add_fcl_test(test_fcl_sphere_capsule test_fcl_sphere_capsule.cpp)
-add_fcl_test(test_fcl_capsule_capsule test_fcl_capsule_capsule.cpp test_fcl_utility.cpp)
-add_fcl_test(test_fcl_box_box_distance test_fcl_box_box_distance.cpp test_fcl_utility.cpp)
-add_fcl_test(test_fcl_simple test_fcl_simple.cpp)
-add_fcl_test(test_fcl_capsule_box_1 test_fcl_capsule_box_1.cpp test_fcl_utility.cpp)
-add_fcl_test(test_fcl_capsule_box_2 test_fcl_capsule_box_2.cpp test_fcl_utility.cpp)
-#add_fcl_test(test_fcl_obb test_fcl_obb.cpp)
+# add_fcl_test(sphere_capsule sphere_capsule.cpp)
+add_fcl_test(capsule_capsule capsule_capsule.cpp)
+add_fcl_test(box_box_distance box_box_distance.cpp)
+add_fcl_test(simple simple.cpp)
+add_fcl_test(capsule_box_1 capsule_box_1.cpp)
+add_fcl_test(capsule_box_2 capsule_box_2.cpp)
+add_fcl_test(obb obb.cpp)
+add_fcl_test(convex convex.cpp)
 
-add_fcl_test(test_fcl_bvh_models test_fcl_bvh_models.cpp test_fcl_utility.cpp)
+add_fcl_test(bvh_models bvh_models.cpp)
 
-add_fcl_test(test_fcl_profiling test_fcl_profiling.cpp test_fcl_utility.cpp)
-PKG_CONFIG_USE_DEPENDENCY(test_fcl_profiling assimp)
+add_fcl_test(profiling profiling.cpp)
+PKG_CONFIG_USE_DEPENDENCY(profiling assimp)
 
-add_fcl_test(test_fcl_gjk test_fcl_gjk.cpp)
+add_fcl_test(gjk gjk.cpp)
 if(HPP_FCL_HAVE_OCTOMAP)
-  add_fcl_test(test_fcl_octree test_fcl_octree.cpp test_fcl_utility.cpp)
+  add_fcl_test(octree octree.cpp)
 endif(HPP_FCL_HAVE_OCTOMAP)
 
 ## Benchmark
-add_executable(test-benchmark benchmark.cpp test_fcl_utility.cpp)
-target_link_libraries(test-benchmark hpp-fcl ${Boost_LIBRARIES})
+add_executable(test-benchmark benchmark.cpp)
+target_link_libraries(test-benchmark hpp-fcl ${Boost_LIBRARIES} utility)
+
+## Python tests
+IF(BUILD_PYTHON_INTERFACE)
+  ADD_SUBDIRECTORY(python_unit)
+ENDIF(BUILD_PYTHON_INTERFACE)
diff --git a/test/benchmark.cpp b/test/benchmark.cpp
index 28b718c5df33032ccd153c1b949ac7583ec518d4..2b120ad0963bc32ac7d34ff2e8711b2b13767062 100644
--- a/test/benchmark.cpp
+++ b/test/benchmark.cpp
@@ -14,13 +14,16 @@
 // received a copy of the GNU Lesser General Public License along with
 // hpp-fcl. If not, see <http://www.gnu.org/licenses/>.
 
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
-#include <hpp/fcl/collision_node.h>
-#include "test_fcl_utility.h"
-#include "fcl_resources/config.h"
 #include <boost/filesystem.hpp>
 
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
+#include "../src/collision_node.h"
+#include <hpp/fcl/internal/BV_splitter.h>
+
+#include "utility.h"
+#include "fcl_resources/config.h"
+
 #define RUN_CASE(BV,tf,models,split) \
   run<BV>(tf, models, split, #BV " - " #split ":\t")
 
diff --git a/test/benchmark/test_fcl_gjk.output b/test/benchmark/test_fcl_gjk.output
index aaf9b5434d9259016a2fa21b57aee3875c5e5543..f20f15d5373150ab41cd103d3ca74c2b9639a87f 100644
--- a/test/benchmark/test_fcl_gjk.output
+++ b/test/benchmark/test_fcl_gjk.output
@@ -1,4 +1,4 @@
-Result after running test_fcl_gjk in Release mode.
+Result after running gjk in Release mode.
 
 nCol = 2840
 nDiff = 0
diff --git a/test/test_fcl_box_box_distance.cpp b/test/box_box_distance.cpp
similarity index 99%
rename from test/test_fcl_box_box_distance.cpp
rename to test/box_box_distance.cpp
index 0613a2edf7ce26abf7f5ebbeb788bf1740e2fa59..90d090e30f2c0853ef2bc0449536cf039a3d87ba 100644
--- a/test/test_fcl_box_box_distance.cpp
+++ b/test/box_box_distance.cpp
@@ -42,13 +42,14 @@
 #define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps))
 
 #include <cmath>
+#include <iostream>
 #include <hpp/fcl/distance.h>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
 
-#include "test_fcl_utility.h"
+#include "utility.h"
 
 typedef boost::shared_ptr <hpp::fcl::CollisionGeometry> CollisionGeometryPtr_t;
 
diff --git a/test/test_fcl_broadphase.cpp b/test/broadphase.cpp
similarity index 99%
rename from test/test_fcl_broadphase.cpp
rename to test/broadphase.cpp
index 320b3f2a0ff341309386a314bd83ce21ba0d1e7b..a7a1676f327350421f984225444e925f1e1924c5 100644
--- a/test/test_fcl_broadphase.cpp
+++ b/test/broadphase.cpp
@@ -45,7 +45,7 @@
 #include <hpp/fcl/broadphase/broadphase.h>
 #include <hpp/fcl/shape/geometric_shape_to_BVH_model.h>
 #include <hpp/fcl/math/transform.h>
-#include "test_fcl_utility.h"
+#include "utility.h"
 
 #if USE_GOOGLEHASH
 #include <sparsehash/sparse_hash_map>
diff --git a/test/test_fcl_bvh_models.cpp b/test/bvh_models.cpp
similarity index 86%
rename from test/test_fcl_bvh_models.cpp
rename to test/bvh_models.cpp
index 82c012862ae731b8eae75edbf01b9752f13d074a..4e8990cac95b2391b5f6d85b30d9aa1792d7140a 100644
--- a/test/test_fcl_bvh_models.cpp
+++ b/test/bvh_models.cpp
@@ -44,13 +44,13 @@
 #include "fcl_resources/config.h"
 
 #include <hpp/fcl/collision.h>
-#include "hpp/fcl/BVH/BVH_model.h"
-#include "hpp/fcl/BVH/BVH_utility.h"
-#include "hpp/fcl/math/transform.h"
-#include "hpp/fcl/shape/geometric_shapes.h"
+#include <hpp/fcl/BVH/BVH_model.h>
+#include <hpp/fcl/BVH/BVH_utility.h>
+#include <hpp/fcl/math/transform.h>
+#include <hpp/fcl/shape/geometric_shapes.h>
 #include <hpp/fcl/mesh_loader/assimp.h>
 #include <hpp/fcl/mesh_loader/loader.h>
-#include "test_fcl_utility.h"
+#include "utility.h"
 #include <iostream>
 
 using namespace hpp::fcl;
@@ -72,18 +72,18 @@ void testBVHModelPointCloud()
   }
 
   Box box;
-  double a = box.side[0];
-  double b = box.side[1];
-  double c = box.side[2];
+  double a = box.halfSide[0];
+  double b = box.halfSide[1];
+  double c = box.halfSide[2];
   std::vector<Vec3f> points(8);
-  points[0] << 0.5 * a, -0.5 * b, 0.5 * c;
-  points[1] << 0.5 * a, 0.5 * b, 0.5 * c;
-  points[2] << -0.5 * a, 0.5 * b, 0.5 * c;
-  points[3] << -0.5 * a, -0.5 * b, 0.5 * c;
-  points[4] << 0.5 * a, -0.5 * b, -0.5 * c;
-  points[5] << 0.5 * a, 0.5 * b, -0.5 * c;
-  points[6] << -0.5 * a, 0.5 * b, -0.5 * c;
-  points[7] << -0.5 * a, -0.5 * b, -0.5 * c;
+  points[0] <<  a, -b,  c;
+  points[1] <<  a,  b,  c;
+  points[2] << -a,  b,  c;
+  points[3] << -a, -b,  c;
+  points[4] <<  a, -b, -c;
+  points[5] <<  a,  b, -c;
+  points[6] << -a,  b, -c;
+  points[7] << -a, -b, -c;
 
   int result;
 
@@ -113,19 +113,19 @@ void testBVHModelTriangles()
   Box box(1,1,1);
   AABB aabb (Vec3f(-1,0,-1), Vec3f(1,1,1));
 
-  double a = box.side[0];
-  double b = box.side[1];
-  double c = box.side[2];
+  double a = box.halfSide[0];
+  double b = box.halfSide[1];
+  double c = box.halfSide[2];
   std::vector<Vec3f> points(8);
   std::vector<Triangle> tri_indices(12);
-  points[0] << 0.5 * a, -0.5 * b, 0.5 * c;
-  points[1] << 0.5 * a, 0.5 * b, 0.5 * c;
-  points[2] << -0.5 * a, 0.5 * b, 0.5 * c;
-  points[3] << -0.5 * a, -0.5 * b, 0.5 * c;
-  points[4] << 0.5 * a, -0.5 * b, -0.5 * c;
-  points[5] << 0.5 * a, 0.5 * b, -0.5 * c;
-  points[6] << -0.5 * a, 0.5 * b, -0.5 * c;
-  points[7] << -0.5 * a, -0.5 * b, -0.5 * c;
+  points[0] <<  a, -b,  c;
+  points[1] <<  a,  b,  c;
+  points[2] << -a,  b,  c;
+  points[3] << -a, -b,  c;
+  points[4] <<  a, -b, -c;
+  points[5] <<  a,  b, -c;
+  points[6] << -a,  b, -c;
+  points[7] << -a, -b, -c;
 
   tri_indices[0].set(0, 4, 1);
   tri_indices[1].set(1, 4, 5);
@@ -202,19 +202,19 @@ void testBVHModelSubModel()
   boost::shared_ptr<BVHModel<BV> > model(new BVHModel<BV>);
   Box box;
 
-  double a = box.side[0];
-  double b = box.side[1];
-  double c = box.side[2];
+  double a = box.halfSide[0];
+  double b = box.halfSide[1];
+  double c = box.halfSide[2];
   std::vector<Vec3f> points(8);
   std::vector<Triangle> tri_indices(12);
-  points[0] << 0.5 * a, -0.5 * b, 0.5 * c;
-  points[1] << 0.5 * a, 0.5 * b, 0.5 * c;
-  points[2] << -0.5 * a, 0.5 * b, 0.5 * c;
-  points[3] << -0.5 * a, -0.5 * b, 0.5 * c;
-  points[4] << 0.5 * a, -0.5 * b, -0.5 * c;
-  points[5] << 0.5 * a, 0.5 * b, -0.5 * c;
-  points[6] << -0.5 * a, 0.5 * b, -0.5 * c;
-  points[7] << -0.5 * a, -0.5 * b, -0.5 * c;
+  points[0] <<  a, -b,  c;
+  points[1] <<  a,  b,  c;
+  points[2] << -a,  b,  c;
+  points[3] << -a, -b,  c;
+  points[4] <<  a, -b, -c;
+  points[5] <<  a,  b, -c;
+  points[6] << -a,  b, -c;
+  points[7] << -a, -b, -c;
 
   tri_indices[0].set(0, 4, 1);
   tri_indices[1].set(1, 4, 5);
diff --git a/test/test_fcl_capsule_box_1.cpp b/test/capsule_box_1.cpp
similarity index 98%
rename from test/test_fcl_capsule_box_1.cpp
rename to test/capsule_box_1.cpp
index 8987672a545c2678c6e8c76d6b31081fd31a06e3..9f034b4f62f39edbf70a521e7b3ad77131f272f1 100644
--- a/test/test_fcl_capsule_box_1.cpp
+++ b/test/capsule_box_1.cpp
@@ -49,7 +49,7 @@
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
 
-#include "test_fcl_utility.h"
+#include "utility.h"
 
 BOOST_AUTO_TEST_CASE(distance_capsule_box)
 {
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(distance_capsule_box)
   BOOST_CHECK_CLOSE (o1 [0], 1.0, 1e-1);
   CHECK_CLOSE_TO_0 (o1 [1], 1e-1);
   BOOST_CHECK_CLOSE (o2 [0], 0.5, 1e-1);
-  CHECK_CLOSE_TO_0 (o1 [1], 1e-1);
+  CHECK_CLOSE_TO_0 (o2 [1], 1e-1);
 
   // Move capsule above box
   tf1 = hpp::fcl::Transform3f (hpp::fcl::Vec3f (0., 0., 8.));
diff --git a/test/test_fcl_capsule_box_2.cpp b/test/capsule_box_2.cpp
similarity index 99%
rename from test/test_fcl_capsule_box_2.cpp
rename to test/capsule_box_2.cpp
index f87b6f60b35bf91522ca6191fe8a7290310b04e8..8a20117ab404ec0d648811b71ef71231968e1ad7 100644
--- a/test/test_fcl_capsule_box_2.cpp
+++ b/test/capsule_box_2.cpp
@@ -42,7 +42,7 @@
 
 #define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps))
 
-#include "test_fcl_utility.h"
+#include "utility.h"
 
 #include <cmath>
 #include <hpp/fcl/distance.h>
diff --git a/test/test_fcl_capsule_capsule.cpp b/test/capsule_capsule.cpp
similarity index 99%
rename from test/test_fcl_capsule_capsule.cpp
rename to test/capsule_capsule.cpp
index 9d13e9b0793d5926a31b15d68c5fe23bf1889e00..7dda5376b31576e3fefee5dadbe8c2232d810841 100644
--- a/test/test_fcl_capsule_capsule.cpp
+++ b/test/capsule_capsule.cpp
@@ -43,13 +43,14 @@
 #define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps))
 
 #include <cmath>
+#include <iostream>
 #include <hpp/fcl/distance.h>
 #include <hpp/fcl/math/transform.h>
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/collision_object.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
 
-#include "test_fcl_utility.h"
+#include "utility.h"
 
 using namespace hpp::fcl;
 typedef boost::shared_ptr <CollisionGeometry> CollisionGeometryPtr_t;
diff --git a/test/collision.cpp b/test/collision.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..655ab7908303ae489f7466125aeb2c0e9239c716
--- /dev/null
+++ b/test/collision.cpp
@@ -0,0 +1,644 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2011-2014, Willow Garage, Inc.
+ *  Copyright (c) 2014-2015, Open Source Robotics Foundation
+ *  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 Open Source Robotics Foundation 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 Joseph Mirabel */
+
+#define BOOST_CHRONO_VERSION 2
+#include <boost/chrono/chrono.hpp>
+#include <boost/chrono/chrono_io.hpp>
+
+#define BOOST_TEST_MODULE FCL_COLLISION
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/binary.hpp>
+
+#include <fstream>
+#include <boost/filesystem.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <hpp/fcl/collision.h>
+#include <hpp/fcl/BV/BV.h>
+#include <hpp/fcl/shape/geometric_shapes.h>
+#include <hpp/fcl/narrowphase/narrowphase.h>
+#include <hpp/fcl/mesh_loader/assimp.h>
+
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include "../src/collision_node.h"
+#include <hpp/fcl/internal/BV_splitter.h>
+
+#include "utility.h"
+#include "fcl_resources/config.h"
+
+using namespace hpp::fcl;
+
+int num_max_contacts = std::numeric_limits<int>::max();
+
+BOOST_AUTO_TEST_CASE(OBB_Box_test)
+{
+  FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
+  std::vector<Transform3f> rotate_transform;
+  generateRandomTransforms(r_extents, rotate_transform, 1);
+  
+  AABB aabb1;
+  aabb1.min_ = Vec3f(-600, -600, -600);
+  aabb1.max_ = Vec3f(600, 600, 600);
+
+  OBB obb1;
+  convertBV(aabb1, rotate_transform[0], obb1);
+  Box box1;
+  Transform3f box1_tf;
+  constructBox(aabb1, rotate_transform[0], box1, box1_tf);
+
+  FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
+  std::size_t n = 1000;
+
+  std::vector<Transform3f> transforms;
+  generateRandomTransforms(extents, transforms, n);
+
+  for(std::size_t i = 0; i < transforms.size(); ++i)
+  {
+    AABB aabb;
+    aabb.min_ = aabb1.min_ * 0.5;
+    aabb.max_ = aabb1.max_ * 0.5;    
+
+    OBB obb2;
+    convertBV(aabb, transforms[i], obb2);
+    
+    Box box2;
+    Transform3f box2_tf;
+    constructBox(aabb, transforms[i], box2, box2_tf);
+
+    GJKSolver solver;
+
+    bool overlap_obb = obb1.overlap(obb2);
+    bool overlap_box = solver.shapeIntersect(box1, box1_tf, box2, box2_tf, NULL, NULL, NULL);
+    
+    BOOST_CHECK(overlap_obb == overlap_box);
+  }
+}
+
+BOOST_AUTO_TEST_CASE(OBB_shape_test)
+{
+  FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
+  std::vector<Transform3f> rotate_transform;
+  generateRandomTransforms(r_extents, rotate_transform, 1);
+  
+  AABB aabb1;
+  aabb1.min_ = Vec3f(-600, -600, -600);
+  aabb1.max_ = Vec3f(600, 600, 600);
+
+  OBB obb1;
+  convertBV(aabb1, rotate_transform[0], obb1);
+  Box box1;
+  Transform3f box1_tf;
+  constructBox(aabb1, rotate_transform[0], box1, box1_tf);
+
+  FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
+  std::size_t n = 1000;
+
+  std::vector<Transform3f> transforms;
+  generateRandomTransforms(extents, transforms, n);
+
+  for(std::size_t i = 0; i < transforms.size(); ++i)
+  {
+    FCL_REAL len = (aabb1.max_[0] - aabb1.min_[0]) * 0.5;
+    OBB obb2;
+    GJKSolver solver;
+ 
+    {  
+      Sphere sphere(len);
+      computeBV(sphere, transforms[i], obb2);
+ 
+      bool overlap_obb = obb1.overlap(obb2);
+      bool overlap_sphere = solver.shapeIntersect(box1, box1_tf, sphere, transforms[i], NULL, NULL, NULL);
+      BOOST_CHECK(overlap_obb >= overlap_sphere);
+    }
+
+    {
+      Capsule capsule(len, 2 * len);
+      computeBV(capsule, transforms[i], obb2);
+      
+      bool overlap_obb = obb1.overlap(obb2);
+      bool overlap_capsule = solver.shapeIntersect(box1, box1_tf, capsule, transforms[i], NULL, NULL, NULL);
+      BOOST_CHECK(overlap_obb >= overlap_capsule);
+    }
+
+    {
+      Cone cone(len, 2 * len);
+      computeBV(cone, transforms[i], obb2);
+      
+      bool overlap_obb = obb1.overlap(obb2);
+      bool overlap_cone = solver.shapeIntersect(box1, box1_tf, cone, transforms[i], NULL, NULL, NULL);
+      BOOST_CHECK(overlap_obb >= overlap_cone);
+    }
+
+    {
+      Cylinder cylinder(len, 2 * len);
+      computeBV(cylinder, transforms[i], obb2);
+      
+      bool overlap_obb = obb1.overlap(obb2);
+      bool overlap_cylinder = solver.shapeIntersect(box1, box1_tf, cylinder, transforms[i], NULL, NULL, NULL);
+      BOOST_CHECK(overlap_obb >= overlap_cylinder);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE(OBB_AABB_test)
+{
+  FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
+  std::size_t n = 1000;
+
+  std::vector<Transform3f> transforms;
+  generateRandomTransforms(extents, transforms, n);
+
+  AABB aabb1;
+  aabb1.min_ = Vec3f(-600, -600, -600);
+  aabb1.max_ = Vec3f(600, 600, 600);
+  
+  OBB obb1;
+  convertBV(aabb1, Transform3f(), obb1);
+  
+  for(std::size_t i = 0; i < transforms.size(); ++i)
+  {
+    AABB aabb;
+    aabb.min_ = aabb1.min_ * 0.5;
+    aabb.max_ = aabb1.max_ * 0.5;    
+
+    AABB aabb2 = translate(aabb, transforms[i].getTranslation());
+    
+    OBB obb2;
+    convertBV(aabb, Transform3f(transforms[i].getTranslation()), obb2);
+
+    bool overlap_aabb = aabb1.overlap(aabb2);
+    bool overlap_obb = obb1.overlap(obb2);
+    if(overlap_aabb != overlap_obb)
+    {
+      std::cout << aabb1.min_ << " " << aabb1.max_ << std::endl;
+      std::cout << aabb2.min_ << " " << aabb2.max_ << std::endl;
+      std::cout << obb1.To << " " << obb1.extent << " " << obb1.axes << std::endl;
+      std::cout << obb2.To << " " << obb2.extent << " " << obb2.axes << std::endl;
+    }
+
+    BOOST_CHECK(overlap_aabb == overlap_obb);
+  }
+  std::cout << std::endl;
+}
+
+std::ostream* bench_stream = NULL;
+bool bs_nl = true;
+bool bs_hp = false;
+#define BENCHMARK(stream) if (bench_stream!=NULL) { *bench_stream << (bs_nl ? "" : ", ") << stream; bs_nl = false; }
+#define BENCHMARK_HEADER(stream) if (!bs_hp) { BENCHMARK(stream) }
+#define BENCHMARK_NEXT() if (bench_stream!=NULL && !bs_nl) { *bench_stream << '\n';  bs_nl = true; bs_hp = true; }
+
+typedef std::vector<Contact> Contacts_t;
+typedef boost::mpl::vector<OBB, RSS, KDOP<24>, KDOP<18>, KDOP<16>, kIOS, OBBRSS> BVs_t;
+std::vector<SplitMethodType> splitMethods = boost::assign::list_of (SPLIT_METHOD_MEAN)(SPLIT_METHOD_MEDIAN)(SPLIT_METHOD_BV_CENTER);
+
+typedef boost::chrono::high_resolution_clock clock_type;
+typedef clock_type::duration duration_type;
+
+#define BV_STR_SPECIALIZATION(bv) \
+  template <> const char* str< bv > () { return #bv; }
+template <typename BV> const char* str();
+BV_STR_SPECIALIZATION(AABB)
+BV_STR_SPECIALIZATION(OBB)
+BV_STR_SPECIALIZATION(RSS)
+BV_STR_SPECIALIZATION(KDOP<24>)
+BV_STR_SPECIALIZATION(KDOP<18>)
+BV_STR_SPECIALIZATION(KDOP<16>)
+BV_STR_SPECIALIZATION(kIOS)
+BV_STR_SPECIALIZATION(OBBRSS)
+
+template <typename T> struct wrap {};
+
+struct base_traits
+{
+  enum { IS_IMPLEMENTED = true
+  };
+};
+
+enum {
+  Oriented = true,
+  NonOriented = false,
+  Recursive = true,
+  NonRecursive = false
+};
+
+template<typename BV, bool Oriented, bool recursive>
+struct traits : base_traits
+{};
+
+template<size_t N, bool recursive>
+struct traits<KDOP<N>, Oriented, recursive> : base_traits
+{
+  enum { IS_IMPLEMENTED = false
+  };
+};
+
+struct mesh_mesh_run_test
+{
+  mesh_mesh_run_test (const std::vector<Transform3f>& _transforms,
+      const CollisionRequest _request
+      ) :
+    transforms (_transforms),
+    request (_request),
+    enable_statistics (false),
+    benchmark (false),
+    isInit (false),
+    indent (0)
+  {}
+
+  const std::vector<Transform3f>& transforms;
+  const CollisionRequest request;
+  bool enable_statistics, benchmark;
+  std::vector<Contacts_t> contacts;
+  std::vector<Contacts_t> contacts_ref;
+  bool isInit;
+
+  int indent;
+
+  const char* getindent()
+  {
+    assert (indent < 9);
+    static const char* t[] = { "", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t",
+      "\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t" };
+    return t[indent];
+  }
+
+  template<typename BV>
+  void query (
+      const std::vector<Transform3f>& transforms,
+      SplitMethodType splitMethod,
+      const CollisionRequest request,
+      std::vector<Contacts_t>& contacts
+      )
+  {
+    BENCHMARK_HEADER("BV");
+    BENCHMARK_HEADER("oriented");
+    BENCHMARK_HEADER("Split method");
+    if (enable_statistics) {
+      BENCHMARK_HEADER("num_bv_tests");
+      BENCHMARK_HEADER("num_leaf_tests");
+    }
+    BENCHMARK_HEADER("numContacts");
+    BENCHMARK_HEADER("distance_lower_bound");
+    BENCHMARK_HEADER("time");
+    BENCHMARK_NEXT();
+
+    typedef BVHModel<BV> BVH_t;
+    typedef boost::shared_ptr<BVH_t> BVHPtr_t;
+
+    BVHPtr_t model1 (new BVH_t), model2 (new BVH_t);
+    model1->bv_splitter.reset(new BVSplitter<BV>(splitMethod));
+    model2->bv_splitter.reset(new BVSplitter<BV>(splitMethod));
+
+    loadPolyhedronFromResource (TEST_RESOURCES_DIR "/env.obj", Vec3f::Ones(), model1);
+    loadPolyhedronFromResource (TEST_RESOURCES_DIR "/rob.obj", Vec3f::Ones(), model2);
+
+    clock_type::time_point start, end;
+    const Transform3f tf2;
+    const std::size_t N = transforms.size();
+
+    contacts.resize (3*N);
+
+    if (traits<BV, Oriented, Recursive>::IS_IMPLEMENTED)
+    {
+      BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented");
+      ++indent;
+
+      for(std::size_t i = 0; i < transforms.size(); ++i)
+      {
+        start = clock_type::now();
+        const Transform3f& tf1 = transforms[i];
+
+        CollisionResult local_result;
+        MeshCollisionTraversalNode<BV, 0> node (request);
+        node.enable_statistics = enable_statistics;
+
+        bool success = initialize (node,
+            *model1, tf1, *model2, tf2,
+            local_result);
+        BOOST_REQUIRE (success);
+
+        collide(&node, request, local_result);
+
+        end = clock_type::now();
+
+        BENCHMARK(str<BV>());
+        BENCHMARK(1);
+        BENCHMARK(splitMethod);
+        if (enable_statistics) {
+          BOOST_TEST_MESSAGE (getindent() << "statistics: " << node.num_bv_tests << " " << node.num_leaf_tests);
+          BOOST_TEST_MESSAGE (getindent() << "nb contacts: " << local_result.numContacts());
+          BENCHMARK(node.num_bv_tests);
+          BENCHMARK(node.num_leaf_tests);
+        }
+        BENCHMARK(local_result.numContacts());
+        BENCHMARK(local_result.distance_lower_bound);
+        BENCHMARK((end - start).count());
+        BENCHMARK_NEXT();
+
+        if(local_result.numContacts() > 0)
+        {
+          local_result.getContacts(contacts[i]);
+          std::sort(contacts[i].begin(), contacts[i].end());
+        }
+      }
+      --indent;
+    }
+
+    if (traits<BV, NonOriented, Recursive>::IS_IMPLEMENTED)
+    {
+      BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>());
+      ++indent;
+
+      for(std::size_t i = 0; i < transforms.size(); ++i)
+      {
+        start = clock_type::now();
+        const Transform3f tf1 = transforms[i];
+
+        CollisionResult local_result;
+        MeshCollisionTraversalNode<BV, RelativeTransformationIsIdentity> node (request);
+        node.enable_statistics = enable_statistics;
+
+        BVH_t* model1_tmp = new BVH_t(*model1);
+        Transform3f tf1_tmp = tf1;
+        BVH_t* model2_tmp = new BVH_t(*model2);
+        Transform3f tf2_tmp = tf2;
+
+        bool success = initialize (node,
+            *model1_tmp, tf1_tmp, *model2_tmp, tf2_tmp,
+            local_result, true, true);
+        BOOST_REQUIRE (success);
+
+        collide(&node, request, local_result);
+        delete model1_tmp;
+        delete model2_tmp;
+
+        end = clock_type::now();
+        BENCHMARK(str<BV>());
+        BENCHMARK(2);
+        BENCHMARK(splitMethod);
+        if (enable_statistics) {
+          BOOST_TEST_MESSAGE (getindent() << "statistics: " << node.num_bv_tests << " " << node.num_leaf_tests);
+          BOOST_TEST_MESSAGE (getindent() << "nb contacts: " << local_result.numContacts());
+          BENCHMARK(node.num_bv_tests);
+          BENCHMARK(node.num_leaf_tests);
+        }
+        BENCHMARK(local_result.numContacts());
+        BENCHMARK(local_result.distance_lower_bound);
+        BENCHMARK((end - start).count());
+        BENCHMARK_NEXT();
+
+        if(local_result.numContacts() > 0)
+        {
+          local_result.getContacts(contacts[i+N]);
+          std::sort(contacts[i+N].begin(), contacts[i+N].end());
+        }
+      }
+      --indent;
+    }
+
+    if (traits<BV, Oriented, NonRecursive>::IS_IMPLEMENTED)
+    {
+      BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented non-recursive");
+      ++indent;
+
+      for(std::size_t i = 0; i < transforms.size(); ++i)
+      {
+        start = clock_type::now();
+        const Transform3f tf1 = transforms[i];
+
+        CollisionResult local_result;
+        MeshCollisionTraversalNode<BV, 0> node (request);
+        node.enable_statistics = enable_statistics;
+
+        bool success = initialize (node,
+            *model1, tf1, *model2, tf2,
+            local_result);
+        BOOST_REQUIRE (success);
+
+        collide(&node, request, local_result, NULL, false);
+
+        end = clock_type::now();
+        BENCHMARK(str<BV>());
+        BENCHMARK(0);
+        BENCHMARK(splitMethod);
+        if (enable_statistics) {
+          BOOST_TEST_MESSAGE (getindent() << "statistics: " << node.num_bv_tests << " " << node.num_leaf_tests);
+          BOOST_TEST_MESSAGE (getindent() << "nb contacts: " << local_result.numContacts());
+          BENCHMARK(node.num_bv_tests);
+          BENCHMARK(node.num_leaf_tests);
+        }
+        BENCHMARK(local_result.numContacts());
+        BENCHMARK(local_result.distance_lower_bound);
+        BENCHMARK((end - start).count());
+        BENCHMARK_NEXT();
+
+        if(local_result.numContacts() > 0)
+        {
+          local_result.getContacts(contacts[i+2*N]);
+          std::sort(contacts[i+2*N].begin(), contacts[i+2*N].end());
+        }
+      }
+      --indent;
+    }
+  }
+
+  void check_contacts (std::size_t i0, std::size_t i1, bool warn)
+  {
+    for(std::size_t i = i0; i < i1; ++i) {
+      Contacts_t in_ref_but_not_in_i;
+      std::set_difference (
+          contacts_ref[i].begin(), contacts_ref[i].end(),
+          contacts    [i].begin(), contacts    [i].end(),
+          std::inserter(in_ref_but_not_in_i, in_ref_but_not_in_i.begin()));
+      if(!in_ref_but_not_in_i.empty()) {
+        for(std::size_t j = 0; j < in_ref_but_not_in_i.size(); ++j) {
+          if (warn) {
+            BOOST_WARN_MESSAGE (false, "Missed contacts: "
+                << in_ref_but_not_in_i[j].b1 << ", "
+                << in_ref_but_not_in_i[j].b2);
+          } else {
+            BOOST_CHECK_MESSAGE(false, "Missed contacts: "
+                << in_ref_but_not_in_i[j].b1 << ", "
+                << in_ref_but_not_in_i[j].b2);
+          }
+        }
+      }
+
+      Contacts_t in_i_but_not_in_ref;
+      std::set_difference (
+          contacts    [i].begin(), contacts    [i].end(),
+          contacts_ref[i].begin(), contacts_ref[i].end(),
+          std::inserter(in_i_but_not_in_ref, in_i_but_not_in_ref.begin()));
+
+      if(!in_i_but_not_in_ref.empty()) {
+        for(std::size_t j = 0; j < in_i_but_not_in_ref.size(); ++j) {
+          if (warn) {
+            BOOST_WARN_MESSAGE (false, "False contacts: "
+                << in_i_but_not_in_ref[j].b1 << ", "
+                << in_i_but_not_in_ref[j].b2);
+          } else {
+            BOOST_CHECK_MESSAGE(false, "False contacts: "
+                << in_i_but_not_in_ref[j].b1 << ", "
+                << in_i_but_not_in_ref[j].b2);
+          }
+        }
+      }
+    }
+  }
+
+  template<typename BV>
+  void check ()
+  {
+    if (benchmark) return;
+    const std::size_t N = transforms.size();
+
+    BOOST_REQUIRE_EQUAL(contacts.size(), 3*N);
+    BOOST_REQUIRE_EQUAL(contacts.size(), contacts_ref.size());
+
+    if (traits<BV, Oriented, Recursive>::IS_IMPLEMENTED) {
+      BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented");
+      ++indent;
+      check_contacts (0, N, false);
+      --indent;
+    }
+    if (traits<BV, NonOriented, Recursive>::IS_IMPLEMENTED) {
+      BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>());
+      ++indent;
+      check_contacts (N, 2*N, true);
+      --indent;
+    }
+    if (traits<BV, Oriented, NonRecursive>::IS_IMPLEMENTED) {
+      BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented non-recursive");
+      ++indent;
+      check_contacts (2*N, 3*N, false);
+      --indent;
+    }
+  }
+
+  template<typename BV>
+  void operator() (wrap<BV>)
+  {
+    for (std::size_t i = 0; i < splitMethods.size(); ++i)
+    {
+      BOOST_TEST_MESSAGE (getindent() << "splitMethod: " << splitMethods[i]);
+      ++indent;
+      query <BV> (transforms, splitMethods[i], request, (isInit ? contacts : contacts_ref));
+      if (isInit) check<BV> ();
+      isInit = true;
+      --indent;
+    }
+  }
+};
+
+// This test
+//  1. load two objects "env.obj" and "rob.obj" from directory
+//     fcl_resources,
+//  2. generates n random transformation and for each of them denote tf,
+//    2.1 performs a collision test where object 1 is in pose tf. All
+//        the contacts are stored in vector global_pairs.
+//    2.2 performs a series of collision tests with the same object and
+//        the same poses using various methods and various types of bounding
+//        volumes. Each time the contacts are stored in vector global_pairs_now.
+//
+// The methods used to test collision are
+//  - collide_Test that calls function collide with tf for object1 pose and
+//      identity for the second object pose,
+//  - collide_Test2 that moves all vertices of object1 in pose tf and that
+//      calls function collide with identity for both object poses,
+//
+BOOST_AUTO_TEST_CASE(mesh_mesh)
+{
+  std::vector<Transform3f> transforms;
+  FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000};
+  std::size_t n = 10;
+
+  generateRandomTransforms(extents, transforms, n);
+
+  Eigen::IOFormat f (Eigen::FullPrecision, 0, ", ", ",", "", "", "(", ")");
+  for(std::size_t i = 0; i < transforms.size(); ++i)
+  {
+    BOOST_TEST_MESSAGE("q" << i << "="
+        << transforms [i].getTranslation  ()          .format (f) << "+"
+        << transforms [i].getQuatRotation ().coeffs ().format (f));
+  }
+
+  // Request all contacts and check that all methods give the same result.
+  mesh_mesh_run_test runner (transforms, CollisionRequest (CONTACT, num_max_contacts));
+  runner.enable_statistics = true;
+  boost::mpl::for_each<BVs_t, wrap<boost::mpl::placeholders::_1> > (runner);
+}
+
+BOOST_AUTO_TEST_CASE(mesh_mesh_benchmark)
+{
+  std::vector<Transform3f> transforms;
+  FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000};
+  std::size_t n = 10;
+
+  generateRandomTransforms(extents, transforms, n);
+
+  Eigen::IOFormat f (Eigen::FullPrecision, 0, ", ", ",", "", "", "(", ")");
+  for(std::size_t i = 0; i < transforms.size(); ++i)
+  {
+    BOOST_TEST_MESSAGE("q" << i << "="
+        << transforms [i].getTranslation  ()          .format (f) << "+"
+        << transforms [i].getQuatRotation ().coeffs ().format (f));
+  }
+
+  // Request all contacts and check that all methods give the same result.
+  typedef boost::mpl::vector<OBB, RSS, AABB, KDOP<24>, KDOP<18>, KDOP<16>, kIOS, OBBRSS> BVs_t;
+
+  std::ofstream ofs ("./collision.benchmark.csv", std::ofstream::out);
+  bench_stream = &ofs;
+
+  // without lower bound.
+  mesh_mesh_run_test runner1 (transforms, CollisionRequest ());
+  runner1.enable_statistics = false;
+  runner1.benchmark = true;
+  boost::mpl::for_each<BVs_t, wrap<boost::mpl::placeholders::_1> > (runner1);
+
+  // with lower bound.
+  mesh_mesh_run_test runner2 (transforms, CollisionRequest (DISTANCE_LOWER_BOUND, 1));
+  runner2.enable_statistics = false;
+  runner2.benchmark = true;
+  boost::mpl::for_each<BVs_t, wrap<boost::mpl::placeholders::_1> > (runner2);
+
+  bench_stream = NULL;
+  ofs.close();
+}
diff --git a/test/convex.cpp b/test/convex.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a81b1734ebd89ca6379ea0cc052ab5d321467d9f
--- /dev/null
+++ b/test/convex.cpp
@@ -0,0 +1,240 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2019, LAAS-CNRS
+ *  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 Open Source Robotics Foundation 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 Joseph Mirabel */
+
+
+#define BOOST_TEST_MODULE FCL_GEOMETRIC_SHAPES
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/binary.hpp>
+
+#include <hpp/fcl/shape/convex.h>
+#include <hpp/fcl/collision.h>
+#include <hpp/fcl/distance.h>
+
+#include "utility.h"
+
+using namespace hpp::fcl;
+
+struct Quadrilateral
+{
+public:
+  typedef std::size_t index_type;
+  typedef int size_type;
+
+  Quadrilateral() {}
+
+  Quadrilateral(index_type p0, index_type p1, index_type p2, index_type p3)
+  {
+    set(p0, p1, p2, p3);
+  }
+
+  /// @brief Set the vertex indices of the triangle
+  inline void set(index_type p0, index_type p1, index_type p2, index_type p3)
+  {
+    vids[0] = p0; vids[1] = p1; vids[2] = p2; vids[3] = p3;
+  }
+
+  /// @access the triangle index
+  inline index_type operator[](int i) const { return vids[i]; }
+
+  inline index_type& operator[](int i) { return vids[i]; }
+
+  static inline size_type size() { return 4; }
+
+private:
+  index_type vids[4];
+};
+
+Convex<Quadrilateral> buildBox (FCL_REAL l, FCL_REAL w, FCL_REAL d)
+{
+  Vec3f* pts = new Vec3f[8];
+  pts[0] = Vec3f( l, w, d);
+  pts[1] = Vec3f( l, w,-d);
+  pts[2] = Vec3f( l,-w, d);
+  pts[3] = Vec3f( l,-w,-d);
+  pts[4] = Vec3f(-l, w, d);
+  pts[5] = Vec3f(-l, w,-d);
+  pts[6] = Vec3f(-l,-w, d);
+  pts[7] = Vec3f(-l,-w,-d);
+
+  Quadrilateral* polygons = new Quadrilateral[6];
+  polygons[0].set(0, 2, 3, 1); // x+ side
+  polygons[1].set(2, 6, 7, 3); // y- side
+  polygons[2].set(4, 5, 7, 6); // x- side
+  polygons[3].set(0, 1, 5, 4); // y+ side
+  polygons[4].set(1, 3, 7, 5); // z- side
+  polygons[5].set(0, 2, 6, 4); // z+ side
+
+  return Convex<Quadrilateral> (true,
+      pts, // points
+      8, // num points
+      polygons,
+      6 // number of polygons
+      );
+}
+
+BOOST_AUTO_TEST_CASE(convex)
+{
+  FCL_REAL l = 1, w = 1, d = 1;
+  Convex<Quadrilateral> box (buildBox (l, w, d));
+
+  // Check neighbors
+  for (int i = 0; i < 8; ++i) {
+    BOOST_CHECK_EQUAL(box.neighbors[i].count(), 3);
+  }
+  BOOST_CHECK_EQUAL(box.neighbors[0][0], 1);
+  BOOST_CHECK_EQUAL(box.neighbors[0][1], 2);
+  BOOST_CHECK_EQUAL(box.neighbors[0][2], 4);
+
+  BOOST_CHECK_EQUAL(box.neighbors[1][0], 0);
+  BOOST_CHECK_EQUAL(box.neighbors[1][1], 3);
+  BOOST_CHECK_EQUAL(box.neighbors[1][2], 5);
+
+  BOOST_CHECK_EQUAL(box.neighbors[2][0], 0);
+  BOOST_CHECK_EQUAL(box.neighbors[2][1], 3);
+  BOOST_CHECK_EQUAL(box.neighbors[2][2], 6);
+
+  BOOST_CHECK_EQUAL(box.neighbors[3][0], 1);
+  BOOST_CHECK_EQUAL(box.neighbors[3][1], 2);
+  BOOST_CHECK_EQUAL(box.neighbors[3][2], 7);
+
+  BOOST_CHECK_EQUAL(box.neighbors[4][0], 0);
+  BOOST_CHECK_EQUAL(box.neighbors[4][1], 5);
+  BOOST_CHECK_EQUAL(box.neighbors[4][2], 6);
+
+  BOOST_CHECK_EQUAL(box.neighbors[5][0], 1);
+  BOOST_CHECK_EQUAL(box.neighbors[5][1], 4);
+  BOOST_CHECK_EQUAL(box.neighbors[5][2], 7);
+
+  BOOST_CHECK_EQUAL(box.neighbors[6][0], 2);
+  BOOST_CHECK_EQUAL(box.neighbors[6][1], 4);
+  BOOST_CHECK_EQUAL(box.neighbors[6][2], 7);
+
+  BOOST_CHECK_EQUAL(box.neighbors[7][0], 3);
+  BOOST_CHECK_EQUAL(box.neighbors[7][1], 5);
+  BOOST_CHECK_EQUAL(box.neighbors[7][2], 6);
+}
+
+template <typename Sa, typename Sb> void compareShapeIntersection (
+    const Sa& sa, const Sb& sb, 
+    const Transform3f& tf1, const Transform3f& tf2,
+    FCL_REAL tol = 1e-9)
+{
+  CollisionRequest request (CONTACT | DISTANCE_LOWER_BOUND, 1);
+  CollisionResult resA, resB;
+
+  collide(&sa, tf1, &sa, tf2, request, resA);
+  collide(&sb, tf1, &sb, tf2, request, resB);
+
+  BOOST_CHECK_EQUAL(resA.isCollision(), resB.isCollision());
+  BOOST_CHECK_EQUAL(resA.numContacts(), resB.numContacts());
+
+  if (resA.isCollision() && resB.isCollision()) {
+    Contact cA = resA.getContact(0),
+            cB = resB.getContact(0);
+
+    BOOST_TEST_MESSAGE(
+        tf1 << '\n'
+        << cA.pos.format(pyfmt) << '\n'
+        << '\n'
+        << tf2 << '\n'
+        << cB.pos.format(pyfmt) << '\n'
+        );
+    // Only warnings because there are still some bugs.
+    BOOST_WARN_SMALL((cA.pos    - cB.pos   ).squaredNorm(), tol);
+    BOOST_WARN_SMALL((cA.normal - cB.normal).squaredNorm(), tol);
+  } else {
+    BOOST_CHECK_CLOSE(resA.distance_lower_bound, resB.distance_lower_bound, tol); // distances should be same
+  }
+}
+
+template <typename Sa, typename Sb> void compareShapeDistance (
+    const Sa& sa, const Sb& sb, 
+    const Transform3f& tf1, const Transform3f& tf2,
+    FCL_REAL tol = 1e-9)
+{
+  DistanceRequest request (true);
+  DistanceResult resA, resB;
+
+  distance(&sa, tf1, &sa, tf2, request, resA);
+  distance(&sb, tf1, &sb, tf2, request, resB);
+
+  BOOST_TEST_MESSAGE(
+      tf1 << '\n'
+      << resA.normal.format(pyfmt) << '\n'
+      << resA.nearest_points[0].format(pyfmt) << '\n'
+      << resA.nearest_points[1].format(pyfmt) << '\n'
+      << '\n'
+      << tf2 << '\n'
+      << resB.normal.format(pyfmt) << '\n'
+      << resB.nearest_points[0].format(pyfmt) << '\n'
+      << resB.nearest_points[1].format(pyfmt) << '\n'
+      );
+  // TODO in one case, there is a mismatch between the distances and I cannot say
+  // which one is correct. To visualize the case, use script test/geometric_shapes.py
+  BOOST_WARN_CLOSE(resA.min_distance, resB.min_distance, tol);
+  //BOOST_CHECK_CLOSE(resA.min_distance, resB.min_distance, tol);
+
+  // Only warnings because there are still some bugs.
+  BOOST_WARN_SMALL((resA.normal - resA.normal).squaredNorm(), tol);
+  BOOST_WARN_SMALL((resA.nearest_points[0] - resB.nearest_points[0]).squaredNorm(), tol);
+  BOOST_WARN_SMALL((resA.nearest_points[1] - resB.nearest_points[1]).squaredNorm(), tol);
+}
+
+BOOST_AUTO_TEST_CASE(compare_convex_box)
+{
+  FCL_REAL extents [6] = {0, 0, 0, 10, 10, 10};
+  FCL_REAL l = 1, w = 1, d = 1;
+  Box box(l*2, w*2, d*2);
+  Convex<Quadrilateral> convex_box (buildBox (l, w, d));
+
+  Transform3f tf1;
+  Transform3f tf2;
+
+  tf2.setTranslation (Vec3f (3, 0, 0));
+  compareShapeIntersection(box, convex_box, tf1, tf2);
+  compareShapeDistance    (box, convex_box, tf1, tf2);
+
+  tf2.setTranslation (Vec3f (0, 0, 0));
+  compareShapeIntersection(box, convex_box, tf1, tf2);
+  compareShapeDistance    (box, convex_box, tf1, tf2);
+
+  for (int i = 0; i < 1000; ++i) {
+    generateRandomTransform(extents, tf2);
+    compareShapeIntersection(box, convex_box, tf1, tf2);
+    compareShapeDistance    (box, convex_box, tf1, tf2);
+  }
+}
diff --git a/test/test_fcl_distance.cpp b/test/distance.cpp
similarity index 98%
rename from test/test_fcl_distance.cpp
rename to test/distance.cpp
index 35eb58408d061fbafbed6f6f8ff60ad9ffebfae8..dc4c2489aa433d1591e7dda3b04b742b7f091c18 100644
--- a/test/test_fcl_distance.cpp
+++ b/test/distance.cpp
@@ -39,15 +39,17 @@
 #define BOOST_TEST_DYN_LINK
 #include <boost/test/unit_test.hpp>
 #include <boost/utility/binary.hpp>
-
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-#include <hpp/fcl/collision_node.h>
-#include "test_fcl_utility.h"
 #include <boost/timer.hpp>
-#include "fcl_resources/config.h"
 #include <boost/filesystem.hpp>
 
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include "../src/collision_node.h"
+#include <hpp/fcl/internal/BV_splitter.h>
+
+#include "utility.h"
+#include "fcl_resources/config.h"
+
 using namespace hpp::fcl;
 
 bool verbose = false;
@@ -447,7 +449,7 @@ bool collide_Test_OBB(const Transform3f& tf,
   bool success (initialize(node, (const BVHModel<OBB>&)m1, tf,
                            (const BVHModel<OBB>&)m2, Transform3f(),
                            local_result));
-  assert (success);
+  BOOST_REQUIRE (success);
 
   node.enable_statistics = verbose;
 
diff --git a/test/test_fcl_distance_lower_bound.cpp b/test/distance_lower_bound.cpp
similarity index 99%
rename from test/test_fcl_distance_lower_bound.cpp
rename to test/distance_lower_bound.cpp
index ee825ba65ff603fac9c0b29617e24256035e5887..0d5a0645d9060ee6e44f756a0dbece6e4ef5df1f 100644
--- a/test/test_fcl_distance_lower_bound.cpp
+++ b/test/distance_lower_bound.cpp
@@ -45,7 +45,7 @@
 #include <hpp/fcl/narrowphase/narrowphase.h>
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/distance.h>
-# include "test_fcl_utility.h"
+# include "utility.h"
 # include "fcl_resources/config.h"
 
 using hpp::fcl::Transform3f;
diff --git a/test/test_fcl_eigen.cpp b/test/eigen.cpp
similarity index 98%
rename from test/test_fcl_eigen.cpp
rename to test/eigen.cpp
index a1bcb12fa7dcb3b5398840e8641ee004671930fc..5b50dce7d6a3fef520f98ee6d6761702a1e52666 100644
--- a/test/test_fcl_eigen.cpp
+++ b/test/eigen.cpp
@@ -102,11 +102,11 @@ BOOST_AUTO_TEST_CASE(fcl_eigen_matrix3fx)
   a *= a;
   PRINT_MATRIX(a);
 
-  Matrix3fX b = inverse(a);
+  Matrix3fX b = a.inverse();
   a += a + a * b;
   PRINT_MATRIX(a);
 
-  b = inverse(a);
+  b = a.inverse();
   a.transpose ();
   PRINT_MATRIX(a);
   PRINT_MATRIX(a.transposeTimes (b));
diff --git a/test/test_fcl_frontlist.cpp b/test/frontlist.cpp
similarity index 97%
rename from test/test_fcl_frontlist.cpp
rename to test/frontlist.cpp
index 36a5c312423916e04fb09c648c74f81baac85d1e..9762d69b272c0211a7cd12778dba22e6cc2b6fd7 100644
--- a/test/test_fcl_frontlist.cpp
+++ b/test/frontlist.cpp
@@ -41,10 +41,11 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/utility/binary.hpp>
 
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-#include <hpp/fcl/collision_node.h>
-#include "test_fcl_utility.h"
+#include <hpp/fcl/internal/traversal_node_bvhs.h>
+#include <hpp/fcl/internal/traversal_node_setup.h>
+#include <../src/collision_node.h>
+#include <hpp/fcl/internal/BV_splitter.h>
+#include "utility.h"
 
 #include "fcl_resources/config.h"
 #include <boost/filesystem.hpp>
@@ -83,7 +84,11 @@ BOOST_AUTO_TEST_CASE(front_list)
   std::vector<Transform3f> transforms2; // t1
   FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000};
   FCL_REAL delta_trans[] = {1, 1, 1};
-  std::size_t n = 10;
+#ifdef NDEBUG
+  std::size_t n = 20;
+#else
+  std::size_t n = 5;
+#endif
   bool verbose = false;
 
   generateRandomTransforms(extents, delta_trans, 0.005 * 2 * 3.1415, transforms, transforms2, n);
@@ -233,7 +238,7 @@ bool collide_front_list_Test(const Transform3f& tf1, const Transform3f& tf2,
   MeshCollisionTraversalNode<BV> node (request);
 
   bool success = initialize <BV>(node, m1, pose1, m2, pose2, local_result);
-  assert (success);
+  BOOST_REQUIRE (success);
 
   node.enable_statistics = verbose;
 
@@ -297,7 +302,7 @@ bool collide_front_list_Test_Oriented(const Transform3f& tf1, const Transform3f&
 
   bool success = initialize (node, (const BVHModel<BV>&)m1, pose1,
                              (const BVHModel<BV>&)m2, pose2, local_result);
-  assert (success);
+  BOOST_REQUIRE (success);
 
   node.enable_statistics = verbose;
 
@@ -310,7 +315,7 @@ bool collide_front_list_Test_Oriented(const Transform3f& tf1, const Transform3f&
   pose1 = tf2;
   success = initialize (node, (const BVHModel<BV>&)m1, pose1,
                         (const BVHModel<BV>&)m2, pose2, local_result);
-  assert (success);
+  BOOST_REQUIRE (success);
 
   local_result.clear();
   collide(&node, request, local_result, &front_list);
@@ -347,7 +352,7 @@ bool collide_Test(const Transform3f& tf,
   MeshCollisionTraversalNode<BV> node (request);
 
   bool success = initialize <BV>(node, m1, pose1, m2, pose2, local_result);
-  assert (success);
+  BOOST_REQUIRE (success);
 
   node.enable_statistics = verbose;
 
diff --git a/test/general_test.cpp b/test/general_test.cpp
index 947682b2285caecd2b66223b03213eaeae46a5a7..144eb5fc3ad31c2be3cc35465f6dd738f9a0b718 100644
--- a/test/general_test.cpp
+++ b/test/general_test.cpp
@@ -12,7 +12,6 @@ int main(int argc, char** argv)
 {
   boost::shared_ptr<Box> box0(new Box(1,1,1));
   boost::shared_ptr<Box> box1(new Box(1,1,1));
-//  GJKSolver_indep solver;
   GJKSolver_libccd solver;
   Vec3f contact_points;
   FCL_REAL penetration_depth;
diff --git a/test/test_fcl_geometric_shapes.cpp b/test/geometric_shapes.cpp
similarity index 94%
rename from test/test_fcl_geometric_shapes.cpp
rename to test/geometric_shapes.cpp
index 60df213b657c9818bf7667b2ecd725c448f516ff..08b22fec339ab5d1e987fb9875ea38c82a9e066c 100644
--- a/test/test_fcl_geometric_shapes.cpp
+++ b/test/geometric_shapes.cpp
@@ -44,32 +44,17 @@
 #include <hpp/fcl/narrowphase/narrowphase.h>
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/distance.h>
-#include "test_fcl_utility.h"
+#include "utility.h"
 #include <iostream>
+#include <hpp/fcl/internal/tools.h>
 
 using namespace hpp::fcl;
 
 FCL_REAL extents [6] = {0, 0, 0, 10, 10, 10};
 
 FCL_REAL tol_gjk = 0.01;
-GJKSolver_indep solver1;
-GJKSolver_indep solver2;
-
-Eigen::IOFormat fmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "", "");
-Eigen::IOFormat pyfmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "[", "]");
-
-namespace hpp {
-namespace fcl {
-std::ostream& operator<< (std::ostream& os, const Transform3f& tf)
-{
-  return os << "[ " <<
-    tf.getTranslation().format(fmt)
-    << ", "
-    << tf.getQuatRotation().coeffs().format(fmt)
-    << " ]" ;
-}
-}
-}
+GJKSolver solver1;
+GJKSolver solver2;
 
 #define BOOST_CHECK_FALSE(p) BOOST_CHECK(!(p))
 
@@ -204,72 +189,6 @@ void testShapeIntersection(const S1& s1, const Transform3f& tf1,
   }
 }
 
-template <typename Sa, typename Sb> void compareShapeIntersection (
-    const Sa& sa, const Sb& sb, 
-    const Transform3f& tf1, const Transform3f& tf2,
-    FCL_REAL tol = 1e-9)
-{
-  CollisionRequest request (CONTACT | DISTANCE_LOWER_BOUND, 1);
-  CollisionResult resA, resB;
-
-  collide(&sa, tf1, &sa, tf2, request, resA);
-  collide(&sb, tf1, &sb, tf2, request, resB);
-
-  BOOST_CHECK_EQUAL(resA.isCollision(), resB.isCollision());
-  BOOST_CHECK_EQUAL(resA.numContacts(), resB.numContacts());
-
-  if (resA.isCollision() && resB.isCollision()) {
-    Contact cA = resA.getContact(0),
-            cB = resB.getContact(0);
-
-    BOOST_TEST_MESSAGE(
-        tf1 << '\n'
-        << cA.pos.format(pyfmt) << '\n'
-        << '\n'
-        << tf2 << '\n'
-        << cB.pos.format(pyfmt) << '\n'
-        );
-    // Only warnings because there are still some bugs.
-    BOOST_WARN_SMALL((cA.pos    - cB.pos   ).squaredNorm(), tol);
-    BOOST_WARN_SMALL((cA.normal - cB.normal).squaredNorm(), tol);
-  } else {
-    BOOST_CHECK_CLOSE(resA.distance_lower_bound, resB.distance_lower_bound, tol); // distances should be same
-  }
-}
-
-template <typename Sa, typename Sb> void compareShapeDistance (
-    const Sa& sa, const Sb& sb, 
-    const Transform3f& tf1, const Transform3f& tf2,
-    FCL_REAL tol = 1e-9)
-{
-  DistanceRequest request (true);
-  DistanceResult resA, resB;
-
-  distance(&sa, tf1, &sa, tf2, request, resA);
-  distance(&sb, tf1, &sb, tf2, request, resB);
-
-  BOOST_TEST_MESSAGE(
-      tf1 << '\n'
-      << resA.normal.format(pyfmt) << '\n'
-      << resA.nearest_points[0].format(pyfmt) << '\n'
-      << resA.nearest_points[1].format(pyfmt) << '\n'
-      << '\n'
-      << tf2 << '\n'
-      << resB.normal.format(pyfmt) << '\n'
-      << resB.nearest_points[0].format(pyfmt) << '\n'
-      << resB.nearest_points[1].format(pyfmt) << '\n'
-      );
-  // TODO in one case, there is a mismatch between the distances and I cannot say
-  // which one is correct. To visualize the case, use script test/test_fcl_geometric_shapes.py
-  BOOST_WARN_CLOSE(resA.min_distance, resB.min_distance, tol);
-  //BOOST_CHECK_CLOSE(resA.min_distance, resB.min_distance, tol);
-
-  // Only warnings because there are still some bugs.
-  BOOST_WARN_SMALL((resA.normal - resA.normal).squaredNorm(), tol);
-  BOOST_WARN_SMALL((resA.nearest_points[0] - resB.nearest_points[0]).squaredNorm(), tol);
-  BOOST_WARN_SMALL((resA.nearest_points[1] - resB.nearest_points[1]).squaredNorm(), tol);
-}
-
 BOOST_AUTO_TEST_CASE (shapeIntersection_cylinderbox)
 {
   Cylinder s1 (0.029, 0.1);
@@ -284,21 +203,19 @@ BOOST_AUTO_TEST_CASE (shapeIntersection_cylinderbox)
     (Quaternion3f (0.70738826916719977, 0, 0, 0.70682518110536596),
      Vec3f (-0.29936284351096382, 0.80023864435868775, 0.71750000000000003));
 
-  GJKSolver_indep solver;
+  GJKSolver solver;
   FCL_REAL distance;
   Vec3f p1, p2, normal;
   bool res = solver.shapeDistance (s1, tf1, s2, tf2, distance, p1, p2, normal);
   BOOST_CHECK ((res && distance > 0) || (!res && distance <= 0));
   // If objects are not colliding, p2 should be outside the cylinder and
   // p1 should be outside the box
-  Vec3f p2Loc (inverse (tf1).transform (p2));
-  bool p2_in_cylinder ((fabs (p2Loc [2]) <= .5*s1.lz) &&
+  Vec3f p2Loc (tf1.inverse().transform (p2));
+  bool p2_in_cylinder ((fabs (p2Loc [2]) <= s1.halfLength) &&
                        (p2Loc [0] * p2Loc [0] + p2Loc [1] * p2Loc [1]
                         <= s1.radius));
-  Vec3f p1Loc (inverse (tf2).transform (p1));
-  bool p1_in_box ((fabs (p1Loc [0]) <= .5 * s2.side [0]) &&
-                  (fabs (p1Loc [1]) <= .5 * s2.side [1]) &&
-                  (fabs (p1Loc [2]) <= .5 * s2.side [2]));
+  Vec3f p1Loc (tf2.inverse().transform (p1));
+  bool p1_in_box = (p1Loc.array().abs() <= s2.halfSide.array()).all();
   std::cout << "p2 in cylinder = (" << p2Loc.transpose () << ")" << std::endl;
   std::cout << "p1 in box = (" << p1Loc.transpose () << ")" << std::endl;
 
@@ -310,14 +227,12 @@ BOOST_AUTO_TEST_CASE (shapeIntersection_cylinderbox)
   // If objects are not colliding, p2 should be outside the cylinder and
   // p1 should be outside the box
 
-  p2Loc = inverse (tf1).transform (p2);
-  p2_in_cylinder = (fabs (p2Loc [2]) <= .5*s1.lz) &&
+  p2Loc = tf1.inverse().transform (p2);
+  p2_in_cylinder = (fabs (p2Loc [2]) <= s1.halfLength) &&
     (p2Loc [0] * p2Loc [0] + p2Loc [1] * p2Loc [1]
      <= s1.radius);
-  p1Loc = inverse (tf2).transform (p1);
-  p1_in_box = (fabs (p1Loc [0]) <= .5 * s2.side [0]) &&
-    (fabs (p1Loc [1]) <= .5 * s2.side [1]) &&
-    (fabs (p1Loc [2]) <= .5 * s2.side [2]);
+  p1Loc = tf2.inverse().transform (p1);
+  p1_in_box = (p1Loc.array().abs() <= s2.halfSide.array()).all();
 
   std::cout << "p2 in cylinder = (" << p2Loc.transpose () << ")" << std::endl;
   std::cout << "p1 in box = (" << p1.transpose () << ")" << std::endl;
@@ -440,9 +355,7 @@ void testBoxBoxContactPoints(const Matrix3f& R)
 
   for (int i = 0; i < 8; ++i)
   {
-    vertices[i][0] *= 0.5 * s2.side[0];
-    vertices[i][1] *= 0.5 * s2.side[1];
-    vertices[i][2] *= 0.5 * s2.side[2];
+    vertices[i].array() *= s2.halfSide.array();
   }
 
   Transform3f tf1 = Transform3f(Vec3f(0, 0, -50));
@@ -483,7 +396,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_boxbox)
   Vec3f normal;
 
   Quaternion3f q;
-  q = Eigen::AngleAxis<double>((FCL_REAL)3.140 / 6, Vec3f(0, 0, 1));
+  q = AngleAxis((FCL_REAL)3.140 / 6, UnitZ);
 
   tf1 = Transform3f();
   tf2 = Transform3f();
@@ -525,82 +438,6 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_boxbox)
   }
 }
 
-BOOST_AUTO_TEST_CASE(compare_convex_box)
-{
-  FCL_REAL l = 1, w = 1, d = 1;
-  Box box(l*2, w*2, d*2);
-
-  Vec3f pts[8];
-  pts[0] = Vec3f( l, w, d);
-  pts[1] = Vec3f( l, w,-d);
-  pts[2] = Vec3f( l,-w, d);
-  pts[3] = Vec3f( l,-w,-d);
-  pts[4] = Vec3f(-l, w, d);
-  pts[5] = Vec3f(-l, w,-d);
-  pts[6] = Vec3f(-l,-w, d);
-  pts[7] = Vec3f(-l,-w,-d);
-  std::vector<int> polygons;
-  polygons.push_back(4);
-  polygons.push_back(0);
-  polygons.push_back(2);
-  polygons.push_back(3);
-  polygons.push_back(1);
-
-  polygons.push_back(4);
-  polygons.push_back(2);
-  polygons.push_back(6);
-  polygons.push_back(7);
-  polygons.push_back(3);
-
-  polygons.push_back(4);
-  polygons.push_back(4);
-  polygons.push_back(5);
-  polygons.push_back(7);
-  polygons.push_back(6);
-
-  polygons.push_back(4);
-  polygons.push_back(0);
-  polygons.push_back(1);
-  polygons.push_back(5);
-  polygons.push_back(4);
-
-  polygons.push_back(4);
-  polygons.push_back(1);
-  polygons.push_back(3);
-  polygons.push_back(7);
-  polygons.push_back(5);
-
-  polygons.push_back(4);
-  polygons.push_back(0);
-  polygons.push_back(2);
-  polygons.push_back(6);
-  polygons.push_back(4);
-
-  Convex convex_box (
-      pts, // points
-      8, // num points
-      polygons.data(),
-      6 // number of polygons
-      );
-
-  Transform3f tf1;
-  Transform3f tf2;
-
-  tf2.setTranslation (Vec3f (3, 0, 0));
-  compareShapeIntersection(box, convex_box, tf1, tf2);
-  compareShapeDistance    (box, convex_box, tf1, tf2);
-
-  tf2.setTranslation (Vec3f (0, 0, 0));
-  compareShapeIntersection(box, convex_box, tf1, tf2);
-  compareShapeDistance    (box, convex_box, tf1, tf2);
-
-  for (int i = 0; i < 1000; ++i) {
-    generateRandomTransform(extents, tf2);
-    compareShapeIntersection(box, convex_box, tf1, tf2);
-    compareShapeDistance    (box, convex_box, tf1, tf2);
-  }
-}
-
 BOOST_AUTO_TEST_CASE(shapeIntersection_spherebox)
 {
   Sphere s1(20);
@@ -954,20 +791,27 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacetriangle)
      normal);
   BOOST_CHECK(res);
 
+  // These tests fail because of numerical precision errors. The points t[1] and t[2]
+  // lies on the border of the half-space.
+  // The normals should be good, when computed (i.e. res == true)
   res =  solver1.shapeTriangleInteraction
     (hs, transform, t[0], t[1], t[2], transform, distance, c1, c2, normal);
-  BOOST_CHECK(res);
+  // BOOST_CHECK(res);
+  if (res)
+    BOOST_CHECK(isEqual(normal, transform.getRotation() * Vec3f(1, 0, 0), 1e-9));
 
   res = solver1.shapeTriangleInteraction
     (hs, Transform3f(), t[0], t[1], t[2], Transform3f(), distance, c1, c2,
      normal);
-  BOOST_CHECK(res);
-  BOOST_CHECK(isEqual(normal, Vec3f(1, 0, 0), 1e-9));
+  // BOOST_CHECK(res);
+  if (res)
+    BOOST_CHECK(isEqual(normal, Vec3f(1, 0, 0), 1e-9));
 
   res =  solver1.shapeTriangleInteraction
     (hs, transform, t[0], t[1], t[2], transform, distance, c1, c2, normal);
-  BOOST_CHECK(res);
-  BOOST_CHECK(isEqual(normal, transform.getRotation() * Vec3f(1, 0, 0), 1e-9));
+  // BOOST_CHECK(res);
+  if (res)
+    BOOST_CHECK(isEqual(normal, transform.getRotation() * Vec3f(1, 0, 0), 1e-9));
 }
 
 BOOST_AUTO_TEST_CASE(shapeIntersection_planetriangle)
@@ -1042,7 +886,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere)
   tf2 = transform;
   contact = transform.transform(Vec3f(-5, 0, 0));
   depth = 10;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1056,7 +900,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere)
   tf2 = transform * Transform3f(Vec3f(5, 0, 0));
   contact = transform.transform(Vec3f(-2.5, 0, 0));
   depth = 15;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1070,7 +914,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere)
   tf2 = transform * Transform3f(Vec3f(-5, 0, 0));
   contact = transform.transform(Vec3f(-7.5, 0, 0));
   depth = 5;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1092,7 +936,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere)
   tf2 = transform * Transform3f(Vec3f(10.1, 0, 0));
   contact = transform.transform(Vec3f(0.05, 0, 0));
   depth = 20.1;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 }
 
@@ -1196,7 +1040,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox)
   tf2 = transform;
   contact = transform.transform(Vec3f(-1.25, 0, 0));
   depth = 2.5;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1210,7 +1054,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox)
   tf2 = transform * Transform3f(Vec3f(1.25, 0, 0));
   contact = transform.transform(Vec3f(-0.625, 0, 0));
   depth = 3.75;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1224,7 +1068,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox)
   tf2 = transform * Transform3f(Vec3f(-1.25, 0, 0));
   contact = transform.transform(Vec3f(-1.875, 0, 0));
   depth = 1.25;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1238,7 +1082,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox)
   tf2 = transform * Transform3f(Vec3f(2.51, 0, 0));
   contact = transform.transform(Vec3f(0.005, 0, 0));
   depth = 5.01;
-  normal = transform.getQuatRotation() * Vec3f(-1, 0, 0);
+  normal = transform.getRotation() * Vec3f(-1, 0, 0);
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal);
 
   tf1 = Transform3f();
@@ -1249,7 +1093,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox)
   tf2 = transform * Transform3f(Vec3f(-2.51, 0, 0));
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, false);
 
-  tf1 = Transform3f(transform.getQuatRotation());
+  tf1 = Transform3f(transform.getRotation());
   tf2 = Transform3f();
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true);
 }
@@ -1327,7 +1171,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_planebox)
   tf2 = transform * Transform3f(Vec3f(-2.51, 0, 0));
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, false);
 
-  tf1 = Transform3f(transform.getQuatRotation());
+  tf1 = Transform3f(transform.getRotation());
   tf2 = Transform3f();
   testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true);
 }
@@ -3059,7 +2903,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_boxbox)
   Vec3f normal;
 
   Quaternion3f q;
-  q = Eigen::AngleAxis<double>((FCL_REAL)3.140 / 6, Vec3f(0, 0, 1));
+  q = AngleAxis((FCL_REAL)3.140 / 6, UnitZ);
 
   tf1 = Transform3f();
   tf2 = Transform3f();
diff --git a/test/gjk-geometric-tools-benchmark b/test/gjk-geometric-tools-benchmark
index 4104d7511f78c3d9f22b4b16fe63395dcacdd5e5..7e522128798f30f7b695f22cf95f674eae03e7bc 100644
--- a/test/gjk-geometric-tools-benchmark
+++ b/test/gjk-geometric-tools-benchmark
@@ -1,4 +1,4 @@
-Result after running test_fcl_gjk.cpp in Release mode.
+Result after running gjk.cpp in Release mode.
 
 nCol = 2831
 nDiff = 41
diff --git a/test/test_fcl_gjk.cpp b/test/gjk.cpp
similarity index 93%
rename from test/test_fcl_gjk.cpp
rename to test/gjk.cpp
index 3bb9b907684090dd37281b3f02495ee24ae237b7..ef05e979ff8ec349ca04130a8283618ccb9ecc6c 100644
--- a/test/test_fcl_gjk.cpp
+++ b/test/gjk.cpp
@@ -43,8 +43,9 @@
 
 #include <hpp/fcl/narrowphase/narrowphase.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
+#include<hpp/fcl/internal/tools.h>
 
-using hpp::fcl::GJKSolver_indep;
+using hpp::fcl::GJKSolver;
 using hpp::fcl::TriangleP;
 using hpp::fcl::Vec3f;
 using hpp::fcl::Quaternion3f;
@@ -73,7 +74,7 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1)
   Eigen::IOFormat tuple (Eigen::FullPrecision, Eigen::DontAlignCols, "",
                          ", ", "", "", "(", ")");
   std::size_t N = 10000;
-  GJKSolver_indep solver;
+  GJKSolver solver;
   Transform3f tf1, tf2;
   Vec3f p1, p2, a1, a2;
   Matrix3f M;
@@ -183,11 +184,11 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1)
     BOOST_CHECK (w1.squaredNorm () > eps*eps);
     M.col (0) = u1; M.col (1) = v1; M.col (2) = w1;
     // Compute a1 such that p1 = P1 + a11 u1 + a12 v1 + a13 u1 x v1
-    a1 = M.inverse () * (p1 - P1);
+    a1 = M.inverse() * (p1 - P1);
     BOOST_CHECK (w2.squaredNorm () > eps*eps);
     // Compute a2 such that p2 = Q1 + a21 u2 + a22 v2 + a23 u2 x v2
     M.col (0) = u2; M.col (1) = v2; M.col (2) = w2;
-    a2 = M.inverse () * (p2 - Q1);
+    a2 = M.inverse() * (p2 - Q1);
 
     // minimal distance and closest points can be considered as a constrained
     // optimisation problem:
@@ -268,7 +269,7 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1)
       }
     }
   }
-  std::cerr << "nCol = " << nCol << std::endl;
+  std::cerr << "nCol / nTotal = " << nCol << " / " << N << std::endl;
   std::cerr << "nDiff = " << nDiff << std::endl;
   // statistics
   clock_t totalTimeGjkColl = 0;
@@ -280,10 +281,10 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1)
       totalTimeGjkNoColl += results [i].timeGjk;
     }
   }
-  std::cerr << "Total time gjk: " << totalTimeGjkNoColl + totalTimeGjkColl
-            << std::endl;
+  std::cerr << "Total / average time gjk: " << totalTimeGjkNoColl + totalTimeGjkColl
+            << ", " << FCL_REAL(totalTimeGjkNoColl + totalTimeGjkColl) / FCL_REAL(CLOCKS_PER_SEC*N) << "s" << std::endl;
   std::cerr << "-- Collisions -------------------------" << std::endl;
-  std::cerr << "Total time gjk: " << totalTimeGjkColl << std::endl;
+  std::cerr << "Total / average time gjk: " << totalTimeGjkColl << ", " << FCL_REAL(totalTimeGjkColl) / FCL_REAL(CLOCKS_PER_SEC*nCol) << "s" << std::endl;
   std::cerr << "-- No collisions -------------------------" << std::endl;
-  std::cerr << "Total time gjk: " << totalTimeGjkNoColl << std::endl;
+  std::cerr << "Total / average time gjk: " << totalTimeGjkNoColl << ", " << FCL_REAL(totalTimeGjkNoColl) / FCL_REAL(CLOCKS_PER_SEC*(N-nCol)) << "s" << std::endl;
 }
diff --git a/test/test_fcl_math.cpp b/test/math.cpp
similarity index 94%
rename from test/test_fcl_math.cpp
rename to test/math.cpp
index a82721b1f5a2e5d3579ee2e86ed5c398d66a02d1..61a1717aaa78d7e472c5bf487fdc3a48c4419c23 100644
--- a/test/test_fcl_math.cpp
+++ b/test/math.cpp
@@ -39,19 +39,15 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/utility/binary.hpp>
 
-#include <hpp/fcl/math/vec_3f.h>
-#include <hpp/fcl/math/matrix_3f.h>
+#include <hpp/fcl/data_types.h>
 #include <hpp/fcl/math/transform.h>
 
-#include <hpp/fcl/intersect.h>
+#include <hpp/fcl/internal/intersect.h>
+#include <hpp/fcl/internal/tools.h>
 
 using namespace hpp::fcl;
 
-template<typename Derived>
-inline Quaternion3f fromAxisAngle(const Eigen::MatrixBase<Derived>& axis, FCL_REAL angle)
-{
-  return Quaternion3f (Eigen::AngleAxis<double>(angle, axis));
-}
+
 
 BOOST_AUTO_TEST_CASE(vec_test_eigen_vec64)
 {
diff --git a/test/obb.cpp b/test/obb.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb4bd9a59cb40a5c9d4489a41c6ef0930f437b56
--- /dev/null
+++ b/test/obb.cpp
@@ -0,0 +1,1376 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2014-2016, CNRS-LAAS
+ *  Author: Florent Lamiraux
+ *  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 CNRS 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.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#define BOOST_CHRONO_VERSION 2
+#include <boost/chrono/chrono.hpp>
+#include <boost/chrono/chrono_io.hpp>
+
+#include <hpp/fcl/narrowphase/narrowphase.h>
+
+#include "../src/BV/OBB.h"
+#include "../src/distance_func_matrix.h"
+
+using namespace hpp::fcl;
+
+int getNumCPUs()
+{
+  int NumCPUs = 0;
+  int MaxID = -1;
+  std::ifstream f("/proc/cpuinfo");
+  if (!f.is_open()) {
+    std::cerr << "failed to open /proc/cpuinfo\n";
+    return -1;
+  }
+  const std::string Key = "processor";
+  std::string ln;
+  while (std::getline(f, ln)) {
+    if (ln.empty()) continue;
+    size_t SplitIdx = ln.find(':');
+    std::string value;
+    if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
+    if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) {
+      NumCPUs++;
+      if (!value.empty()) {
+        int CurID = (int) strtol(value.c_str(), NULL, 10);
+        MaxID = std::max(CurID, MaxID);
+      }
+    }
+  }
+  if (f.bad()) {
+    std::cerr << "Failure reading /proc/cpuinfo\n";
+    return -1;
+  }
+  if (!f.eof()) {
+    std::cerr << "Failed to read to end of /proc/cpuinfo\n";
+    return -1;
+  }
+  f.close();
+
+  if ((MaxID + 1) != NumCPUs) {
+    fprintf(stderr,
+            "CPU ID assignments in /proc/cpuinfo seem messed up."
+            " This is usually caused by a bad BIOS.\n");
+  }
+  return NumCPUs;
+}
+
+bool checkCpuScalingEnabled()
+{
+  int num_cpus = getNumCPUs ();
+
+  // We don't have a valid CPU count, so don't even bother.
+  if (num_cpus <= 0) return false;
+  // On Linux, the CPUfreq subsystem exposes CPU information as files on the
+  // local file system. If reading the exported files fails, then we may not be
+  // running on Linux, so we silently ignore all the read errors.
+  std::string res;
+  for (int cpu = 0; cpu < num_cpus; ++cpu) {
+    std::ostringstream oss;
+    oss << "/sys/devices/system/cpu/cpu" << cpu << "/cpufreq/scaling_governor";
+    std::string governor_file = oss.str();
+    std::ifstream f(governor_file.c_str());
+    if (!f.is_open()) return false;
+    f >> res;
+    if (!f.good()) return false;
+    if (res != "performance") return true;
+  }
+  return false;
+}
+
+void randomOBBs (
+    Vec3f& a, Vec3f& b, FCL_REAL extentNorm)
+{
+  // Extent norm is between 0 and extentNorm on each axis
+  //a = (Vec3f::Ones()+Vec3f::Random()) * extentNorm / (2*sqrt(3));
+  //b = (Vec3f::Ones()+Vec3f::Random()) * extentNorm / (2*sqrt(3));
+
+  a = extentNorm * Vec3f::Random().cwiseAbs().normalized();
+  b = extentNorm * Vec3f::Random().cwiseAbs().normalized();
+}
+
+void randomTransform (
+    Matrix3f& B, Vec3f& T,
+    const Vec3f& a, const Vec3f& b, const FCL_REAL extentNorm)
+{
+  // TODO Should we scale T to a and b norm ?
+  (void) a;
+  (void) b;
+  (void) extentNorm;
+
+  FCL_REAL N = a.norm() + b.norm();
+  // A translation of norm N ensures there is no collision.
+  // Set translation to be between 0 and 2 * N;
+  T = ( Vec3f::Random() / sqrt(3) ) * 1.5 * N;
+  //T.setZero();
+
+  Quaternion3f q;
+  q.coeffs().setRandom();
+  q.normalize();
+  B = q;
+}
+
+#define NB_METHODS 7
+#define MANUAL_PRODUCT 1
+
+#if MANUAL_PRODUCT
+# define PRODUCT(M33,v3) ( M33.col(0) * v3[0] + M33.col(1) * v3[1] + M33.col(2) * v3[2] )
+#else
+# define PRODUCT(M33,v3) (M33*v3)
+#endif
+
+typedef boost::chrono::high_resolution_clock clock_type;
+typedef clock_type::duration duration_type;
+
+const char* sep = ",\t"; 
+const FCL_REAL eps = 1e-10;
+
+const Eigen::IOFormat py_fmt(Eigen::FullPrecision,
+    0,
+    ", ",       // Coeff separator
+    ",\n",      // Row separator
+    "(",        // row prefix
+    ",)",       // row suffix
+    "( ",       // mat prefix
+    ", )"       // mat suffix
+    );
+
+namespace obbDisjoint_impls
+{
+  /// @return true if OBB are disjoint.
+  bool distance (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, FCL_REAL& distance)
+  {
+    GJKSolver gjk;
+    Box ba (2*a), bb (2*b);
+    Transform3f tfa, tfb (B, T);
+
+    Vec3f p1, p2, normal;
+    return gjk.shapeDistance (ba, tfa, bb, tfb, distance, p1, p2, normal);
+  }
+
+  inline FCL_REAL _computeDistanceForCase1 (
+      const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf)
+  {
+    Vec3f AABB_corner;
+     /* This seems to be slower
+    AABB_corner.noalias() = T.cwiseAbs () - a;
+    AABB_corner.noalias() -= PRODUCT(Bf,b);
+    /*/
+#if MANUAL_PRODUCT
+    AABB_corner.noalias() = T.cwiseAbs () - a;
+    AABB_corner.noalias() -= Bf.col(0) * b[0];
+    AABB_corner.noalias() -= Bf.col(1) * b[1];
+    AABB_corner.noalias() -= Bf.col(2) * b[2];
+#else
+    AABB_corner.noalias() = T.cwiseAbs () - Bf * b - a;
+#endif
+    // */
+    return AABB_corner.array().max(0).matrix().squaredNorm ();
+  }
+
+  inline FCL_REAL _computeDistanceForCase2 (
+      const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf)
+  {
+    /*
+    Vec3f AABB_corner(PRODUCT(B.transpose(), T).cwiseAbs() - b);
+    AABB_corner.noalias() -= PRODUCT(Bf.transpose(), a);
+    return AABB_corner.array().max(0).matrix().squaredNorm ();
+    /*/
+#if MANUAL_PRODUCT
+    register FCL_REAL s, t = 0;
+    s = std::abs(B.col(0).dot(T)) - Bf.col(0).dot(a) - b[0];
+    if (s > 0) t += s*s;
+    s = std::abs(B.col(1).dot(T)) - Bf.col(1).dot(a) - b[1];
+    if (s > 0) t += s*s;
+    s = std::abs(B.col(2).dot(T)) - Bf.col(2).dot(a) - b[2];
+    if (s > 0) t += s*s;
+    return t;
+#else
+    Vec3f AABB_corner((B.transpose () * T).cwiseAbs ()  - Bf.transpose () * a - b);
+    return AABB_corner.array().max(0).matrix().squaredNorm ();
+#endif
+    // */
+  }
+
+  int separatingAxisId (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    int id = 0;
+
+    Matrix3f Bf (B.cwiseAbs());
+
+    // Corner of b axis aligned bounding box the closest to the origin
+    squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return id;
+    ++id;
+
+    // | B^T T| - b - Bf^T a
+    squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return id;
+    ++id;
+
+    int ja = 1, ka = 2, jb = 1, kb = 2;
+    for (int ia = 0; ia < 3; ++ia) {
+      for (int ib = 0; ib < 3; ++ib) {
+        const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
+
+        const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
+            b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
+        // We need to divide by the norm || Aia x Bib ||
+        // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
+        if (diff > 0) {
+          FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+          if (sinus2 > 1e-6) {
+            squaredLowerBoundDistance = diff * diff / sinus2;
+            if (squaredLowerBoundDistance > breakDistance2) {
+              return id;
+            }
+          }
+          /* // or
+             FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+             squaredLowerBoundDistance = diff * diff;
+             if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
+             squaredLowerBoundDistance /= sinus2;
+             return true;
+             }
+          // */
+        }
+        ++id;
+
+        jb = kb; kb = ib;
+      }
+      ja = ka; ka = ia;
+    }
+
+    return id;
+  }
+
+  // ------------------------ 0 --------------------------------------
+  bool withRuntimeLoop (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    Matrix3f Bf (B.cwiseAbs());
+
+    // Corner of b axis aligned bounding box the closest to the origin
+    squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    // | B^T T| - b - Bf^T a
+    squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    int ja = 1, ka = 2, jb = 1, kb = 2;
+    for (int ia = 0; ia < 3; ++ia) {
+      for (int ib = 0; ib < 3; ++ib) {
+        const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
+
+        const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
+            b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
+        // We need to divide by the norm || Aia x Bib ||
+        // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
+        if (diff > 0) {
+          FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+          if (sinus2 > 1e-6) {
+            squaredLowerBoundDistance = diff * diff / sinus2;
+            if (squaredLowerBoundDistance > breakDistance2) {
+              return true;
+            }
+          }
+          /* // or
+             FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+             squaredLowerBoundDistance = diff * diff;
+             if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
+             squaredLowerBoundDistance /= sinus2;
+             return true;
+             }
+          // */
+        }
+
+        jb = kb; kb = ib;
+      }
+      ja = ka; ka = ia;
+    }
+
+    return false;
+
+  }
+
+  // ------------------------ 1 --------------------------------------
+  bool withManualLoopUnrolling_1 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    FCL_REAL t, s;
+    FCL_REAL diff;
+
+    // Matrix3f Bf = abs(B);
+    // Bf += reps;
+    Matrix3f Bf (B.cwiseAbs());
+
+    // Corner of b axis aligned bounding box the closest to the origin
+    Vec3f AABB_corner (T.cwiseAbs () - Bf * b);
+    Vec3f diff3 (AABB_corner - a);
+    diff3 = diff3.cwiseMax (Vec3f::Zero());
+
+    //for (Vec3f::Index i=0; i<3; ++i) diff3 [i] = std::max (0, diff3 [i]);
+    squaredLowerBoundDistance = diff3.squaredNorm ();
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    AABB_corner = (B.transpose () * T).cwiseAbs ()  - Bf.transpose () * a;
+    // diff3 = | B^T T| - b - Bf^T a
+    diff3 = AABB_corner - b;
+    diff3 = diff3.cwiseMax (Vec3f::Zero());
+    squaredLowerBoundDistance = diff3.squaredNorm ();
+
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    // A0 x B0
+    s = T[2] * B(1, 0) - T[1] * B(2, 0);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    FCL_REAL sinus2;
+    diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) +
+        b[1] * Bf(0, 2) + b[2] * Bf(0, 1));
+    // We need to divide by the norm || A0 x B0 ||
+    // As ||A0|| = ||B0|| = 1,
+    //              2            2
+    // || A0 x B0 ||  + (A0 | B0)  = 1
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,0) * Bf (0,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A0 x B1
+    s = T[2] * B(1, 1) - T[1] * B(2, 1);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) +
+        b[0] * Bf(0, 2) + b[2] * Bf(0, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,1) * Bf (0,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A0 x B2
+    s = T[2] * B(1, 2) - T[1] * B(2, 2);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) +
+        b[0] * Bf(0, 1) + b[1] * Bf(0, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,2) * Bf (0,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B0
+    s = T[0] * B(2, 0) - T[2] * B(0, 0);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) +
+        b[1] * Bf(1, 2) + b[2] * Bf(1, 1));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,0) * Bf (1,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B1
+    s = T[0] * B(2, 1) - T[2] * B(0, 1);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) +
+        b[0] * Bf(1, 2) + b[2] * Bf(1, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,1) * Bf (1,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B2
+    s = T[0] * B(2, 2) - T[2] * B(0, 2);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) +
+        b[0] * Bf(1, 1) + b[1] * Bf(1, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,2) * Bf (1,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B0
+    s = T[1] * B(0, 0) - T[0] * B(1, 0);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) +
+        b[1] * Bf(2, 2) + b[2] * Bf(2, 1));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,0) * Bf (2,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B1
+    s = T[1] * B(0, 1) - T[0] * B(1, 1);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) +
+        b[0] * Bf(2, 2) + b[2] * Bf(2, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,1) * Bf (2,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B2
+    s = T[1] * B(0, 2) - T[0] * B(1, 2);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) +
+        b[0] * Bf(2, 1) + b[1] * Bf(2, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,2) * Bf (2,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    return false;
+
+  }
+
+  // ------------------------ 2 --------------------------------------
+  bool withManualLoopUnrolling_2 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    Matrix3f Bf (B.cwiseAbs());
+
+    // Corner of b axis aligned bounding box the closest to the origin
+    squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    // A0 x B0
+    FCL_REAL t, s;
+    s = T[2] * B(1, 0) - T[1] * B(2, 0);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    FCL_REAL sinus2;
+    FCL_REAL diff;
+    diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) +
+        b[1] * Bf(0, 2) + b[2] * Bf(0, 1));
+    // We need to divide by the norm || A0 x B0 ||
+    // As ||A0|| = ||B0|| = 1,
+    //              2            2
+    // || A0 x B0 ||  + (A0 | B0)  = 1
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,0) * Bf (0,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A0 x B1
+    s = T[2] * B(1, 1) - T[1] * B(2, 1);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) +
+        b[0] * Bf(0, 2) + b[2] * Bf(0, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,1) * Bf (0,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A0 x B2
+    s = T[2] * B(1, 2) - T[1] * B(2, 2);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) +
+        b[0] * Bf(0, 1) + b[1] * Bf(0, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,2) * Bf (0,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B0
+    s = T[0] * B(2, 0) - T[2] * B(0, 0);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) +
+        b[1] * Bf(1, 2) + b[2] * Bf(1, 1));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,0) * Bf (1,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B1
+    s = T[0] * B(2, 1) - T[2] * B(0, 1);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) +
+        b[0] * Bf(1, 2) + b[2] * Bf(1, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,1) * Bf (1,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B2
+    s = T[0] * B(2, 2) - T[2] * B(0, 2);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) +
+        b[0] * Bf(1, 1) + b[1] * Bf(1, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,2) * Bf (1,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B0
+    s = T[1] * B(0, 0) - T[0] * B(1, 0);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) +
+        b[1] * Bf(2, 2) + b[2] * Bf(2, 1));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,0) * Bf (2,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B1
+    s = T[1] * B(0, 1) - T[0] * B(1, 1);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) +
+        b[0] * Bf(2, 2) + b[2] * Bf(2, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,1) * Bf (2,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B2
+    s = T[1] * B(0, 2) - T[0] * B(1, 2);
+    t = ((s < 0.0) ? -s : s); assert (t == fabs (s));
+
+    diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) +
+        b[0] * Bf(2, 1) + b[1] * Bf(2, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,2) * Bf (2,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    return false;
+
+  }
+
+  // ------------------------ 3 --------------------------------------
+  template <int ia, int ib,
+    int ja = (ia+1)%3, int ka = (ia+2)%3,
+    int jb = (ib+1)%3, int kb = (ib+2)%3 >
+  struct loop_case_1 {
+    static inline bool run (
+        const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b,
+        const Matrix3f& Bf,
+        const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+    {
+      const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
+
+      const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
+                                       b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
+      // We need to divide by the norm || Aia x Bib ||
+      // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
+      if (diff > 0) {
+        FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+        if (sinus2 > 1e-6) {
+          squaredLowerBoundDistance = diff * diff / sinus2;
+          if (squaredLowerBoundDistance > breakDistance2) {
+            return true;
+          }
+        }
+        /* // or
+           FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+           squaredLowerBoundDistance = diff * diff;
+           if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
+           squaredLowerBoundDistance /= sinus2;
+           return true;
+           }
+        // */
+      }
+      return false;
+    }
+  };
+
+  bool withTemplateLoopUnrolling_1 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    Matrix3f Bf (B.cwiseAbs());
+
+    // Corner of b axis aligned bounding box the closest to the origin
+    squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    // Ai x Bj
+    if (loop_case_1<0,0>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<0,1>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<0,2>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<1,0>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<1,1>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<1,2>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<2,0>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<2,1>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+    if (loop_case_1<2,2>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+
+    return false;
+  }
+
+  // ------------------------ 4 --------------------------------------
+
+  template <int ib, int jb = (ib+1)%3, int kb = (ib+2)%3 >
+  struct loop_case_2 
+  {
+    static inline bool run (int ia, int ja, int ka,
+        const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b,
+        const Matrix3f& Bf,
+        const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+    {
+      const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
+
+      const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
+                                       b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
+      // We need to divide by the norm || Aia x Bib ||
+      // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
+      if (diff > 0) {
+        FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+        if (sinus2 > 1e-6) {
+          squaredLowerBoundDistance = diff * diff / sinus2;
+          if (squaredLowerBoundDistance > breakDistance2) {
+            return true;
+          }
+        }
+        /* // or
+           FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
+           squaredLowerBoundDistance = diff * diff;
+           if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
+           squaredLowerBoundDistance /= sinus2;
+           return true;
+           }
+        // */
+      }
+      return false;
+    }
+  };
+
+  bool withPartialTemplateLoopUnrolling_1 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    Matrix3f Bf (B.cwiseAbs());
+
+    // Corner of b axis aligned bounding box the closest to the origin
+    squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf);
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    // Ai x Bj
+    int ja = 1, ka = 2;
+    for (int ia = 0; ia < 3; ++ia) {
+      if (loop_case_2<0>::run (ia, ja, ka,
+            B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+      if (loop_case_2<1>::run (ia, ja, ka,
+            B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+      if (loop_case_2<2>::run (ia, ja, ka,
+            B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true;
+      ja = ka; ka = ia;
+    }
+
+    return false;
+  }
+
+  // ------------------------ 5 --------------------------------------
+  bool originalWithLowerBound (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance)
+  {
+    register FCL_REAL t, s;
+    FCL_REAL diff;
+
+    Matrix3f Bf (B.cwiseAbs());
+    squaredLowerBoundDistance = 0;
+
+    // if any of these tests are one-sided, then the polyhedra are disjoint
+
+    // A1 x A2 = A0
+    t = ((T[0] < 0.0) ? -T[0] : T[0]);
+
+    diff = t - (a[0] + Bf.row(0).dot(b));
+    if (diff > 0) {
+      squaredLowerBoundDistance = diff*diff;
+    }
+
+    // A2 x A0 = A1
+    t = ((T[1] < 0.0) ? -T[1] : T[1]);
+
+    diff = t - (a[1] + Bf.row(1).dot(b));
+    if (diff > 0) {
+      squaredLowerBoundDistance += diff*diff;
+    }
+
+    // A0 x A1 = A2
+    t =((T[2] < 0.0) ? -T[2] : T[2]);
+
+    diff = t - (a[2] + Bf.row(2).dot(b));
+    if (diff > 0) {
+      squaredLowerBoundDistance += diff*diff;
+    }
+
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    squaredLowerBoundDistance = 0;
+
+    // B1 x B2 = B0
+    s =  B.col(0).dot(T);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (b[0] + Bf.col(0).dot(a));
+    if (diff > 0) {
+      squaredLowerBoundDistance += diff*diff;
+    }
+
+    // B2 x B0 = B1
+    s = B.col(1).dot(T);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (b[1] + Bf.col(1).dot(a));
+    if (diff > 0) {
+      squaredLowerBoundDistance += diff*diff;
+    }
+
+    // B0 x B1 = B2
+    s = B.col(2).dot(T);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (b[2] + Bf.col(2).dot(a));
+    if (diff > 0) {
+      squaredLowerBoundDistance += diff*diff;
+    }
+
+    if (squaredLowerBoundDistance > breakDistance2)
+      return true;
+
+    // A0 x B0
+    s = T[2] * B(1, 0) - T[1] * B(2, 0);
+    t = ((s < 0.0) ? -s : s);
+
+    FCL_REAL sinus2;
+    diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) +
+        b[1] * Bf(0, 2) + b[2] * Bf(0, 1));
+    // We need to divide by the norm || A0 x B0 ||
+    // As ||A0|| = ||B0|| = 1,
+    //              2            2
+    // || A0 x B0 ||  + (A0 | B0)  = 1
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,0) * Bf (0,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A0 x B1
+    s = T[2] * B(1, 1) - T[1] * B(2, 1);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) +
+        b[0] * Bf(0, 2) + b[2] * Bf(0, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,1) * Bf (0,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A0 x B2
+    s = T[2] * B(1, 2) - T[1] * B(2, 2);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) +
+        b[0] * Bf(0, 1) + b[1] * Bf(0, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (0,2) * Bf (0,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B0
+    s = T[0] * B(2, 0) - T[2] * B(0, 0);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) +
+        b[1] * Bf(1, 2) + b[2] * Bf(1, 1));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,0) * Bf (1,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B1
+    s = T[0] * B(2, 1) - T[2] * B(0, 1);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) +
+        b[0] * Bf(1, 2) + b[2] * Bf(1, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,1) * Bf (1,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A1 x B2
+    s = T[0] * B(2, 2) - T[2] * B(0, 2);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) +
+        b[0] * Bf(1, 1) + b[1] * Bf(1, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (1,2) * Bf (1,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B0
+    s = T[1] * B(0, 0) - T[0] * B(1, 0);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) +
+        b[1] * Bf(2, 2) + b[2] * Bf(2, 1));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,0) * Bf (2,0);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B1
+    s = T[1] * B(0, 1) - T[0] * B(1, 1);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) +
+        b[0] * Bf(2, 2) + b[2] * Bf(2, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,1) * Bf (2,1);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    // A2 x B2
+    s = T[1] * B(0, 2) - T[0] * B(1, 2);
+    t = ((s < 0.0) ? -s : s);
+
+    diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) +
+        b[0] * Bf(2, 1) + b[1] * Bf(2, 0));
+    if (diff > 0) {
+      sinus2 = 1 - Bf (2,2) * Bf (2,2);
+      if (sinus2 > 1e-6) {
+        squaredLowerBoundDistance = diff * diff / sinus2;
+        if (squaredLowerBoundDistance > breakDistance2) {
+          return true;
+        }
+      }
+    }
+
+    return false;
+
+  }
+
+  // ------------------------ 6 --------------------------------------
+  bool originalWithNoLowerBound (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& , FCL_REAL& squaredLowerBoundDistance)
+  {
+    register FCL_REAL t, s;
+    const FCL_REAL reps = 1e-6;
+
+    squaredLowerBoundDistance = 0;
+
+    Matrix3f Bf (B.array().abs() + reps);
+    // Bf += reps;
+
+    // if any of these tests are one-sided, then the polyhedra are disjoint
+
+    // A1 x A2 = A0
+    t = ((T[0] < 0.0) ? -T[0] : T[0]);
+
+    // if(t > (a[0] + Bf.dotX(b)))
+    if(t > (a[0] + Bf.row(0).dot(b)))
+      return true;
+
+    // B1 x B2 = B0
+    // s =  B.transposeDotX(T);
+    s =  B.col(0).dot(T);
+    t = ((s < 0.0) ? -s : s);
+
+    // if(t > (b[0] + Bf.transposeDotX(a)))
+    if(t > (b[0] + Bf.col(0).dot(a)))
+      return true;
+
+    // A2 x A0 = A1
+    t = ((T[1] < 0.0) ? -T[1] : T[1]);
+
+    // if(t > (a[1] + Bf.dotY(b)))
+    if(t > (a[1] + Bf.row(1).dot(b)))
+      return true;
+
+    // A0 x A1 = A2
+    t =((T[2] < 0.0) ? -T[2] : T[2]);
+
+    // if(t > (a[2] + Bf.dotZ(b)))
+    if(t > (a[2] + Bf.row(2).dot(b)))
+      return true;
+
+    // B2 x B0 = B1
+    // s = B.transposeDotY(T);
+    s = B.col(1).dot(T);
+    t = ((s < 0.0) ? -s : s);
+
+    // if(t > (b[1] + Bf.transposeDotY(a)))
+    if(t > (b[1] + Bf.col(1).dot(a)))
+      return true;
+
+    // B0 x B1 = B2
+    // s = B.transposeDotZ(T);
+    s = B.col(2).dot(T);
+    t = ((s < 0.0) ? -s : s);
+
+    // if(t > (b[2] + Bf.transposeDotZ(a)))
+    if(t > (b[2] + Bf.col(2).dot(a)))
+      return true;
+
+    // A0 x B0
+    s = T[2] * B(1, 0) - T[1] * B(2, 0);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) +
+          b[1] * Bf(0, 2) + b[2] * Bf(0, 1)))
+      return true;
+
+    // A0 x B1
+    s = T[2] * B(1, 1) - T[1] * B(2, 1);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) +
+          b[0] * Bf(0, 2) + b[2] * Bf(0, 0)))
+      return true;
+
+    // A0 x B2
+    s = T[2] * B(1, 2) - T[1] * B(2, 2);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) +
+          b[0] * Bf(0, 1) + b[1] * Bf(0, 0)))
+      return true;
+
+    // A1 x B0
+    s = T[0] * B(2, 0) - T[2] * B(0, 0);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) +
+          b[1] * Bf(1, 2) + b[2] * Bf(1, 1)))
+      return true;
+
+    // A1 x B1
+    s = T[0] * B(2, 1) - T[2] * B(0, 1);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) +
+          b[0] * Bf(1, 2) + b[2] * Bf(1, 0)))
+      return true;
+
+    // A1 x B2
+    s = T[0] * B(2, 2) - T[2] * B(0, 2);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) +
+          b[0] * Bf(1, 1) + b[1] * Bf(1, 0)))
+      return true;
+
+    // A2 x B0
+    s = T[1] * B(0, 0) - T[0] * B(1, 0);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) +
+          b[1] * Bf(2, 2) + b[2] * Bf(2, 1)))
+      return true;
+
+    // A2 x B1
+    s = T[1] * B(0, 1) - T[0] * B(1, 1);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) +
+          b[0] * Bf(2, 2) + b[2] * Bf(2, 0)))
+      return true;
+
+    // A2 x B2
+    s = T[1] * B(0, 2) - T[0] * B(1, 2);
+    t = ((s < 0.0) ? -s : s);
+
+    if(t > (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) +
+          b[0] * Bf(2, 1) + b[1] * Bf(2, 0)))
+      return true;
+
+    return false;
+
+  }
+}
+
+struct BenchmarkResult
+{
+  /// The test ID:
+  /// - 0-10 identifies a separating axes.
+  /// - 11 means no separatins axes could be found. (distance should be <= 0)
+  int ifId;
+  FCL_REAL distance;
+  FCL_REAL squaredLowerBoundDistance;
+  duration_type duration[NB_METHODS];
+  bool failure;
+
+  static std::ostream& headers (std::ostream& os)
+  {
+    duration_type dummy (1);
+    std::string unit = " (" + boost::chrono::duration_units_default<>().get_unit (boost::chrono::duration_style::symbol, dummy) + ")";
+    os << boost::chrono::symbol_format
+      << "separating axis"
+      << sep << "distance lower bound"
+      << sep << "distance"
+      << sep << "failure"
+      << sep << "Runtime Loop" << unit
+      << sep << "Manual Loop Unrolling 1" << unit
+      << sep << "Manual Loop Unrolling 2" << unit
+      << sep << "Template Unrolling" << unit
+      << sep << "Partial Template Unrolling" << unit
+      << sep << "Original (LowerBound)" << unit
+      << sep << "Original (NoLowerBound)" << unit
+      ;
+    return os;
+  }
+
+  std::ostream& print (std::ostream& os) const
+  {
+    os << ifId
+      << sep << std::sqrt(squaredLowerBoundDistance)
+      << sep << distance
+      << sep << failure;
+    for (int i = 0; i < NB_METHODS; ++i) os << sep << duration[i].count();
+    return os;
+  }
+};
+
+std::ostream& operator<< (std::ostream& os, const BenchmarkResult& br)
+{
+  return br.print (os);
+}
+
+BenchmarkResult benchmark_obb_case (
+    const Matrix3f& B, const Vec3f& T,
+    const Vec3f& a, const Vec3f& b,
+    const CollisionRequest& request,
+    std::size_t N)
+{
+  const FCL_REAL breakDistance (request.break_distance + request.security_margin);
+  const FCL_REAL breakDistance2 = breakDistance * breakDistance;
+
+  BenchmarkResult result;
+  // First determine which axis provide the answer
+  result.ifId = obbDisjoint_impls::separatingAxisId (B, T, a, b, breakDistance2,
+      result.squaredLowerBoundDistance);
+  bool disjoint = obbDisjoint_impls::distance (B, T, a, b, result.distance);
+  assert (0 <= result.ifId && result.ifId <= 11);
+
+  // Sanity check
+  result.failure = true;
+  bool overlap = (result.ifId == 11); 
+  FCL_REAL dist_thr = request.break_distance + request.security_margin;
+  if (       !overlap && result.distance <= 0) {
+    std::cerr << "Failure: negative distance for disjoint OBBs.";
+  } else if (!overlap && result.squaredLowerBoundDistance < 0) {
+    std::cerr << "Failure: negative distance lower bound.";
+  } else if (!overlap && eps < std::sqrt (result.squaredLowerBoundDistance) - result.distance) {
+    std::cerr << "Failure: distance is inferior to its lower bound (diff = " << 
+      std::sqrt (result.squaredLowerBoundDistance) - result.distance << ").";
+  } else if (overlap != !disjoint && result.distance >= dist_thr - eps) {
+    std::cerr << "Failure: overlapping test and distance query mismatch.";
+  } else if (overlap              && result.distance >= dist_thr - eps) {
+    std::cerr << "Failure: positive distance for overlapping OBBs.";
+  } else {
+    result.failure = false;
+  }
+  if (result.failure) {
+    std::cerr
+      << "\nR = " << Quaternion3f(B).coeffs().transpose().format (py_fmt)
+      << "\nT = " << T.transpose().format (py_fmt)
+      << "\na = " << a.transpose().format (py_fmt)
+      << "\nb = " << b.transpose().format (py_fmt)
+      << "\nresult = " << result
+      << '\n' << std::endl;
+  }
+
+  // Compute time
+  FCL_REAL tmp;
+  clock_type::time_point start, end;
+
+  // ------------------------ 0 --------------------------------------
+  start = clock_type::now();
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::withRuntimeLoop (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[0] = (end - start) / N;
+
+  // ------------------------ 1 --------------------------------------
+  start = clock_type::now();
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::withManualLoopUnrolling_1 (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[1] = (end - start) / N;
+
+  // ------------------------ 2 --------------------------------------
+  start = clock_type::now();
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::withManualLoopUnrolling_2 (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[2] = (end - start) / N;
+
+  // ------------------------ 3 --------------------------------------
+  start = clock_type::now();
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::withTemplateLoopUnrolling_1 (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[3] = (end - start) / N;
+
+  // ------------------------ 4 --------------------------------------
+  start = clock_type::now();
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::withPartialTemplateLoopUnrolling_1 (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[4] = (end - start) / N;
+
+  // ------------------------ 5 --------------------------------------
+  start = clock_type::now();
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::originalWithLowerBound (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[5] = (end - start) / N;
+
+  // ------------------------ 6 --------------------------------------
+  start = clock_type::now();
+  // The 2 last arguments are unused.
+  for (std::size_t i = 0; i < N; ++i)
+    obbDisjoint_impls::originalWithNoLowerBound (B, T, a, b, breakDistance2, tmp);
+  end = clock_type::now();
+  result.duration[6] = (end - start) / N;
+
+  return result;
+}
+
+std::size_t obb_overlap_and_lower_bound_distance(std::ostream* output)
+{
+  std::size_t nbFailure = 0;
+
+  // Create two OBBs axis
+  Vec3f a, b;
+  Matrix3f B;
+  Vec3f T;
+  CollisionRequest request;
+
+  static const size_t nbRandomOBB       = 100;
+  static const size_t nbTransformPerOBB = 100;
+  static const size_t nbRunForTimeMeas  = 1000;
+  static const FCL_REAL extentNorm = 1.;
+
+  if (output != NULL) *output << BenchmarkResult::headers << '\n';
+  
+  BenchmarkResult result;
+  for (std::size_t iobb = 0; iobb < nbRandomOBB; ++iobb) {
+    randomOBBs (a, b, extentNorm);
+    for (std::size_t itf = 0; itf < nbTransformPerOBB; ++itf) {
+      randomTransform (B, T, a, b, extentNorm);
+      result = benchmark_obb_case (B, T, a, b, request, nbRunForTimeMeas);
+      if (output != NULL) *output << result << '\n';
+      if (result.failure) nbFailure++;
+    }
+  }
+  return nbFailure;
+}
+
+int main (int argc, char** argv)
+{
+  std::ostream* output = NULL;
+  if (argc > 1 && strcmp(argv[1], "--generate-output") == 0)
+  {
+    output = &std::cout;
+  }
+
+  bool cpuScalingEnabled = checkCpuScalingEnabled();
+  if (cpuScalingEnabled)
+    std::cerr <<
+      "CPU scaling is enabled."
+      "\n\tThe benchmark real time measurements may be noisy and will incur extra overhead."
+      "\n\tUse the following commands to turn on and off."
+      "\n\t\tsudo cpufreq-set --governor performance"
+      "\n\t\tsudo cpufreq-set --governor powersave"
+      "\n"
+      ;
+
+  std::size_t nbFailure = obb_overlap_and_lower_bound_distance(output);
+  if (nbFailure > INT_MAX) return INT_MAX;
+  return (int)nbFailure;
+}
diff --git a/test/test_fcl_octree.cpp b/test/octree.cpp
similarity index 98%
rename from test/test_fcl_octree.cpp
rename to test/octree.cpp
index 40951efe67872bcf486440898a3242d554e4015e..5632a496190508769b5f5e174002d88299966b9c 100644
--- a/test/test_fcl_octree.cpp
+++ b/test/octree.cpp
@@ -38,14 +38,16 @@
 #define BOOST_TEST_DYN_LINK
 #include <fstream>
 #include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
 
 #include <hpp/fcl/BVH/BVH_model.h>
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/distance.h>
 #include <hpp/fcl/shape/geometric_shapes.h>
-#include "test_fcl_utility.h"
+#include <hpp/fcl/internal/BV_splitter.h>
+
+#include "utility.h"
 #include "fcl_resources/config.h"
-#include <boost/filesystem.hpp>
 
 using hpp::fcl::Vec3f;
 using hpp::fcl::Triangle;
diff --git a/test/test_fcl_profiling.cpp b/test/profiling.cpp
similarity index 97%
rename from test/test_fcl_profiling.cpp
rename to test/profiling.cpp
index f62e49bf5757fc02dc9efa94362e0bd7f0adfe8f..2e96e4c82abe0ece23c4d3c4398b91c708441db2 100644
--- a/test/test_fcl_profiling.cpp
+++ b/test/profiling.cpp
@@ -26,12 +26,12 @@
 #include <hpp/fcl/collision_func_matrix.h>
 #include <hpp/fcl/narrowphase/narrowphase.h>
 #include <hpp/fcl/mesh_loader/assimp.h>
-#include "test_fcl_utility.h"
+#include "utility.h"
 #include "fcl_resources/config.h"
 
 using namespace hpp::fcl;
 
-CollisionFunctionMatrix<GJKSolver_indep> lookupTable;
+CollisionFunctionMatrix lookupTable;
 bool supportedPair(const CollisionGeometry* o1, const CollisionGeometry* o2)
 {
   OBJECT_TYPE object_type1 = o1->getObjectType();
@@ -253,8 +253,8 @@ int main(int argc, char** argv)
     geoms.push_back(Geometry ("Capsule"   , new Capsule   (2, 1)                                          ));
     geoms.push_back(Geometry ("Cone"      , new Cone      (2, 1)                                          ));
     geoms.push_back(Geometry ("Cylinder"  , new Cylinder  (2, 1)                                          ));
-    geoms.push_back(Geometry ("Plane"     , new Plane     (Vec3f(1,1,1).normalized(), 0)                  ));
-    geoms.push_back(Geometry ("Halfspace" , new Halfspace (Vec3f(1,1,1).normalized(), 0)                  ));
+    //geoms.push_back(Geometry ("Plane"     , new Plane     (Vec3f(1,1,1).normalized(), 0)                  ));
+    //geoms.push_back(Geometry ("Halfspace" , new Halfspace (Vec3f(1,1,1).normalized(), 0)                  ));
     // not implemented // geoms.push_back(Geometry ("TriangleP" , new TriangleP (Vec3f(0,1,0), Vec3f(0,0,1), Vec3f(-1,0,0))     ));
 
     geoms.push_back(Geometry ("rob BVHModel<OBB>"   , objToGeom<OBB>   ((path / "rob.obj").string())));
diff --git a/test/python_unit/CMakeLists.txt b/test/python_unit/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6d62837aee6187fd6b7e0d3665b3090cc6e0efb2
--- /dev/null
+++ b/test/python_unit/CMakeLists.txt
@@ -0,0 +1,7 @@
+SET(${PROJECT_NAME}_PYTHON_TESTS
+  geometric_shapes
+  )
+
+FOREACH(TEST ${${PROJECT_NAME}_PYTHON_TESTS})
+  ADD_PYTHON_UNIT_TEST("py-${TEST}" "test/python_unit/${TEST}.py" "python")
+ENDFOREACH(TEST ${${PROJECT_NAME}_PYTHON_TESTS})
diff --git a/test/python_unit/geometric_shapes.py b/test/python_unit/geometric_shapes.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e9109e0f054535156ba27904ecd746accbe6a47
--- /dev/null
+++ b/test/python_unit/geometric_shapes.py
@@ -0,0 +1,80 @@
+import unittest
+import hppfcl
+hppfcl.switchToNumpyMatrix()
+import numpy as np
+
+class TestGeometricShapes(unittest.TestCase):
+
+    def test_capsule(self):
+        capsule = hppfcl.Capsule(1.,2.)
+        self.assertIsInstance(capsule, hppfcl.Capsule)
+        self.assertIsInstance(capsule, hppfcl.ShapeBase)
+        self.assertIsInstance(capsule, hppfcl.CollisionGeometry)
+        self.assertEqual(capsule.getNodeType(), hppfcl.NODE_TYPE.GEOM_CAPSULE)
+        self.assertEqual(capsule.radius,1.)
+        self.assertEqual(capsule.halfLength,1.)
+        capsule.radius = 3.
+        capsule.halfLength = 4.
+        self.assertEqual(capsule.radius,3.)
+        self.assertEqual(capsule.halfLength,4.)
+
+    def test_box1(self):
+        box = hppfcl.Box(np.matrix([1.,2.,3.]).T)
+        self.assertIsInstance(box, hppfcl.Box)
+        self.assertIsInstance(box, hppfcl.ShapeBase)
+        self.assertIsInstance(box, hppfcl.CollisionGeometry)
+        self.assertEqual(box.getNodeType(), hppfcl.NODE_TYPE.GEOM_BOX)
+        self.assertTrue(np.array_equal(box.halfSide,np.matrix([.5,1.,1.5]).T))
+        box.halfSide = np.matrix([4.,5.,6.]).T
+        self.assertTrue(np.array_equal(box.halfSide,np.matrix([4.,5.,6.]).T))
+
+    def test_box2(self):
+        box = hppfcl.Box(1.,2.,3)
+        self.assertIsInstance(box, hppfcl.Box)
+        self.assertIsInstance(box, hppfcl.ShapeBase)
+        self.assertIsInstance(box, hppfcl.CollisionGeometry)
+        self.assertEqual(box.getNodeType(), hppfcl.NODE_TYPE.GEOM_BOX)
+        self.assertEqual(box.halfSide[0],0.5)
+        self.assertEqual(box.halfSide[1],1.0)
+        self.assertEqual(box.halfSide[2],1.5)
+        box.halfSide[0] = 4.
+        box.halfSide[0] = 5.
+        box.halfSide[0] = 6.
+#         self.assertEqual(box.halfSide[0],4.)
+#         self.assertEqual(box.halfSide[1],5.)
+#         self.assertEqual(box.halfSide[2],6.)
+
+    def test_sphere(self):
+        sphere = hppfcl.Sphere(1.)
+        self.assertIsInstance(sphere, hppfcl.Sphere)
+        self.assertIsInstance(sphere, hppfcl.ShapeBase)
+        self.assertIsInstance(sphere, hppfcl.CollisionGeometry)
+        self.assertEqual(sphere.getNodeType(), hppfcl.NODE_TYPE.GEOM_SPHERE)
+        self.assertEqual(sphere.radius,1.)
+        sphere.radius = 2.
+        self.assertEqual(sphere.radius,2.)
+
+    def test_cylinder(self):
+        cylinder = hppfcl.Cylinder(1.,2.)
+        self.assertIsInstance(cylinder, hppfcl.Cylinder)
+        self.assertIsInstance(cylinder, hppfcl.ShapeBase)
+        self.assertIsInstance(cylinder, hppfcl.CollisionGeometry)
+        self.assertEqual(cylinder.getNodeType(), hppfcl.NODE_TYPE.GEOM_CYLINDER)
+        self.assertEqual(cylinder.radius,1.)
+        self.assertEqual(cylinder.halfLength,1.)
+
+    def test_cone(self):
+        cone = hppfcl.Cone(1.,2.)
+        self.assertIsInstance(cone, hppfcl.Cone)
+        self.assertIsInstance(cone, hppfcl.ShapeBase)
+        self.assertIsInstance(cone, hppfcl.CollisionGeometry)
+        self.assertEqual(cone.getNodeType(), hppfcl.NODE_TYPE.GEOM_CONE)
+        self.assertEqual(cone.radius,1.)
+        self.assertEqual(cone.halfLength,1.)
+        cone.radius = 3.
+        cone.halfLength = 4.
+        self.assertEqual(cone.radius,3.)
+        self.assertEqual(cone.halfLength,4.)
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/test/scripts/collision-bench.py b/test/scripts/collision-bench.py
new file mode 100644
index 0000000000000000000000000000000000000000..3497c83a26441f8f3474c2a753a01496a04864a7
--- /dev/null
+++ b/test/scripts/collision-bench.py
@@ -0,0 +1,76 @@
+import matplotlib.pyplot as plt
+import csv, sys, numpy as np
+from math import sqrt
+
+filename = sys.argv[1] 
+
+with open(filename, 'r') as file:
+    reader = csv.reader (file, strict = True)
+    fieldnames = None
+    #fieldnames = reader.fieldnames
+    converters = (str, int, int, int, float, lambda x: float(x)*1e-3)
+
+    for row in reader:
+        if fieldnames is None:
+            fieldnames = [ n.strip() for n in row]
+            values = []
+            continue
+
+        values.append ( [ c(v) for v, c in zip(row, converters) ] )
+
+request1 = values[:int(len(values)/2)]
+request2 = values[int(len(values)/2):]
+
+Ntransforms = 1
+while values[0][0:3] == values[Ntransforms][0:3]:
+    Ntransforms += 1
+
+splitMethods = ['avg', 'med', 'cen']
+type = ["o", "or", "r", ]
+BVs = sorted (list (set ([ v[0] for v in request1[::Ntransforms] ])))
+xvals = [ BVs.index(v[0]) + len(BVs)*v[2] + 3*len(BVs)*v[1] for v in request1[::Ntransforms] ]
+cases = [ v[0] + " " + type[v[1]] + " " + splitMethods[v[2]] for v in request1[::Ntransforms] ]
+
+idx_reorder = sorted (list(range(len(xvals))), key=lambda i: xvals[i])
+def reorder (l): return [ l[i] for i in idx_reorder ]
+
+xvals_s = reorder (xvals)
+cases_s = reorder (cases)
+
+onlyLB = True
+# Time
+plt.figure(0)
+for i in range(Ntransforms):
+    if not onlyLB:
+        plt.plot(xvals_s, reorder([ v[5] for v in request1[i::Ntransforms] ]) , '-.o', label=str(i))
+    plt.plot(xvals_s, reorder([ v[5] for v in request2[i::Ntransforms] ]) , ':+',  label=str(i)+"+lb")
+
+plt.legend()
+plt.xticks(ticks=xvals_s, labels=cases_s, rotation=90)
+plt.ylabel('Time (us)')
+plt.yscale('log')
+
+# Time
+plt.figure(2)
+for k in range (0, len(request1), Ntransforms):
+    if not onlyLB:
+        plt.plot([ xvals[int(k/Ntransforms)], ], sum([ v[5] for v in request1[k:k+Ntransforms] ])/Ntransforms)
+    plt.plot([ xvals[int(k/Ntransforms)], ], sum([ v[5] for v in request2[k:k+Ntransforms] ])/Ntransforms)
+
+plt.plot(xvals_s, reorder ([ sum([ v[5] for v in request2[k:k+Ntransforms] ])/Ntransforms for k in range (0, len(request1), Ntransforms) ]))
+
+plt.xticks(ticks=xvals_s, labels=cases_s, rotation=90)
+plt.ylabel('Time (us)')
+plt.yscale('log')
+
+# Distance lower bound
+plt.figure(1)
+for i in range(Ntransforms):
+    if request2[i][3] > 0: continue
+    plt.plot(xvals_s, reorder([ v[4] for v in request2[i::Ntransforms] ]) , ':+',  label=str(i)+"+lb")
+
+plt.legend()
+plt.ylabel('Distance lower bound')
+plt.xticks(ticks=xvals_s, labels=cases_s, rotation=90)
+
+plt.show()
diff --git a/test/test_fcl_collision.py b/test/scripts/collision.py
similarity index 100%
rename from test/test_fcl_collision.py
rename to test/scripts/collision.py
diff --git a/test/test_fcl_distance_lower_bound.py b/test/scripts/distance_lower_bound.py
similarity index 100%
rename from test/test_fcl_distance_lower_bound.py
rename to test/scripts/distance_lower_bound.py
diff --git a/test/test_fcl_geometric_shapes.py b/test/scripts/geometric_shapes.py
similarity index 100%
rename from test/test_fcl_geometric_shapes.py
rename to test/scripts/geometric_shapes.py
diff --git a/test/test_fcl_gjk.py b/test/scripts/gjk.py
similarity index 100%
rename from test/test_fcl_gjk.py
rename to test/scripts/gjk.py
diff --git a/test/scripts/obb.py b/test/scripts/obb.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f9141cd74306a72d64ac3229b4f2800e67d9bf1
--- /dev/null
+++ b/test/scripts/obb.py
@@ -0,0 +1,110 @@
+import matplotlib.pyplot as plt
+import csv, sys, numpy as np
+from math import sqrt
+
+filename = sys.argv[1] 
+
+with open(filename, 'r') as file:
+    reader = csv.reader (file, strict = True)
+    fieldnames = None
+    #fieldnames = reader.fieldnames
+    for row in reader:
+        if fieldnames is None:
+            fieldnames = [ n.strip() for n in row]
+            values = [ [] for _ in fieldnames ]
+            continue
+
+        values[0].append (int(row[0]))
+        for i, v in enumerate(row[1:]):
+            values[i+1].append (float(v))
+
+# Compute mean and variance for each values, for each separating axis
+means = [ [ 0., ] * 12 for _ in fieldnames[4:] ]
+stddevs = [ [ 0., ] * 12 for _ in fieldnames[4:] ]
+nb_occurence = [ 0, ] * 12
+
+for i, id in enumerate(values[0]):
+    nb_occurence[id] += 1
+
+for i, id in enumerate(values[0]):
+    for k, n in enumerate(fieldnames[4:]):
+        v = values[k+4][i]
+        means  [k][id] += v / nb_occurence[id]
+        stddevs[k][id] += v * v / nb_occurence[id]
+
+for k, n in enumerate(fieldnames[4:]):
+    for id in range(12):
+        #means  [k][id] /= nb_occurence[id]
+        #stddevs[k][id] = sqrt (stddevs[k][id]) / nb_occurence[id] - means[k][id])
+        stddevs[k][id] = sqrt (stddevs[k][id] - means[k][id]*means[k][id])
+
+subplots = False
+Nrows = 1
+Ncols = 3
+iplot = 1
+time_vs_sep_axis = True
+nb_occ_sep_axis = False
+avg_time_vs_impl = True
+
+if time_vs_sep_axis:
+    if subplots: plt.subplot (Nrows, Ncols, iplot)
+    else:        plt.figure (iplot)
+    plt.title ("Time, with std dev, versus separating axis")
+    for k, n in enumerate(fieldnames[4:]):
+        #plt.errorbar ([ np.linspace(0, 11, 12) + shift for shift in np.linspace (-0.2, 0.2, ) ], means[k], stddevs[k], label=n)
+        plt.errorbar (np.linspace(0, 11, 12), means[k], stddevs[k], label=n)
+        # plt.errorbar (np.linspace(0, 11, 12), means[k],  [ [ 0 ] * len(stddevs[k]), stddevs[k] ], label=n)
+    plt.xlim([-0.5,11.5])
+    plt.ylabel('Time (ns)')
+    plt.xlabel('Separating axis')
+    plt.legend(loc='upper left')
+
+    axx = plt.gca().twinx()
+    axx.hist (values[0], bins=[ i-0.5 for i in range(13) ], bottom=-0.5, cumulative=True,
+            rwidth=0.5, fill=False, label='Cumulative occurence')
+    axx.set_ylabel('Nb occurence of a separating axis.')
+    plt.legend(loc='lower right')
+
+iplot += 1
+if nb_occ_sep_axis:
+    if subplots: plt.subplot (Nrows, Ncols, iplot)
+    else:        plt.figure (iplot)
+    plt.title ("Nb of occurence per separating axis")
+    plt.hist (values[0], bins=[ i-0.5 for i in range(13) ])
+    plt.ylabel('Nb occurence')
+    plt.xlabel('Separating axis')
+    dlb_id = 1
+    d_id = 2
+    #plt.title ("Time, with std dev, versus distance")
+    #for k, n in enumerate(fieldnames[4:]):
+        #plt.plot (values[dlb_id], values[k+4], '.', label=n)
+
+iplot += 1
+if avg_time_vs_impl:
+    if subplots: plt.subplot (Nrows, Ncols, iplot)
+    else:        plt.figure (iplot)
+    plt.title ("Average time versus the implementation")
+    #plt.boxplot(values[4:], labels=fieldnames[4:], showmeans=True)
+    _mins = np.min (values[4:], axis=1)
+    _maxs = np.max (values[4:], axis=1)
+    _means = np.mean (values[4:], axis=1)
+    _stddev = np.std (values[4:], axis=1)
+    _sorted = sorted ( zip(fieldnames[4:], _means, _stddev, _mins, _maxs), key=lambda x: x[1])
+    plt.errorbar(
+            [ f for f,m,s,l,u in _sorted],
+            [ m for f,m,s,l,u in _sorted],
+            [ s for f,m,s,l,u in _sorted],
+            fmt='go', linestyle='', label='mean and std deviation')
+    plt.plot (
+            [ f for f,m,s,l,u in _sorted],
+            [ l for f,m,s,l,u in _sorted],
+            'b+', ls='', label='min')
+    plt.plot (
+            [ f for f,m,s,l,u in _sorted],
+            [ u for f,m,s,l,u in _sorted],
+            'r+', ls='', label='max')
+    plt.ylabel('Time (ns)')
+    plt.xticks(rotation=20)
+    plt.legend()
+
+plt.show()
diff --git a/test/test_fcl_octree.py b/test/scripts/octree.py
similarity index 100%
rename from test/test_fcl_octree.py
rename to test/scripts/octree.py
diff --git a/test/test_fcl_shape_mesh_consistency.cpp b/test/shape_mesh_consistency.cpp
similarity index 99%
rename from test/test_fcl_shape_mesh_consistency.cpp
rename to test/shape_mesh_consistency.cpp
index f2471bf25d43bdc4659288a6a128b79f78c29041..226f15898e91ddccbabef13a2804f26f9e653920 100644
--- a/test/test_fcl_shape_mesh_consistency.cpp
+++ b/test/shape_mesh_consistency.cpp
@@ -44,7 +44,7 @@
 #include <hpp/fcl/shape/geometric_shape_to_BVH_model.h>
 #include <hpp/fcl/distance.h>
 #include <hpp/fcl/collision.h>
-#include "test_fcl_utility.h"
+#include "utility.h"
 
 
 using namespace hpp::fcl;
diff --git a/test/test_fcl_simple.cpp b/test/simple.cpp
similarity index 96%
rename from test/test_fcl_simple.cpp
rename to test/simple.cpp
index 725f6ac657d43743e8a668afdc36f9428d962979..54cd915c89756a0165696e11f9a3154d0e7f574b 100644
--- a/test/test_fcl_simple.cpp
+++ b/test/simple.cpp
@@ -3,7 +3,7 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/utility/binary.hpp>
 
-#include <hpp/fcl/intersect.h>
+#include <hpp/fcl/internal/intersect.h>
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/BVH/BVH_model.h>
 #include "fcl_resources/config.h"
diff --git a/test/test_fcl_sphere_capsule.cpp b/test/sphere_capsule.cpp
similarity index 100%
rename from test/test_fcl_sphere_capsule.cpp
rename to test/sphere_capsule.cpp
diff --git a/test/test_fcl_collision.cpp b/test/test_fcl_collision.cpp
deleted file mode 100644
index 2330248b60a98519ab5afbb4562c78d7aae75562..0000000000000000000000000000000000000000
--- a/test/test_fcl_collision.cpp
+++ /dev/null
@@ -1,1054 +0,0 @@
-/*
- * Software License Agreement (BSD License)
- *
- *  Copyright (c) 2011-2014, Willow Garage, Inc.
- *  Copyright (c) 2014-2015, Open Source Robotics Foundation
- *  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 Open Source Robotics Foundation 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 Jia Pan */
-
-#define BOOST_TEST_MODULE FCL_COLLISION
-#define BOOST_TEST_DYN_LINK
-#include <boost/test/unit_test.hpp>
-#include <boost/utility/binary.hpp>
-
-#include <hpp/fcl/traversal/traversal_node_bvhs.h>
-#include <hpp/fcl/traversal/traversal_node_setup.h>
-#include <hpp/fcl/collision_node.h>
-#include <hpp/fcl/collision.h>
-#include <hpp/fcl/BV/BV.h>
-#include <hpp/fcl/shape/geometric_shapes.h>
-#include <hpp/fcl/narrowphase/narrowphase.h>
-#include "test_fcl_utility.h"
-#include "fcl_resources/config.h"
-#include <boost/filesystem.hpp>
-
-using namespace hpp::fcl;
-
-template<typename BV>
-bool collide_Test(const Transform3f& tf,
-                  const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                  const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose = true);
-
-template<typename BV>
-bool collide_Test2(const Transform3f& tf,
-                   const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                   const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose = true);
-
-template<typename BV, typename TraversalNode>
-bool collide_Test_Oriented(const Transform3f& tf,
-                           const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                           const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose = true);
-
-
-template<typename BV>
-bool test_collide_func(const Transform3f& tf,
-                       const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                       const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method);
-
-int num_max_contacts = std::numeric_limits<int>::max();
-
-std::vector<Contact> global_pairs;
-std::vector<Contact> global_pairs_now;
-
-BOOST_AUTO_TEST_CASE(OBB_Box_test)
-{
-  FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
-  std::vector<Transform3f> rotate_transform;
-  generateRandomTransforms(r_extents, rotate_transform, 1);
-  
-  AABB aabb1;
-  aabb1.min_ = Vec3f(-600, -600, -600);
-  aabb1.max_ = Vec3f(600, 600, 600);
-
-  OBB obb1;
-  convertBV(aabb1, rotate_transform[0], obb1);
-  Box box1;
-  Transform3f box1_tf;
-  constructBox(aabb1, rotate_transform[0], box1, box1_tf);
-
-  FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
-  std::size_t n = 1000;
-
-  std::vector<Transform3f> transforms;
-  generateRandomTransforms(extents, transforms, n);
-
-  for(std::size_t i = 0; i < transforms.size(); ++i)
-  {
-    AABB aabb;
-    aabb.min_ = aabb1.min_ * 0.5;
-    aabb.max_ = aabb1.max_ * 0.5;    
-
-    OBB obb2;
-    convertBV(aabb, transforms[i], obb2);
-    
-    Box box2;
-    Transform3f box2_tf;
-    constructBox(aabb, transforms[i], box2, box2_tf);
-
-    GJKSolver_indep solver;
-
-    bool overlap_obb = obb1.overlap(obb2);
-    bool overlap_box = solver.shapeIntersect(box1, box1_tf, box2, box2_tf, NULL, NULL, NULL);
-    
-    BOOST_CHECK(overlap_obb == overlap_box);
-  }
-}
-
-BOOST_AUTO_TEST_CASE(OBB_shape_test)
-{
-  FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
-  std::vector<Transform3f> rotate_transform;
-  generateRandomTransforms(r_extents, rotate_transform, 1);
-  
-  AABB aabb1;
-  aabb1.min_ = Vec3f(-600, -600, -600);
-  aabb1.max_ = Vec3f(600, 600, 600);
-
-  OBB obb1;
-  convertBV(aabb1, rotate_transform[0], obb1);
-  Box box1;
-  Transform3f box1_tf;
-  constructBox(aabb1, rotate_transform[0], box1, box1_tf);
-
-  FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
-  std::size_t n = 1000;
-
-  std::vector<Transform3f> transforms;
-  generateRandomTransforms(extents, transforms, n);
-
-  for(std::size_t i = 0; i < transforms.size(); ++i)
-  {
-    FCL_REAL len = (aabb1.max_[0] - aabb1.min_[0]) * 0.5;
-    OBB obb2;
-    GJKSolver_indep solver;
- 
-    {  
-      Sphere sphere(len);
-      computeBV(sphere, transforms[i], obb2);
- 
-      bool overlap_obb = obb1.overlap(obb2);
-      bool overlap_sphere = solver.shapeIntersect(box1, box1_tf, sphere, transforms[i], NULL, NULL, NULL);
-      BOOST_CHECK(overlap_obb >= overlap_sphere);
-    }
-
-    {
-      Capsule capsule(len, 2 * len);
-      computeBV(capsule, transforms[i], obb2);
-      
-      bool overlap_obb = obb1.overlap(obb2);
-      bool overlap_capsule = solver.shapeIntersect(box1, box1_tf, capsule, transforms[i], NULL, NULL, NULL);
-      BOOST_CHECK(overlap_obb >= overlap_capsule);
-    }
-
-    {
-      Cone cone(len, 2 * len);
-      computeBV(cone, transforms[i], obb2);
-      
-      bool overlap_obb = obb1.overlap(obb2);
-      bool overlap_cone = solver.shapeIntersect(box1, box1_tf, cone, transforms[i], NULL, NULL, NULL);
-      BOOST_CHECK(overlap_obb >= overlap_cone);
-    }
-
-    {
-      Cylinder cylinder(len, 2 * len);
-      computeBV(cylinder, transforms[i], obb2);
-      
-      bool overlap_obb = obb1.overlap(obb2);
-      bool overlap_cylinder = solver.shapeIntersect(box1, box1_tf, cylinder, transforms[i], NULL, NULL, NULL);
-      BOOST_CHECK(overlap_obb >= overlap_cylinder);
-    }
-  }
-}
-
-BOOST_AUTO_TEST_CASE(OBB_AABB_test)
-{
-  FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000};
-  std::size_t n = 1000;
-
-  std::vector<Transform3f> transforms;
-  generateRandomTransforms(extents, transforms, n);
-
-  AABB aabb1;
-  aabb1.min_ = Vec3f(-600, -600, -600);
-  aabb1.max_ = Vec3f(600, 600, 600);
-  
-  OBB obb1;
-  convertBV(aabb1, Transform3f(), obb1);
-  
-  for(std::size_t i = 0; i < transforms.size(); ++i)
-  {
-    AABB aabb;
-    aabb.min_ = aabb1.min_ * 0.5;
-    aabb.max_ = aabb1.max_ * 0.5;    
-
-    AABB aabb2 = translate(aabb, transforms[i].getTranslation());
-    
-    OBB obb2;
-    convertBV(aabb, Transform3f(transforms[i].getTranslation()), obb2);
-
-    bool overlap_aabb = aabb1.overlap(aabb2);
-    bool overlap_obb = obb1.overlap(obb2);
-    if(overlap_aabb != overlap_obb)
-    {
-      std::cout << aabb1.min_ << " " << aabb1.max_ << std::endl;
-      std::cout << aabb2.min_ << " " << aabb2.max_ << std::endl;
-      std::cout << obb1.To << " " << obb1.extent << " " << obb1.axes << std::endl;
-      std::cout << obb2.To << " " << obb2.extent << " " << obb2.axes << std::endl;
-    }
-
-    BOOST_CHECK(overlap_aabb == overlap_obb);
-  }
-  std::cout << std::endl;
-}
-
-// This test
-//  1. load two objects "env.obj" and "rob.obj" from directory
-//     fcl_resources,
-//  2. generates n random transformation and for each of them denote tf,
-//    2.1 performs a collision test where object 1 is in pose tf. All
-//        the contacts are stored in vector global_pairs.
-//    2.2 performs a series of collision tests with the same object and
-//        the same poses using various methods and various types of bounding
-//        volumes. Each time the contacts are stored in vector global_pairs_now.
-//
-// The methods used to test collision are
-//  - collide_Test that calls function collide with tf for object1 pose and
-//      identity for the second object pose,
-//  - collide_Test2 that moves all vertices of object1 in pose tf and that
-//      calls function collide with identity for both object poses,
-//
-BOOST_AUTO_TEST_CASE(mesh_mesh)
-{
-  std::vector<Vec3f> p1, p2;
-  std::vector<Triangle> t1, t2;
-  boost::filesystem::path path(TEST_RESOURCES_DIR);
-  
-  loadOBJFile((path / "env.obj").string().c_str(), p1, t1);
-  loadOBJFile((path / "rob.obj").string().c_str(), p2, t2);
-
-  std::vector<Transform3f> transforms;
-  FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000};
-  std::size_t n = 10;
-  bool verbose = false;
-
-  generateRandomTransforms(extents, transforms, n);
-
-  // collision
-  for(std::size_t i = 0; i < transforms.size(); ++i)
-  {
-    Eigen::IOFormat f (Eigen::FullPrecision, 0, ", ", ",", "", "", "(", ")");
-
-    std::cerr
-      << "q1=" << transforms [i].getTranslation ().format (f) << "+" <<
-      transforms [i].getQuatRotation ().coeffs ().format (f) << std::endl;
-    global_pairs.clear();
-    global_pairs_now.clear();
-
-    // First test: constacts are stored in vector global_pairs
-    collide_Test<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-
-    collide_Test<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<OBB, MeshCollisionTraversalNodeOBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<OBB, MeshCollisionTraversalNodeOBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<OBB, MeshCollisionTraversalNodeOBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<RSS, MeshCollisionTraversalNodeRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<RSS, MeshCollisionTraversalNodeRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<RSS, MeshCollisionTraversalNodeRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    
-    collide_Test<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-    
-    collide_Test_Oriented<kIOS, MeshCollisionTraversalNodekIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<kIOS, MeshCollisionTraversalNodekIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<kIOS, MeshCollisionTraversalNodekIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test2<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-    
-    collide_Test_Oriented<OBBRSS, MeshCollisionTraversalNodeOBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<OBBRSS, MeshCollisionTraversalNodeOBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    collide_Test_Oriented<OBBRSS, MeshCollisionTraversalNodeOBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-
-    test_collide_func<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER);
-    assert (global_pairs.size() == global_pairs_now.size());
-    for(std::size_t j = 0; j < global_pairs.size(); ++j)
-    {
-      BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1);
-      BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2);
-    }
-  }
-}
-
-
-template<typename BV>
-bool collide_Test2(const Transform3f& tf,
-                   const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                   const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose)
-{
-  BVHModel<BV> m1;
-  BVHModel<BV> m2;
-  m1.bv_splitter.reset(new BVSplitter<BV>(split_method));
-  m2.bv_splitter.reset(new BVSplitter<BV>(split_method));
-
-  std::vector<Vec3f> vertices1_new(vertices1.size());
-  for(unsigned int i = 0; i < vertices1_new.size(); ++i)
-  {
-    vertices1_new[i] = tf.transform(vertices1[i]);
-  }
-
-
-  m1.beginModel();
-  m1.addSubModel(vertices1_new, triangles1);
-  m1.endModel();
-
-  m2.beginModel();
-  m2.addSubModel(vertices2, triangles2);
-  m2.endModel();
-
-  Transform3f pose1, pose2;
-
-  CollisionResult local_result;
-  CollisionRequest request (CONTACT, num_max_contacts);
-  MeshCollisionTraversalNode<BV> node (request);
-
-  bool success = initialize <BV> (node, m1, pose1, m2, pose2, local_result);
-  assert (success);
-
-  node.enable_statistics = verbose;
-
-  collide(&node, request, local_result);
-
-  if(local_result.numContacts() > 0)
-  {
-    if(global_pairs.size() == 0)
-    {
-      local_result.getContacts(global_pairs);
-      std::sort(global_pairs.begin(), global_pairs.end());
-    }
-    else
-    {
-      local_result.getContacts(global_pairs_now);
-      std::sort(global_pairs_now.begin(), global_pairs_now.end());
-    }
-
-
-    if(verbose)
-      std::cout << "in collision " << local_result.numContacts() << ": " << std::endl;
-    if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl;
-    return true;
-  }
-  else
-  {
-    if(verbose) std::cout << "collision free " << std::endl;
-    if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl;
-    return false;
-  }
-}
-
-// Test collision between two sets of triangles
-// first object is in pose tf, second object is in pose identity.
-template<typename BV>
-bool collide_Test(const Transform3f& tf,
-                  const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                  const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose)
-{
-  BVHModel<BV> m1;
-  BVHModel<BV> m2;
-  m1.bv_splitter.reset(new BVSplitter<BV>(split_method));
-  m2.bv_splitter.reset(new BVSplitter<BV>(split_method));
-
-  m1.beginModel();
-  m1.addSubModel(vertices1, triangles1);
-  m1.endModel();
-
-  m2.beginModel();
-  m2.addSubModel(vertices2, triangles2);
-  m2.endModel();
-
-  Transform3f pose1(tf), pose2;
-
-  CollisionResult local_result;
-  CollisionRequest request (CONTACT, num_max_contacts);
-  MeshCollisionTraversalNode<BV> node (request);
-
-  bool success = initialize <BV> (node, m1, pose1, m2, pose2, local_result);
-  assert (success);
-
-  node.enable_statistics = verbose;
-
-  collide(&node, request, local_result);
-
-  if(local_result.numContacts() > 0)
-  {
-    if(global_pairs.size() == 0)
-    {
-      local_result.getContacts(global_pairs);
-      std::sort(global_pairs.begin(), global_pairs.end());
-    }
-    else
-    {
-      local_result.getContacts(global_pairs_now);
-      std::sort(global_pairs_now.begin(), global_pairs_now.end());
-    }
-
-    if(verbose)
-      std::cout << "in collision " << local_result.numContacts() << ": " << std::endl;
-    if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl;
-    return true;
-  }
-  else
-  {
-    if(verbose) std::cout << "collision free " << std::endl;
-    if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl;
-    return false;
-  }
-}
-
-// This function is the same as collide_Test, except that the type of traversal
-// node is chosen via template argument.
-template<typename BV, typename TraversalNode>
-bool collide_Test_Oriented(const Transform3f& tf,
-                           const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                           const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose)
-{
-  BVHModel<BV> m1;
-  BVHModel<BV> m2;
-  m1.bv_splitter.reset(new BVSplitter<BV>(split_method));
-  m2.bv_splitter.reset(new BVSplitter<BV>(split_method));
-
-  m1.beginModel();
-  m1.addSubModel(vertices1, triangles1);
-  m1.endModel();
-
-  m2.beginModel();
-  m2.addSubModel(vertices2, triangles2);
-  m2.endModel();
-
-  Transform3f pose1(tf), pose2;
-
-  CollisionResult local_result;
-  CollisionRequest request (CONTACT, num_max_contacts);
-  TraversalNode node (request);
-  bool success = initialize (node, (const BVHModel<BV>&)m1, pose1,
-                             (const BVHModel<BV>&)m2, pose2, local_result);
-  assert (success);
-
-  node.enable_statistics = verbose;
-
-  collide(&node, request, local_result);
-
-  if(local_result.numContacts() > 0)
-  {
-    if(global_pairs.size() == 0)
-    {
-      local_result.getContacts(global_pairs);
-      std::sort(global_pairs.begin(), global_pairs.end());
-    }
-    else
-    {
-      local_result.getContacts(global_pairs_now);
-      std::sort(global_pairs_now.begin(), global_pairs_now.end());
-    }
-
-    if(verbose)
-      std::cout << "in collision " << local_result.numContacts() << ": " << std::endl;
-    if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl;
-    return true;
-  }
-  else
-  {
-    if(verbose) std::cout << "collision free " << std::endl;
-    if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl;
-    return false;
-  }
-}
-
-
-template<typename BV>
-bool test_collide_func(const Transform3f& tf,
-                       const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                       const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method)
-{
-  BVHModel<BV> m1;
-  BVHModel<BV> m2;
-  m1.bv_splitter.reset(new BVSplitter<BV>(split_method));
-  m2.bv_splitter.reset(new BVSplitter<BV>(split_method));
-
-  m1.beginModel();
-  m1.addSubModel(vertices1, triangles1);
-  m1.endModel();
-
-  m2.beginModel();
-  m2.addSubModel(vertices2, triangles2);
-  m2.endModel();
-
-  Transform3f pose1(tf), pose2;
-
-  std::vector<Contact> contacts;
-
-  CollisionRequest request (CONTACT, num_max_contacts);
-  CollisionResult result;
-  int num_contacts = collide(&m1, pose1, &m2, pose2, 
-                             request, result);
-	
-  result.getContacts(contacts);
-
-  global_pairs_now.resize(num_contacts);
-
-  for(int i = 0; i < num_contacts; ++i)
-  {
-    global_pairs_now[i].b1 = contacts[i].b1;
-    global_pairs_now[i].b2 = contacts[i].b2;
-  }
-
-  std::sort(global_pairs_now.begin(), global_pairs_now.end());
-
-  if(num_contacts > 0) return true;
-  else return false;
-}
diff --git a/test/test_fcl_obb.cpp b/test/test_fcl_obb.cpp
deleted file mode 100644
index 9e38af65e41144d0731dd9f7e4339c62e1c50cb0..0000000000000000000000000000000000000000
--- a/test/test_fcl_obb.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Software License Agreement (BSD License)
- *
- *  Copyright (c) 2014-2016, CNRS-LAAS
- *  Author: Florent Lamiraux
- *  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 CNRS 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.
- */
-
-#define BOOST_TEST_MODULE FCL_DISTANCE_OBB
-#define BOOST_TEST_DYN_LINK
-#include <boost/test/unit_test.hpp>
-#include <boost/utility/binary.hpp>
-
-#define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps))
-
-#include <boost/test/included/unit_test.hpp>
-#include <hpp/fcl/narrowphase/narrowphase.h>
-
-#include "../src/BV/OBB.h"
-#include "../src/distance_func_matrix.h"
-
-using hpp::fcl::FCL_REAL;
-
-struct Sample
-{
-  hpp::fcl::Matrix3f R;
-  hpp::fcl::Vec3f T;
-  hpp::fcl::Vec3f extent1;
-  hpp::fcl::Vec3f extent2;
-};
-
-struct Result
-{
-  bool overlap;
-  FCL_REAL distance;
-};
-
-BOOST_AUTO_TEST_CASE(obb_overlap)
-{
-  static const size_t nbSamples = 10000;
-  Sample sample [nbSamples];
-  FCL_REAL range = 2;
-  FCL_REAL sumDistance = 0, sumDistanceLowerBound = 0;
-  for (std::size_t i=0; i<nbSamples; ++i) {
-    // sample unit quaternion
-    FCL_REAL u1 = (FCL_REAL) rand() / RAND_MAX;
-    FCL_REAL u2 = (FCL_REAL) rand() / RAND_MAX;
-    FCL_REAL u3 = (FCL_REAL) rand() / RAND_MAX;
-
-    FCL_REAL q1 = sqrt (1-u1)*sin(2*M_PI*u2);
-    FCL_REAL q2 = sqrt (1-u1)*cos(2*M_PI*u2);
-    FCL_REAL q3 = sqrt (u1) * sin(2*M_PI*u3);
-    FCL_REAL q4 = sqrt (u1) * cos(2*M_PI*u3);
-    hpp::fcl::Quaternion3f (q1, q2, q3, q4).toRotation (sample [i].R);
-
-    // sample translation
-    sample [i].T = hpp::fcl::Vec3f ((FCL_REAL) range * rand() / RAND_MAX,
-			       (FCL_REAL) range * rand() / RAND_MAX,
-			       (FCL_REAL) range * rand() / RAND_MAX);
-
-    // sample extents
-    sample [i].extent1 = hpp::fcl::Vec3f ((FCL_REAL) rand() / RAND_MAX,
-				     (FCL_REAL) rand() / RAND_MAX,
-				     (FCL_REAL) rand() / RAND_MAX);
-
-    sample [i].extent2 = hpp::fcl::Vec3f ((FCL_REAL) rand() / RAND_MAX,
-				     (FCL_REAL) rand() / RAND_MAX,
-				     (FCL_REAL) rand() / RAND_MAX);
-  }
-
-  // Compute result for each function
-  Result resultDistance [nbSamples];
-  Result resultDisjoint [nbSamples];
-  Result resultDisjointAndLowerBound [nbSamples];
-
-  hpp::fcl::Transform3f tf1;
-  hpp::fcl::Transform3f tf2;
-  hpp::fcl::Box box1 (0, 0, 0);
-  hpp::fcl::Box box2 (0, 0, 0);
-  hpp::fcl::DistanceRequest request (false, 0, 0, hpp::fcl::GST_INDEP);
-  hpp::fcl::DistanceResult result;
-  FCL_REAL distance;
-  FCL_REAL squaredDistance;
-  timeval t0, t1;
-  hpp::fcl::GJKSolver_indep gjkSolver;
-
-  // ShapeShapeDistance
-  gettimeofday (&t0, NULL);
-  for (std::size_t i=0; i<nbSamples; ++i) {
-    box1.side = 2*sample [i].extent1;
-    box2.side = 2*sample [i].extent2;
-    tf2.setTransform (sample [i].R, sample [i].T);
-    resultDistance [i].distance =
-      hpp::fcl::ShapeShapeDistance<hpp::fcl::Box, hpp::fcl::Box, hpp::fcl::GJKSolver_indep>
-      (&box1, tf1, &box2, tf2, &gjkSolver, request, result);
-    resultDistance [i].overlap = (resultDistance [i].distance < 0);
-    if (resultDistance [i].distance < 0) {
-      resultDistance [i].distance = 0;
-    }
-    result.clear ();
-  }    
-  gettimeofday (&t1, NULL);
-  double t = (t1.tv_sec - t0.tv_sec) + 1e-6*(t1.tv_usec - t0.tv_usec + 0.);
-  std::cout << "Time for " << nbSamples
-	    << " calls to ShapeShapeDistance (in seconds): "
-	    << t << std::endl;
-
-  // obbDisjointAndLowerBoundDistance
-  gettimeofday (&t0, NULL);
-  for (std::size_t i=0; i<nbSamples; ++i) {
-    resultDisjointAndLowerBound [i].overlap =
-      !obbDisjointAndLowerBoundDistance (sample [i].R, sample [i].T,
-					 sample [i].extent1,
-					 sample [i].extent2,
-					 squaredDistance);
-    resultDisjointAndLowerBound [i].distance = sqrt (squaredDistance);
-  }    
-  gettimeofday (&t1, NULL);
-  t = (t1.tv_sec - t0.tv_sec) + 1e-6*(t1.tv_usec - t0.tv_usec + 0.);
-  std::cout << "Time for " << nbSamples
-	    << " calls to obbDisjointAndLowerBoundDistance"
-	    << " (in seconds): "
-	    << t << std::endl;
-
-  gettimeofday (&t0, NULL);
-  for (std::size_t i=0; i<nbSamples; ++i) {
-    resultDisjoint [i].overlap =
-      !obbDisjoint (sample [i].R, sample [i].T,
-		    sample [i].extent1,
-		    sample [i].extent2);
-    resultDisjoint [i].distance = 0;
-  }    
-  gettimeofday (&t1, NULL);
-  t = (t1.tv_sec - t0.tv_sec) + 1e-6*(t1.tv_usec - t0.tv_usec + 0.);
-  std::cout << "Time for " << nbSamples << " calls to obbDisjoint"
-	    << " (in seconds): "
-	    << t << std::endl;
-
-  // Test correctness of results
-  bool res1, res2, res3;
-  for (std::size_t i=0; i<nbSamples; ++i) {
-    res1 = resultDisjoint [i].overlap;
-    res2 = resultDisjointAndLowerBound [i].overlap;
-    res3 = resultDistance [i].overlap;
-    sumDistanceLowerBound += resultDisjointAndLowerBound [i].distance;
-    sumDistance += resultDistance [i].distance;
-
-#if 0
-    std::cout << "ShapeShapeDistance:    overlap: "
-	      << resultDistance [i].overlap
-	      << ", distance: " << resultDistance [i].distance << std::endl;
-    std::cout << "disjoint:              overlap: "
-	      << resultDisjoint [i].overlap
-	      << ", distance: " << resultDisjoint [i].distance << std::endl;
-    std::cout << "disjointAndLowerBound: overlap: "
-	      << resultDisjointAndLowerBound [i].overlap
-	      << ", distance: " << resultDisjointAndLowerBound [i].distance
-	      << std::endl << std::endl;
-#endif
-    BOOST_CHECK (res1 == res2);
-    BOOST_CHECK (res1 == res3);
-    BOOST_CHECK ((!res1 && resultDisjointAndLowerBound [i].distance > 0) ||
-		 (res1 && resultDisjointAndLowerBound [i].distance == 0));
-    BOOST_CHECK (resultDisjointAndLowerBound [i].distance <=
-		 resultDistance [i].distance);
-  }
-  std::cout << "Sum distances ShapeShapeDistance:               "
-	    << sumDistance << std::endl;
-  std::cout << "Sum distances obbDisjointAndLowerBoundDistance: "
-	    << sumDistanceLowerBound << std::endl;
-}
diff --git a/test/test_fcl_utility.cpp b/test/utility.cpp
similarity index 86%
rename from test/test_fcl_utility.cpp
rename to test/utility.cpp
index 9a22a9dffeac0c854e64a551ed151c1529a71e98..a107faf800e65c71051f954a91e6124b10761609 100644
--- a/test/test_fcl_utility.cpp
+++ b/test/utility.cpp
@@ -1,16 +1,16 @@
-#include "test_fcl_utility.h"
+#include "utility.h"
 #include <hpp/fcl/collision.h>
 #include <hpp/fcl/distance.h>
 #include <cstdio>
 #include <cstddef>
 #include <fstream>
+#include <iostream>
 
 namespace hpp
 {
 namespace fcl
 {
 
-
 Timer::Timer()
 {
 #ifdef _WIN32
@@ -94,6 +94,13 @@ double Timer::getElapsedTime()
 }
 
 
+const Eigen::IOFormat vfmt  = Eigen::IOFormat (Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "", "");
+const Eigen::IOFormat pyfmt = Eigen::IOFormat (Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "[", "]");
+
+const Vec3f UnitX = Vec3f(1, 0, 0);
+const Vec3f UnitY = Vec3f(0, 1, 0);
+const Vec3f UnitZ = Vec3f(0, 0, 1);
+
 FCL_REAL rand_interval(FCL_REAL rmin, FCL_REAL rmax)
 {
   FCL_REAL t = rand() / ((FCL_REAL)RAND_MAX + 1);
@@ -332,51 +339,6 @@ void generateRandomTransforms(FCL_REAL extents[6], FCL_REAL delta_trans[3], FCL_
   }
 }
 
-void generateRandomTransform_ccd(FCL_REAL extents[6], std::vector<Transform3f>& transforms, std::vector<Transform3f>& transforms2, FCL_REAL delta_trans[3], FCL_REAL delta_rot, std::size_t n,
-                                 const std::vector<Vec3f>& /*vertices1*/, const std::vector<Triangle>& /*riangles1*/,
-                                 const std::vector<Vec3f>& /*vertices2*/, const std::vector<Triangle>& /*riangles2*/)
-{
-  transforms.resize(n);
-  transforms2.resize(n);
-
-  for(std::size_t i = 0; i < n;)
-  {
-    FCL_REAL x = rand_interval(extents[0], extents[3]);
-    FCL_REAL y = rand_interval(extents[1], extents[4]);
-    FCL_REAL z = rand_interval(extents[2], extents[5]);
-
-    const FCL_REAL pi = 3.1415926;
-    FCL_REAL a = rand_interval(0, 2 * pi);
-    FCL_REAL b = rand_interval(0, 2 * pi);
-    FCL_REAL c = rand_interval(0, 2 * pi);
-
-
-    Matrix3f R;
-    eulerToMatrix(a, b, c, R);
-    Vec3f T(x, y, z);    
-    Transform3f tf(R, T);
-
-    std::vector<std::pair<int, int> > results;
-    {
-      transforms[i] = tf;
-
-      FCL_REAL deltax = rand_interval(-delta_trans[0], delta_trans[0]);
-      FCL_REAL deltay = rand_interval(-delta_trans[1], delta_trans[1]);
-      FCL_REAL deltaz = rand_interval(-delta_trans[2], delta_trans[2]);
-
-      FCL_REAL deltaa = rand_interval(-delta_rot, delta_rot);
-      FCL_REAL deltab = rand_interval(-delta_rot, delta_rot);
-      FCL_REAL deltac = rand_interval(-delta_rot, delta_rot);
-
-      Matrix3f R2;
-      eulerToMatrix(a + deltaa, b + deltab, c + deltac, R2);
-      Vec3f T2(x + deltax, y + deltay, z + deltaz);
-      transforms2[i].setTransform(R2, T2);
-      ++i;
-    }
-  }
-}
-
 bool defaultCollisionFunction(CollisionObject* o1, CollisionObject* o2, void* cdata_)
 {
   CollisionData* cdata = static_cast<CollisionData*>(cdata_);
@@ -473,6 +435,15 @@ Quaternion3f makeQuat(FCL_REAL w, FCL_REAL x, FCL_REAL y, FCL_REAL z)
   return q;
 }
 
+std::ostream& operator<< (std::ostream& os, const Transform3f& tf)
+{
+  return os << "[ " <<
+    tf.getTranslation().format(vfmt)
+    << ", "
+    << tf.getQuatRotation().coeffs().format(vfmt)
+    << " ]" ;
+}
+
 }
 
 } // namespace hpp
diff --git a/test/test_fcl_utility.h b/test/utility.h
similarity index 89%
rename from test/test_fcl_utility.h
rename to test/utility.h
index 80bab48ebdc7a24282a2543fe98a4d9fe8ddff86..dcefa68407e78a52928ba54432d8cc602445425d 100644
--- a/test/test_fcl_utility.h
+++ b/test/utility.h
@@ -92,6 +92,12 @@ private:
 #endif
 };
 
+extern const Eigen::IOFormat vfmt;
+extern const Eigen::IOFormat pyfmt;
+typedef Eigen::AngleAxis<FCL_REAL> AngleAxis;
+extern const Vec3f UnitX;
+extern const Vec3f UnitY;
+extern const Vec3f UnitZ;
 
 /// @brief Load an obj mesh file
 void loadOBJFile(const char* filename, std::vector<Vec3f>& points, std::vector<Triangle>& triangles);
@@ -112,12 +118,6 @@ void generateRandomTransforms(FCL_REAL extents[6], std::vector<Transform3f>& tra
 /// @brief Generate n random transforms whose translations are constrained by extents. Also generate another transforms2 which have additional random translation & rotation to the transforms generated.
 void generateRandomTransforms(FCL_REAL extents[6], FCL_REAL delta_trans[3], FCL_REAL delta_rot, std::vector<Transform3f>& transforms, std::vector<Transform3f>& transforms2, std::size_t n);
 
-/// @brief Generate n random tranforms and transform2 with addtional random translation/rotation. The transforms and transform2 are used as initial and goal configurations for the first mesh. The second mesh is in I. This is used for continuous collision detection checking.
-void generateRandomTransforms_ccd(FCL_REAL extents[6], std::vector<Transform3f>& transforms, std::vector<Transform3f>& transforms2, FCL_REAL delta_trans[3], FCL_REAL delta_rot, std::size_t n,
-                                 const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1,
-                                 const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2);
-
-
 /// @ brief Structure for minimum distance between two meshes and the corresponding nearest point pair
 struct DistanceRes
 {
@@ -176,6 +176,8 @@ std::string getGJKSolverName(GJKSolverType solver_type);
 
 Quaternion3f makeQuat(FCL_REAL w, FCL_REAL x, FCL_REAL y, FCL_REAL z);
 
+std::ostream& operator<< (std::ostream& os, const Transform3f& tf);
+
 }
 
 } // namespace hpp
diff --git a/travis_custom/custom_before_install_linux.sh b/travis_custom/custom_before_install_linux.sh
new file mode 100755
index 0000000000000000000000000000000000000000..37285b80c268fc4b86cb0b224e4a407bbf44d8bb
--- /dev/null
+++ b/travis_custom/custom_before_install_linux.sh
@@ -0,0 +1,11 @@
+# Add robotpkg
+sudo sh -c "echo \"deb [arch=amd64] http://robotpkg.openrobots.org/packages/debian/pub $(lsb_release -cs) robotpkg\" >> /etc/apt/sources.list"
+curl http://robotpkg.openrobots.org/packages/debian/robotpkg.key | sudo apt-key add -
+sudo apt-get update
+
+# install eigenpy
+sudo apt-get -qqy install robotpkg-py27-eigenpy
+
+# set environment variables
+export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/opt/openrobots/lib/pkgconfig"
+export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/opt/openrobots/lib"
\ No newline at end of file
diff --git a/travis_custom/custom_before_install_osx.sh b/travis_custom/custom_before_install_osx.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b2d8bb1153c3c8a083f8aad1548a883c0c225df0
--- /dev/null
+++ b/travis_custom/custom_before_install_osx.sh
@@ -0,0 +1,11 @@
+brew update
+
+# Add gepetto tap
+brew tap gepetto/homebrew-gepetto
+
+# install eigenpy
+brew install boost assimp eigen octomap eigenpy
+
+# set environment variables
+export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/opt/openrobots/lib/pkgconfig"
+export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/opt/openrobots/lib"