From 3cd28ecab5bfcc5e1da18bcbc2b8c59320bdd315 Mon Sep 17 00:00:00 2001
From: Tobias Leemann <tobias.leemann@fau.de>
Date: Fri, 17 Nov 2017 19:48:56 +0100
Subject: [PATCH] Removed Debug function, updated name of GJK call to match
 EPA, added Implementation in cpp-File

---
 src/pe/collision/EPA.cpp        |  883 ++++++++++++++++++++++++++
 src/pe/collision/GJK.cpp        | 1045 +++++++++++++++++++++++++++++++
 src/pe/fcd/IterativeFCD.h       |    2 +-
 tests/pe/CollisionTobiasGJK.cpp |    2 +-
 4 files changed, 1930 insertions(+), 2 deletions(-)
 create mode 100644 src/pe/collision/EPA.cpp
 create mode 100644 src/pe/collision/GJK.cpp

diff --git a/src/pe/collision/EPA.cpp b/src/pe/collision/EPA.cpp
new file mode 100644
index 000000000..b20d776dd
--- /dev/null
+++ b/src/pe/collision/EPA.cpp
@@ -0,0 +1,883 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file EPA.cpp
+//! \author Tobias Scharpff
+//! \author Tobias Leemann
+//
+//  DISCLAIMER: The following source file contains modified code from the SOLID-3.5 library for
+//  interference detection as it is published in the book "Collision Detection in Interactive
+//  3D Environments" by Gino van den Bergen <info@dtecta.com>. Even though the original source
+//  was published under the GPL version 2 not allowing later versions, the original author of the
+//  source code permitted the relicensing of the SOLID-3.5 library under the GPL version 3 license.
+//
+//=================================================================================================
+
+//*************************************************************************************************
+// Includes
+//*************************************************************************************************
+#include "EPA.h"
+
+#include <pe/Thresholds.h>
+#include <pe/Types.h>
+
+#include <core/math/Constants.h>
+#include <core/math/Limits.h>
+#include <core/math/Matrix3.h>
+#include <core/math/Quaternion.h>
+
+#include <vector>
+
+namespace walberla {
+namespace pe {
+namespace fcd {
+
+//=================================================================================================
+//
+//  EPA::EPA_TRIANGLE CONSTRUCTOR
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \brief Construct a new EPA_Triangle.
+ *  \param a First point index
+ *  \param b Second point index
+ *  \param c Third point index
+ *  \param points Vector with all points
+ */
+inline EPA::EPA_Triangle::EPA_Triangle( size_t a, size_t b, size_t c,
+                                        const std::vector<Vec3>& points )
+{
+   const Vec3& A = points[a];
+   const Vec3& B = points[b];
+   const Vec3& C = points[c];
+
+   indices_[0] = a;
+   indices_[1] = b;
+   indices_[2] = c;
+
+   //calculate the closest point to the origin
+   //Real-Time Collsion Buch Seite 137
+   Vec3 ab = B-A;
+   Vec3 ac = C-A;
+   //Vec3 bc = C-B;
+
+   normal_ = ab % ac;
+   Vec3 nT = normal_;
+
+   //
+   real_t vc = nT * (A % B);
+   real_t va = nT * (B % C);
+   real_t vb = nT * (C % A);
+   real_t denom = real_t(1.0) / (va + vb + vc);
+
+   bar_[0] = va * denom;
+   bar_[1] = vb * denom;
+   bar_[2] = real_t(1.0) - bar_[0] - bar_[1];
+
+   closest_ = bar_[0] * A + bar_[1] * B + bar_[2] * C;
+
+   //sqrDist=key is square distance of v to origin
+   sqrDist_ = closest_.sqrLength();
+
+   //adjoined triangles not set yet
+   adjTriangle_[0] = adjTriangle_[1] = adjTriangle_[2] = NULL;
+   adjEdges_[0]    = adjEdges_[1]    = adjEdges_[2] = 4;
+
+   obsolete_ = false;
+}
+
+//=================================================================================================
+//
+//  EPA::EPA_TRIANGLE UTILITY FUNCTIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \brief Sets the link of this triangles edge0 neighbor to tria and vice versa.
+ */
+inline bool EPA::EPA_Triangle::link( size_t edge0, EPA_Triangle* tria, size_t edge1 )
+{
+   WALBERLA_ASSERT_LESS(edge0, 3, "link: invalid edge index");
+   WALBERLA_ASSERT_LESS(edge1, 3, "link: invalid edge index");
+
+   adjTriangle_[edge0] = tria;
+   adjEdges_[edge0] = edge1;
+   tria->adjTriangle_[edge1] = this;
+   tria->adjEdges_[edge1] = edge0;
+
+   bool b = indices_[edge0]       == tria->indices_[(edge1+1)%3] &&
+         indices_[(edge0+1)%3] == tria->indices_[edge1];
+   return b;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Fills edgeBuffer with the CCW contour of triangles not seen from point w which is in normal direction of the triangle.
+ */
+inline void EPA::EPA_Triangle::silhouette( const Vec3& w, EPA_EdgeBuffer& edgeBuffer )
+{
+   //std::cerr << "Starting Silhoutette search on Triangle {" << indices_[0] << "," << indices_[1] << "," << indices_[2] << "}" << std::endl;
+   edgeBuffer.clear();
+   obsolete_ = true;
+
+   adjTriangle_[0]->silhouette(adjEdges_[0], w, edgeBuffer);
+   adjTriangle_[1]->silhouette(adjEdges_[1], w, edgeBuffer);
+   adjTriangle_[2]->silhouette(adjEdges_[2], w, edgeBuffer);
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Recursive silhuette finding method.
+ */
+void EPA::EPA_Triangle::silhouette( size_t index, const Vec3& w,
+                                           EPA_EdgeBuffer& edgeBuffer )
+{
+   if (!obsolete_) {
+      real_t test = (closest_ * w);
+      if (test < sqrDist_) {
+         edgeBuffer.push_back(EPA_Edge(this, index));
+      }
+      else {
+         obsolete_ = true; // Facet is visible
+         size_t next = (index+1) % 3;
+         adjTriangle_[next]->silhouette(adjEdges_[next], w, edgeBuffer);
+         next = (next+1) % 3;
+         adjTriangle_[next]->silhouette(adjEdges_[next], w, edgeBuffer);
+      }
+   }
+}
+//*************************************************************************************************
+
+//=================================================================================================
+//
+//  EPA QUERY FUNCTIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+//EPA Precision default values for different data types
+template< class T > struct EpsilonRelEPA;
+template<> struct EpsilonRelEPA<       float > { static const       float value; };
+template<> struct EpsilonRelEPA<      double > { static const      double value; };
+template<> struct EpsilonRelEPA< long double > { static const long double value; };
+
+const       float EpsilonRelEPA<       float >::value = static_cast<       float >(1e-4);
+const      double EpsilonRelEPA<      double >::value = static_cast<      double >(1e-6);
+const long double EpsilonRelEPA< long double >::value = static_cast< long double >(1e-6);
+
+//*************************************************************************************************
+/*! \brief Does an EPA computation with contactthreshold added. Use Default relative Error.
+ */
+bool EPA::doEPAcontactThreshold( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec3& retNormal,
+                                        Vec3& contactPoint, real_t& penetrationDepth){
+
+   //Default relative epsilon
+   return doEPA(geom1, geom2, gjk, retNormal, contactPoint, penetrationDepth, contactThreshold, EpsilonRelEPA<real_t>::value);
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Does an EPA computation with contactThreshold added. Relative Error can be specified.
+ */
+bool EPA::doEPAcontactThreshold( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec3& retNormal,
+                                        Vec3& contactPoint, real_t& penetrationDepth, real_t eps_rel){
+
+   return doEPA(geom1, geom2, gjk, retNormal, contactPoint, penetrationDepth, contactThreshold, eps_rel);
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Does an EPA computation with margin added. Use Default relative Error.
+ */
+bool EPA::doEPAmargin( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec3& retNormal,
+                              Vec3& contactPoint, real_t& penetrationDepth, real_t margin){
+   //Default relative epsilon
+   return doEPA(geom1, geom2, gjk, retNormal, contactPoint, penetrationDepth, margin, EpsilonRelEPA<real_t>::value);
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Does an epa computation with contact margin added and specified realtive error.
+ */
+bool EPA::doEPA( GeomPrimitive &geom1, GeomPrimitive &geom2, const GJK& gjk, Vec3& retNormal,
+                        Vec3& contactPoint, real_t& penetrationDepth, real_t margin, real_t eps_rel )
+{
+   //have in mind that we use a support mapping which blows up the objects a wee bit so
+   //zero penetraion aka toching contact means that the original bodies have a distance of 2*margin between them
+
+   //Set references to the results of GJK
+   size_t     numPoints( static_cast<size_t>( gjk.getSimplexSize() ) );
+   std::vector<Vec3> epaVolume( gjk.getSimplex() );
+   std::vector<Vec3> supportA ( gjk.getSupportA() );
+   std::vector<Vec3> supportB ( gjk.getSupportB() );
+
+   Vec3 support;
+
+   epaVolume.reserve( maxSupportPoints_ );
+   supportA.reserve ( maxSupportPoints_ );
+   supportB.reserve ( maxSupportPoints_ );
+
+   EPA_EntryBuffer entryBuffer;
+   entryBuffer.reserve(maxTriangles_);
+
+   EPA_EntryHeap entryHeap;
+   entryHeap.reserve(maxTriangles_);
+
+   EPA_EdgeBuffer edgeBuffer;
+   edgeBuffer.reserve(20);
+
+   real_t lowerBoundSqr = math::Limits<real_t>::inf();
+   real_t upperBoundSqr = math::Limits<real_t>::inf();
+
+   //create an Initial simplex
+   if(numPoints == 1) {
+      //If the GJK-Simplex contains only one point, it must be the origin and it must be on the boundary of the CSO.
+      //This means the enlarged bodies are in touching contact and the original bodies do not intersect.
+      return false;
+   }
+   else {
+      createInitialSimplex(numPoints, geom1, geom2, supportA, supportB, epaVolume, entryBuffer, margin);
+   }
+
+   for(EPA_EntryBuffer::iterator it=entryBuffer.begin(); it != entryBuffer.end(); ++it) {
+      if(it->isClosestInternal()) {
+         entryHeap.push_back(&(*it));
+      }
+   }
+
+   if(entryHeap.size() == 0) {
+      //unrecoverable error.
+      return false;
+   }
+
+   std::make_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
+   EPA_Triangle* current = NULL;
+
+   //EPA Main-Loop
+   do {
+      std::pop_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
+      current = entryHeap.back();
+      entryHeap.pop_back();
+      if(!current->isObsolete()) {
+         WALBERLA_ASSERT_GREATER(current->getSqrDist(), real_t(0.0), "EPA_Trianalge distance is negative.");
+         lowerBoundSqr = current->getSqrDist();
+
+         if(epaVolume.size() == maxSupportPoints_) {
+            WALBERLA_ASSERT(false, "Support point limit reached.");
+            break;
+         }
+
+         // Compute new support direction
+         // if origin is contained in plane, use out-facing normal.
+         Vec3 normal;
+         if(current->getSqrDist() < real_comparison::Epsilon<real_t>::value*real_comparison::Epsilon<real_t>::value){
+            normal = current->getNormal().getNormalized();
+         }else{
+            normal = current->getClosest().getNormalized();
+         }
+         //std::cerr << "Current Closest: " << current->getClosest();
+         //std::cerr << "New support direction: " <<  normal << std::endl;
+
+         pushSupportMargin(geom1, geom2, normal, margin, epaVolume, supportA, supportB);
+         support = epaVolume.back();
+
+         numPoints++;
+
+         real_t farDist = support * normal; //not yet squared
+
+         WALBERLA_ASSERT_GREATER(farDist, real_t(0.0), "EPA support mapping gave invalid point in expansion direction");
+         //std::cerr << "New upper bound: " <<  farDist*farDist << std::endl;
+         upperBoundSqr = std::min(upperBoundSqr, farDist*farDist);
+
+         //Try to approximate the new surface with a sphere
+         Vec3 ctr;
+         real_t radius2 = calculateCircle(support, epaVolume[(*current)[0]],
+               epaVolume[(*current)[1]], epaVolume[(*current)[2]], ctr);
+         if(radius2 > real_t(0.0)){ //if a Sphere exists
+            //std::cerr << "Circle created with center at " << ctr << ". r2=" << radius2 << std::endl;
+            real_t center_len = ctr.length();
+            real_t circle_dist = (std::sqrt(radius2) - center_len); //Distance from center to the spheres surface
+            //Check if the circle matches the bounds given by EPA and limit max error to ca. 5%
+            if(circle_dist*circle_dist <= upperBoundSqr && circle_dist*circle_dist >= lowerBoundSqr &&
+                  (circle_dist*circle_dist)/lowerBoundSqr < real_t(1.10) && !floatIsEqual(center_len, real_t(0.0))) {
+
+               ctr = -1*ctr.getNormalized();
+               //std::cerr << "New support direction: " <<  ctr << std::endl;
+               pushSupportMargin(geom1, geom2, ctr, margin, epaVolume, supportA, supportB);
+               support = epaVolume.back();
+               // Check if support is in expected direction
+
+               if(floatIsEqual((support % ctr).sqrLength()/support.sqrLength(), real_t(0.0))){ //Accept sphere
+
+                  contactPoint = real_t(0.5) * (supportA.back() + supportB.back());
+                  penetrationDepth = -support.length()+ real_t(2.0) * margin;
+                  retNormal = -ctr;
+                  //std::cerr << "Found penetration depth " << penetrationDepth << " with CurvedEPA!" << std::endl;
+                  if(penetrationDepth < contactThreshold){
+                     return true;
+                  }else{
+                     return false;
+                  }
+               } else { //Reject sphere
+                  removeSupportMargin(epaVolume, supportA, supportB);
+                  support = epaVolume.back();
+               }
+            }
+         }
+
+         //terminating criteria's
+         //- we found that the two bounds are close enough
+         //- the added support point was already in the epaVolume
+         if(upperBoundSqr <= (real_t(1.0)+eps_rel)*(real_t(1.0)+eps_rel)*lowerBoundSqr
+               || support == epaVolume[(*current)[0]]
+               || support == epaVolume[(*current)[1]]
+               || support == epaVolume[(*current)[2]])
+         {
+            //std::cerr << "Tolerance reached." << std::endl;
+            break;
+         }
+
+         // Compute the silhouette cast by the new vertex
+         // Note that the new vertex is on the positive side
+         // of the current triangle, so the current triangle
+         // will not be in the convex hull. Start local search
+         // from this facet.
+
+         current->silhouette(support, edgeBuffer);
+         if(edgeBuffer.size() < 3 ) {
+            return false;
+         }
+
+         if(entryBuffer.size() == maxSupportPoints_) {
+            //"out of memory" so stop here
+            //std::cerr << "Memory Limit reached." << std::endl;
+            break;
+         }
+
+         EPA_EdgeBuffer::const_iterator it = edgeBuffer.begin();
+         entryBuffer.push_back(EPA_Triangle(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume));
+
+         EPA_Triangle* firstTriangle = &(entryBuffer.back());
+         //if it is expanding candidate add to heap
+         //std::cerr << "Considering Triangle (" << firstTriangle->getSqrDist() << ") {"  << (*firstTriangle)[0] <<  "," << (*firstTriangle)[1] <<  ","<< (*firstTriangle)[2] << "} ("<< epaVolume[(*firstTriangle)[0]] * firstTriangle->getNormal()<< ")" << std::endl;
+         if(epaVolume[(*firstTriangle)[0]] * firstTriangle->getNormal() < real_t(0.0)){
+            //the whole triangle is on the wrong side of the origin.
+            //This is a numerical error and will produce wrong results, if the search is continued. Stop here.
+            break;
+         }
+         if(firstTriangle->isClosestInternal()
+               && firstTriangle->getSqrDist() > lowerBoundSqr
+               && firstTriangle->getSqrDist() < upperBoundSqr)
+         {
+            entryHeap.push_back(firstTriangle);
+            std::push_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
+         }
+
+         firstTriangle->link(0, it->getTriangle(), it->getIndex());
+
+         EPA_Triangle* lastTriangle = firstTriangle;
+
+         ++it;
+         for(; it != edgeBuffer.end(); ++it){
+            if(entryBuffer.size() == maxSupportPoints_) {
+               //"out of memory" so stop here
+               break;
+            }
+
+            entryBuffer.push_back(EPA_Triangle(it->getEnd(), it->getStart(), epaVolume.size()-1, epaVolume));
+            EPA_Triangle* newTriangle = &(entryBuffer.back());
+
+            //std::cerr << "Considering Triangle (" << newTriangle->getSqrDist() << ") {"  << (*newTriangle)[0] <<  "," << (*newTriangle)[1] <<  ","<< (*newTriangle)[2] << "} ("<< epaVolume[(*newTriangle)[0]] * newTriangle->getNormal() << ")" << std::endl;
+
+            if(epaVolume[(*newTriangle)[0]] * newTriangle->getNormal() < real_t(0.0)){
+               //the whole triangle is on the wrong side of the origin.
+               //This is an error.
+               break;
+            }
+            //if it is expanding candidate add to heap
+            if(newTriangle->isClosestInternal()
+                  &&  newTriangle->getSqrDist() > lowerBoundSqr
+                  &&  newTriangle->getSqrDist() < upperBoundSqr)
+            {
+               entryHeap.push_back(newTriangle);
+               std::push_heap(entryHeap.begin(), entryHeap.end(), EPA::EPA_TriangleComp());
+            }
+
+            if(!newTriangle->link(0, it->getTriangle(), it->getIndex())) {
+               break;
+            }
+
+            if(!newTriangle->link(2, lastTriangle, 1)) {
+               break;
+            }
+
+            lastTriangle = newTriangle;
+         }
+
+         if(it != edgeBuffer.end()) {
+            //For some reason the silhouette couldn't be processed completely
+            //so we stop here and take the last result
+            break;
+         }
+
+         firstTriangle->link(2, lastTriangle, 1);
+      }
+   } while (entryHeap.size() > 0 && entryHeap[0]->getSqrDist() <= upperBoundSqr);
+
+   //Normal must be inverted
+   retNormal   = -current->getClosest().getNormalized();
+
+   //Calculate Witness points
+   const Vec3 wittnessA = current->getClosestPoint(supportA);
+   const Vec3 wittnessB = current->getClosestPoint(supportB);
+   contactPoint = real_t(0.5) * (wittnessA + wittnessB);
+
+   //Penetration Depth
+   penetrationDepth = -(current->getClosest().length() - real_t(2.0) * margin);
+
+   /*std::cerr << "normal=" << retNormal <<std::endl;
+   std::cerr << "close =" << current->getClosest() << std::endl;
+   std::cerr << "diff  =" << wittnesA - wittnesB  <<std::endl;
+   std::cerr << "wittnesA    =" << wittnesA <<std::endl;
+   std::cerr << "wittnesB    =" << wittnesB <<std::endl;
+   std::cerr << "contactPoint=" << contactPoint << std::endl;
+   std::cerr << "penDepth=" << penetrationDepth  <<std::endl;
+   std::cerr << "lowerBound=" << sqrt(lowerBoundSqr) <<std::endl;
+   std::cerr << "curreBound=" << current->getClosest().length() << std::endl;
+   std::cerr << "upperBound=" << sqrt(upperBoundSqr) <<std::endl;
+   std::cerr << "Heap Size=" << entryHeap.size() << std::endl;
+   std::cerr << "entryHeap[0]->getSqrDist()=" << entryHeap[0]->getSqrDist() << std::endl;*/
+   //std::cout << "EPA penetration depth: " << penetrationDepth <<  std::endl;
+
+   if(penetrationDepth < contactThreshold) {
+      return true;
+   }
+
+   //no intersection found!
+   return false;
+}
+//*************************************************************************************************
+
+//=================================================================================================
+//
+//  EPA UTILITY FUNCTIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \brief Create a starting tetrahedron for EPA, from the GJK Simplex.
+ */
+inline void EPA::createInitialSimplex( size_t numPoints, GeomPrimitive &geom1, GeomPrimitive &geom2,
+                                       std::vector<Vec3>& supportA, std::vector<Vec3>& supportB,
+                                       std::vector<Vec3>& epaVolume, EPA_EntryBuffer& entryBuffer, real_t margin )
+{
+   switch(numPoints) {
+   case 2:
+   {
+      //simplex is a line segement
+      //add 3 points around the this segment
+      //the COS is konvex so the resulting hexaheadron should be konvex too
+
+      Vec3 d = epaVolume[1] - epaVolume[0];
+      //find coordinate axis e_i which is furthest from paralell to d
+      //and therefore d has the smallest abs(d[i])
+      real_t abs0 = std::abs(d[0]);
+      real_t abs1 = std::abs(d[1]);
+      real_t abs2 = std::abs(d[2]);
+
+      Vec3 axis;
+      if( abs0 < abs1 && abs0 < abs2) {
+         axis = Vec3(real_t(1.0), real_t(0.0), real_t(0.0));
+      }
+      else if( abs1 < abs0 && abs1 < abs2) {
+         axis = Vec3(real_t(0.0), real_t(1.0), real_t(0.0));
+      }
+      else {
+         axis = Vec3(real_t(0.0), real_t(0.0), real_t(1.0));
+      }
+
+      Vec3 direction1 = (d % axis).getNormalized();
+      Quat q(d, (real_t(2.0)/real_t(3.0)) * real_t(walberla::math::M_PI));
+      Mat3 rot = q.toRotationMatrix();
+      Vec3 direction2 = (rot*direction1).getNormalized();
+      Vec3 direction3 = (rot*direction2).getNormalized();
+
+      //add point in positive normal direction1
+      pushSupportMargin(geom1, geom2, direction1, margin, epaVolume, supportA, supportB);
+      //std::cerr << "S1: " << support1 << std::endl;
+
+      //add point in negative normal direction2
+      pushSupportMargin(geom1, geom2, direction2, margin, epaVolume, supportA, supportB);
+      //std::cerr << "S2: " << support2 << std::endl;
+
+      //add point in negative normal direction
+      pushSupportMargin(geom1, geom2, direction3, margin, epaVolume, supportA, supportB);
+      //std::cerr << "S3: " << support3 << std::endl;
+
+      //Build the hexahedron as it is convex
+      //epaVolume[1] = up
+      //epaVolume[0] = down
+      //epaVolume[2] = ccw1
+      //epaVolume[3] = ccw2
+      //epaVolume[4] = ccw3
+
+
+      //check for containment inside
+      if(originInTetrahedron(epaVolume[0], epaVolume[2], epaVolume[3], epaVolume[4]) || originInTetrahedron(epaVolume[1], epaVolume[2], epaVolume[3], epaVolume[4]) ){
+         //insert triangle 1
+         entryBuffer.push_back(EPA_Triangle(1, 2, 3, epaVolume)); //[0] up->ccw1->ccw2
+         //insert triangle 2
+         entryBuffer.push_back(EPA_Triangle(1, 3, 4, epaVolume)); //[1] up->ccw2->ccw3
+         //insert triangle 3
+         entryBuffer.push_back(EPA_Triangle(1, 4, 2, epaVolume)); //[2] up->ccw3->ccw1
+
+         //link these 3 triangles
+         entryBuffer[0].link(2, &(entryBuffer[1]), 0); //edge up->ccw1
+         entryBuffer[1].link(2, &(entryBuffer[2]), 0); //edge up->ccw2
+         entryBuffer[2].link(2, &(entryBuffer[0]), 0); //edge up->ccw3
+
+
+         //insert triangle 4
+         entryBuffer.push_back(EPA_Triangle(0, 2, 4, epaVolume)); //[3] down->ccw1->ccw3
+         //insert triangle 5
+         entryBuffer.push_back(EPA_Triangle(0, 4, 3, epaVolume)); //[4] down->ccw3->ccw2
+         //insert triangle 6
+         entryBuffer.push_back(EPA_Triangle(0, 3, 2, epaVolume)); //[5] down->ccw2->ccw1
+
+         //link these 3 triangles
+         entryBuffer[3].link(2, &(entryBuffer[4]), 0); //edge down->ccw3
+         entryBuffer[4].link(2, &(entryBuffer[5]), 0); //edge down->ccw1
+         entryBuffer[5].link(2, &(entryBuffer[3]), 0); //edge down->ccw1
+
+         //link the two pyramids
+         entryBuffer[0].link(1, &(entryBuffer[5]), 1); //edge ccw1->ccw2
+         entryBuffer[1].link(1, &(entryBuffer[4]), 1); //edge ccw2->ccw3
+         entryBuffer[2].link(1, &(entryBuffer[3]), 1); //edge ccw3->ccw1
+      }else{
+         //Apply iterative search
+         removeSupportMargin(epaVolume, supportA, supportB); //remove 5th point.
+         //Search starts from the remaining 4 points
+         searchTetrahedron(geom1, geom2, epaVolume, supportA, supportB, entryBuffer, margin);
+      }
+
+      break;
+   }
+   case 3:
+   {
+      //simplex is a triangle, add tow points in positive and negative normal direction
+
+      const Vec3& A = epaVolume[2];  //The Point last added to the simplex
+      const Vec3& B = epaVolume[1];  //One Point that was already in the simplex
+      const Vec3& C = epaVolume[0];  //One Point that was already in the simplex
+      //ABC is a conterclockwise triangle
+
+      const Vec3  AB  = B-A;       //The vector A->B
+      const Vec3  AC  = C-A;       //The vector A->C
+      const Vec3  ABC = (AB%AC).getNormalized();     //The the normal pointing towards the viewer if he sees a CCW triangle ABC
+
+      //add point in positive normal direction
+      pushSupportMargin(geom1, geom2, ABC, margin, epaVolume, supportA, supportB);
+
+      //add point in negative normal direction
+      pushSupportMargin(geom1, geom2, -ABC, margin, epaVolume, supportA, supportB);
+      //Vec3 support2 = epaVolume.back();
+
+      //check if the hexahedron is convex aka check if a partial tetrahedron contains the last point
+      if(pointInTetrahedron(epaVolume[3], epaVolume[4], epaVolume[0], epaVolume[2], epaVolume[1])) {
+         //epaVolumne[1] is whithin the tetraheadron 3-4-0-2 so this is the epaVolume to take
+         createInitialTetrahedron(3,4,0,2, epaVolume, entryBuffer);
+      }
+      else if(pointInTetrahedron(epaVolume[3], epaVolume[4], epaVolume[1], epaVolume[0], epaVolume[2])) {
+         createInitialTetrahedron(3,4,1,0, epaVolume, entryBuffer);
+      }
+      else if(pointInTetrahedron(epaVolume[3], epaVolume[4], epaVolume[2], epaVolume[1], epaVolume[0])) {
+         createInitialTetrahedron(3,4,2,1, epaVolume, entryBuffer);
+      }
+      else {
+         //Build the hexahedron as it is convex
+         //insert triangle 1
+         entryBuffer.push_back(EPA_Triangle(3, 2, 1, epaVolume)); //[0] support1->A->B
+         //insert triangle 2
+         entryBuffer.push_back(EPA_Triangle(3, 1, 0, epaVolume)); //[1] support1->B->C
+         //insert triangle 3
+         entryBuffer.push_back(EPA_Triangle(3, 0, 2, epaVolume)); //[2] support1->C->A
+
+         //link these 3 triangles
+         entryBuffer[0].link(2, &(entryBuffer[1]), 0); //edge support1->A
+         entryBuffer[1].link(2, &(entryBuffer[2]), 0); //edge support1->B
+         entryBuffer[2].link(2, &(entryBuffer[0]), 0); //edge support1->C
+
+
+         //insert triangle 4
+         entryBuffer.push_back(EPA_Triangle(4, 2, 0, epaVolume)); //[3] support2->A->C
+         //insert triangle 5
+         entryBuffer.push_back(EPA_Triangle(4, 0, 1, epaVolume)); //[4] support2->C->B
+         //insert triangle 6
+         entryBuffer.push_back(EPA_Triangle(4, 1, 2, epaVolume)); //[5] support2->B->A
+
+         //link these 3 triangles
+         entryBuffer[3].link(2, &(entryBuffer[4]), 0); //edge support2->C
+         entryBuffer[4].link(2, &(entryBuffer[5]), 0); //edge support2->B
+         entryBuffer[5].link(2, &(entryBuffer[3]), 0); //edge support2->A
+
+         //link the two pyramids
+         entryBuffer[0].link(1, &(entryBuffer[5]), 1); //edge A->B
+         entryBuffer[1].link(1, &(entryBuffer[4]), 1); //edge B->C
+         entryBuffer[2].link(1, &(entryBuffer[3]), 1); //edge C->A
+
+      }
+
+      break;
+   }
+   case 4:
+   {
+      createInitialTetrahedron(3,2,1,0, epaVolume, entryBuffer);
+      break;
+   }
+   default:
+   {
+      WALBERLA_ASSERT( false, "invalid number of simplex points in EPA" );
+      break;
+   }
+   }
+}
+
+//*************************************************************************************************
+
+//*************************************************************************************************
+/*! \brief TODO
+ *
+ * see Book "collision detection in interactive 3D environments" page161
+ * ATTENTION seems to have no consistent behavior on the surface and vertices
+ */
+inline bool EPA::originInTetrahedron( const Vec3& p0, const Vec3& p1, const Vec3& p2,
+                                      const Vec3& p3 )
+{
+   Vec3 normal0T = (p1 -p0) % (p2-p0);
+   if( (normal0T*p0 > real_t(0.0)) == (normal0T*p3 > real_t(0.0)) ) {
+      return false;
+   }
+   Vec3 normal1T = (p2 -p1) % (p3-p1);
+   if( (normal1T*p1 > real_t(0.0)) == (normal1T*p0 > real_t(0.0)) ) {
+      return false;
+   }
+   Vec3 normal2T = (p3 -p2) % (p0-p2);
+   if( (normal2T*p2 > real_t(0.0)) == (normal2T*p1 > real_t(0.0)) ) {
+      return false;
+   }
+   Vec3 normal3T = (p0 -p3) % (p1-p3);
+   if( (normal3T*p3 > real_t(0.0)) == (normal3T*p2 > real_t(0.0)) ) {
+      return false;
+   }
+
+   return true;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Retrurns true, if the origin lies in the tetrahedron ABCD.
+ */
+inline bool EPA::originInTetrahedronVolumeMethod( const Vec3& A, const Vec3& B, const Vec3& C,
+                                                  const Vec3& D )
+{
+   Vec3 aoT = A;
+   if((aoT * (B % C)) <= real_t(0.0)) {
+      //if volume of ABC and Origin <0.0 than the origin is on the wrong side of ABC
+      //http://mathworld.wolfram.com/Tetrahedron.html volume formula
+      return false;
+   }
+   if((aoT * (C % D)) <= real_t(0.0)) {
+      return false;
+   }
+   if((aoT * (D % B)) <= real_t(0.0)) {
+      return false;
+   }
+   if((B * (D % C)) <= real_t(0.0)) {
+      return false;
+   }
+   return true;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Retrurns true, if a point lies in the tetrahedron ABCD.
+ *  \param point The point to be checked for containment.
+ */
+inline bool EPA::pointInTetrahedron( const Vec3& A, const Vec3& B, const Vec3& C, const Vec3& D,
+                                     const Vec3& point )
+{
+   return originInTetrahedronVolumeMethod( A-point, B-point, C-point, D-point );
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*!\brief TODO
+ * top, frontLeft ... are indices
+ */
+inline void EPA::createInitialTetrahedron( size_t top, size_t frontLeft, size_t frontRight,
+                                           size_t back, std::vector<Vec3>& epaVolume,
+                                           EPA_EntryBuffer& entryBuffer )
+{
+   //insert triangle 1
+   entryBuffer.push_back(EPA_Triangle(top, frontLeft, frontRight, epaVolume)); //[0] vorne
+   //insert triangle 2
+   entryBuffer.push_back(EPA_Triangle(top, frontRight, back, epaVolume)); //[1] rechts hinten
+   //insert triangle 3
+   entryBuffer.push_back(EPA_Triangle(top, back, frontLeft, epaVolume)); //[2] links hinten
+   //insert triangle 4
+   entryBuffer.push_back(EPA_Triangle(back, frontRight, frontLeft, epaVolume)); //[3] unten
+
+   //make links between the triangles
+   entryBuffer[0].link(0, &(entryBuffer[2]), 2); //Kante vorne links
+   entryBuffer[0].link(2, &(entryBuffer[1]), 0); //Kante vorne rechts
+   entryBuffer[0].link(1, &(entryBuffer[3]), 1); //kante vorne unten
+
+   entryBuffer[1].link(2, &(entryBuffer[2]), 0); //Kante hinten
+   entryBuffer[1].link(1, &(entryBuffer[3]), 0); //kante rechts unten
+
+   entryBuffer[2].link(1, &(entryBuffer[3]), 2); //kante links unten
+
+}
+//*************************************************************************************************
+
+/*! \brief Search a tetrahedron that contains the origin.
+ * Start with four arbitrary support points in epaVolume that form a
+ * tetrahedron. (This needn't contain the origin.)
+ * This algorithm will search and return an altered tetrahedron
+ * containing the origin. Do only use this function if the object/body
+ * certainly contains the origin!
+ * \return True, if a tetrahedron was found. False if search has been aborted.
+ */
+inline bool EPA::searchTetrahedron(GeomPrimitive &geom1, GeomPrimitive &geom2, std::vector<Vec3>& epaVolume,
+                                   std::vector<Vec3>& supportA, std::vector<Vec3>& supportB, EPA_EntryBuffer& entryBuffer, real_t margin )
+{
+   //Store the point no longer needed (0 if all points are needed, and origin is contained.)
+   int loopCount = 0;
+   int pointIndexToRemove = -1;
+   Vec3 newSearchDirection;
+   do{
+      loopCount++;
+      pointIndexToRemove = -1;
+      //Check if opposite tetrahedron point and orign are on the same side
+      //of the face. (for all faces)
+      Vec3 normal0T = (epaVolume[1] -epaVolume[0]) % (epaVolume[2]-epaVolume[0]);
+      real_t dot_val = normal0T*epaVolume[0];
+      if( (normal0T*epaVolume[3] < dot_val) == (dot_val < real_t(0.0)) ) {
+         pointIndexToRemove = 3;
+         newSearchDirection = (normal0T*epaVolume[3] < dot_val) ? normal0T : -normal0T;
+      }
+
+      Vec3 normal1T = (epaVolume[2] -epaVolume[1]) % (epaVolume[3]-epaVolume[1]);
+      dot_val = normal1T*epaVolume[1];
+      if( (normal1T*epaVolume[0] < dot_val) == (dot_val < real_t(0.0)) ) {
+         pointIndexToRemove = 0;
+         newSearchDirection = (normal1T*epaVolume[0] < dot_val) ? normal1T : -normal1T;
+      }
+
+      Vec3 normal2T = (epaVolume[3] -epaVolume[2]) % (epaVolume[0]-epaVolume[2]);
+      dot_val = normal2T*epaVolume[2];
+      if( (normal2T*epaVolume[1] < dot_val) == (dot_val < real_t(0.0)) ) {
+         pointIndexToRemove = 1;
+         newSearchDirection = (normal2T*epaVolume[1] < dot_val) ? normal2T : -normal2T;
+      }
+
+      Vec3 normal3T = (epaVolume[0] -epaVolume[3]) % (epaVolume[1]-epaVolume[3]);
+      dot_val = normal3T*epaVolume[3];
+      if( (normal3T*epaVolume[2] < dot_val) == (dot_val < real_t(0.0)) ) {
+         pointIndexToRemove = 2;
+         newSearchDirection = (normal3T*epaVolume[2] < dot_val) ? normal3T : -normal3T;
+      }
+      //Origin not contained in tetrahedron.
+      if(pointIndexToRemove != -1){
+         if(loopCount > 50){
+            return false;
+         }
+         //Get new support point and replace old.
+         /*std::cerr << "Search Direction is: "<< newSearchDirection << std::endl;
+                   std::cerr << "Projection of unnecc. point " << pointIndexToRemove << ": " << epaVolume[pointIndexToRemove] * newSearchDirection << std::endl;
+                   std::cerr << "Projection of other points: " << epaVolume[(pointIndexToRemove+1)%4] * newSearchDirection << std::endl;*/
+         newSearchDirection = newSearchDirection.getNormalized();
+         /*supportA[pointIndexToRemove] = geom1.supportContactThreshold(newSearchDirection);
+                   supportB[pointIndexToRemove] = geom2.supportContactThreshold(-newSearchDirection);
+                   epaVolume[pointIndexToRemove] = supportA[pointIndexToRemove] - supportB[pointIndexToRemove];*/
+         replaceSupportMargin(geom1, geom2, newSearchDirection, margin, epaVolume, supportA, supportB, (size_t)pointIndexToRemove);
+         //std::cerr << "Projection of new support point " << epaVolume[pointIndexToRemove] << ": " << epaVolume[pointIndexToRemove] * newSearchDirection << std::endl;
+
+      }
+   }
+   while(pointIndexToRemove != 0);
+   //std::cerr << "Found Tet after " << loopCount << " searches." << std::endl;
+
+   //Build final tetrahedron
+   Vec3 check_normal = (epaVolume[1] -epaVolume[0]) % (epaVolume[2]-epaVolume[0]);
+   if(check_normal*epaVolume[3] > check_normal*epaVolume[0]){
+      //p3 is behind.
+      createInitialTetrahedron(1, 0, 2, 3, epaVolume, entryBuffer);
+   }else{
+      //p3 is in front
+      createInitialTetrahedron(1, 3, 2, 0, epaVolume, entryBuffer);
+   }
+   return true;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Calculate a Circle through the for Points A, B, C, D.
+ * \param center Contains the center point of the circle after the call
+ * \return The squared radius of the circle or a negative value if no such circle exists.
+ */
+inline real_t EPA::calculateCircle(const Vec3& A, const Vec3& B, const Vec3& C,
+                                   const Vec3& D, Vec3& center ){
+   real_t l1, l2, l3, d1, d2, d3;
+   l1 = (A-B).length(); /* These three sqrt evaluations are necessary */
+   l2 = (A-C).length();
+   l3 = (A-D).length();
+
+   Vec3 n1, n2, n3;
+   n1 = (real_t(1.0)/l1)*(A-B);
+   n2 = (real_t(1.0)/l2)*(A-C);
+   n3 = (real_t(1.0)/l3)*(A-D);
+
+   // Here we already see if such circle exists.
+   real_t det = n1 * (n2 % n3);
+   if(std::fabs(det) < math::Limits<real_t>::fpuAccuracy()){
+      //no circle exists. Leave center untouched, and return -1.0
+      return real_t(-1.0);
+   }
+   real_t Alen = A.sqrLength();
+   d1 = (Alen - B.sqrLength())/(real_t(2.0)*l1);
+   d2 = (Alen - C.sqrLength())/(real_t(2.0)*l2);
+   d3 = (Alen - D.sqrLength())/(real_t(2.0)*l3);
+
+   //Apply solution formula
+   center = (real_t(1.0)/det)*(d1 * (n2 % n3) + d2 * (n3 % n1) + d3 * (n1 % n2));
+
+   return (A - center).sqrLength();
+}
+//*************************************************************************************************
+
+} //fcd
+} //pe
+} //walberla
diff --git a/src/pe/collision/GJK.cpp b/src/pe/collision/GJK.cpp
new file mode 100644
index 000000000..b681b7805
--- /dev/null
+++ b/src/pe/collision/GJK.cpp
@@ -0,0 +1,1045 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file GJK.cpp
+//! \author Tobias Scharpff
+//! \author Tobias Leemann
+//
+//======================================================================================================================
+
+#include "GJK.h"
+
+//*************************************************************************************************
+// Includes
+//*************************************************************************************************
+
+#include <vector>
+#include <pe/Types.h>
+#include <pe/Thresholds.h>
+#include <core/Abort.h>
+#include <core/math/Limits.h>
+#include <core/math/Vector3.h>
+
+
+namespace walberla {
+namespace pe {
+namespace fcd {
+
+//=================================================================================================
+//
+//  QUERY FUNCTIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \brief Calculate an upper bound for the distance of two Geometries.
+ * \return Distance between geom1 and geom2 or 0.0 if they are intersecting.
+ */
+real_t GJK::doGJK(GeomPrimitive &geom1, GeomPrimitive &geom2, Vec3& normal, Vec3& contactPoint)
+{
+
+
+   //Variables
+   Vec3 support;     //the current support point
+   real_t ret;         //return value aka distance between geom1 and geom2
+
+
+   ////////////////////////////////////////////////////////////////////////
+   //Initial initialisation step
+   ret = 0.0;
+   supportA_.resize(4);
+   supportB_.resize(4);
+   simplex_.resize(4);
+
+   //get any first support point
+
+   supportA_[0] = geom1.support(d_);
+   supportB_[0] = geom2.support(-d_);
+   support = supportA_[0] - supportB_[0];
+
+   //add this point to the simplex_
+   simplex_[0] = support;
+   numPoints_ = 1;
+
+   if(support * d_ < real_t(0.0)){
+      //we went as far as we could in direction 'd' but not passed the origin
+      //this means the bodies don't overlap
+      ret = calcDistance(normal, contactPoint);
+      return ret;
+   }
+
+   //first real search direction is in the opposite direction of the first support po
+   d_ = -support;
+
+   ////////////////////////////////////////////////////////////////////////
+   //GJK main loop
+   while (true) {
+      //get the support point in the current search direction
+      normalize(d_);
+      supportA_[numPoints_] = geom1.support(d_);
+      supportB_[numPoints_] = geom2.support(-d_);
+      support = supportA_[numPoints_] - supportB_[numPoints_];
+      //std::cerr << "[GJK] Support Direction: " << d_ << std::endl;
+      //std::cerr << "[GJK] Got Support: " << support << std::endl;
+
+      //check if "support" is passed the origin in search direction
+      if(support * d_ < real_t(0.0)){
+         //we went as far as we could in direction 'd' but not passed the origin
+         //this means the bodies don't overlap
+         //calc distance simplex to Origin
+         ret = calcDistance(normal, contactPoint);
+
+         return ret;
+      }
+
+      //add the new support point into the simplex
+      simplex_[numPoints_] = support;
+      numPoints_++;
+
+      ////////////////////////////////////////////////////////////////
+      //check if the origin is in the simplex
+      //if it is the triangle mashes are overlapping
+      switch(numPoints_)
+      {
+      case 2:
+      {
+         if(simplex2(d_)) {
+            simplex_.pop_back();
+            simplex_.pop_back();
+            supportA_.pop_back();
+            supportA_.pop_back();
+            supportB_.pop_back();
+            supportB_.pop_back();
+            return ret;
+         }
+      }
+         break;
+
+      case 3:
+      {
+         if(simplex3(d_)) {
+            simplex_.pop_back();
+            supportA_.pop_back();
+            supportB_.pop_back();
+            return ret;
+         }
+      }
+         break;
+
+      case 4:
+      {
+         if(simplex4(d_)) {
+
+            return ret;
+         }
+      }
+         break;
+      default:
+      {
+         WALBERLA_ABORT( "Number of points in the simplex is not 1<=n<=4" );
+      }
+         break;
+      }
+   }
+
+   return ret; //never reach this point
+}
+//*************************************************************************************************
+
+//*************************************************************************************************
+/*! \brief Compute if two geometries intersect. Both can be enlarged by a specified margin.
+ * \param geom1 The first Body
+ * \param geom2 The second Body
+ * \param margin The margin by which the objects will be enlarged.
+ * \return true, if an itersection is found.
+ */
+bool GJK::doGJKmargin(GeomPrimitive &geom1, GeomPrimitive &geom2, real_t margin)
+{
+   //Variables
+   Vec3 support;     //the current support point
+
+   ////////////////////////////////////////////////////////////////////////
+   //Initial initialisation step
+   supportA_.resize(4);
+   supportB_.resize(4);
+   simplex_.resize(4);
+
+   //get any first support point
+   if(numPoints_ != 0) {
+      normalize(d_);
+   }
+   support = putSupport(geom1, geom2, d_, margin, simplex_, supportA_, supportB_, 0);
+
+   //std::cerr << "Support 1: " << support << std::endl;
+   //add this point to the simplex_
+   numPoints_ = 1;
+
+   //first real_t search direction is in the opposite direction of the first support point
+   d_ = -support;
+
+   /*
+   if(support * d_ < 0.0){
+         //we went as far as we could in direction 'd' but not passed the origin
+         //this means the triangle mashes don't overlap
+         //and as the support()-function extends the support point by contactThreshold
+         //the mashes are not even close enough to be considered in contact.
+         return false;
+   }
+   */
+   ////////////////////////////////////////////////////////////////////////
+   //GJK main loop
+   while (true) {
+      //get the support point in the current search direction
+      normalize(d_);
+      support = putSupport(geom1, geom2, d_, margin, simplex_, supportA_, supportB_, numPoints_);
+
+      //std::cerr << "GJK: Got support storing at " << (int)numPoints_ << ": "<< support << std::endl;
+      //check if "support" is passed the origin in search direction
+      if(support * d_ < 0.0){
+         // std::cerr << support * d_ << ": Returning false." << std::endl;
+         //we went as far as we could in direction 'd' but not passed the origin
+         //this means the triangle meshes don't overlap
+         //and as the support()-function extends the support point by contactThreshold
+         //the meshes are not even close enough to be considered in contact.
+         return false;
+      }
+
+      //add the new support point into the simplex
+      numPoints_++;
+
+      //std::cerr << "Num points " << (int)numPoints_ << std::endl;
+      ////////////////////////////////////////////////////////////////
+      //check if the origin is in the simplex
+      //if it is the triangle mashes are overlapping
+      switch(numPoints_)
+      {
+      case 2:
+      {
+         if(simplex2(d_)) {
+
+            //std::cerr << "Simplex2 success." << std::endl;
+            while(simplex_.size() > numPoints_){
+               simplex_.pop_back();
+               supportA_.pop_back();
+               supportB_.pop_back();
+            }
+            return true;
+         }
+      }
+         break;
+
+      case 3:
+      {
+         if(simplex3(d_)) {
+            //std::cerr << "Simplex3 success." << std::endl;
+            while(simplex_.size() > numPoints_){
+               simplex_.pop_back();
+               supportA_.pop_back();
+               supportB_.pop_back();
+            }
+            return true;
+         }
+      }
+         break;
+
+      case 4:
+      {
+         if(simplex4(d_)) {
+            //std::cerr << "Simplex4 success." << std::endl;
+            return true;
+         }
+      }
+         break;
+
+      default:
+      {
+         //std::cerr << "numPoints_="<< numPoints_ <<std::endl;
+         WALBERLA_ABORT( "Number of points in the simplex is not 1<=n<=4" );
+      }
+         break;
+      }
+   }
+
+   return false; //never reach this point
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*!\brief Calculate clostes Point in the simplex and its distance to the origin.
+ */
+inline real_t GJK::calcDistance( Vec3& normal, Vec3& contactPoint )
+{
+   //find the point in the simplex closest to the origin#
+   //its distance to the origin is the distance of the two objects
+   real_t dist= 0.0;
+
+   real_t barCoords[3] = { 0.0, 0.0, 0.0};
+   real_t& u = barCoords[0];
+   real_t& v = barCoords[1];
+   real_t& w = barCoords[2];
+
+   Vec3& A = simplex_[0];
+   Vec3& B = simplex_[1];
+   Vec3& C = simplex_[2];
+   //std::cerr << (int) numPoints_ << " " << A << B << C << std::endl;
+   switch(numPoints_){
+   case 1:
+   {
+      //the only point in simplex is closest to Origin
+      dist = std::sqrt(A.sqrLength());
+      u = real_t(1.0);
+      break;
+   }
+   case 2:
+   {
+      //calc distance Origin to line segment
+      //it is definitively closest do the segment not to one of the end points
+      //as the voronoi regions of the points also consist of the border borderline between
+      //point region and segment region
+      // compare "Real-Time Collision Detection" by Christer Ericson page 129ff
+      Vec3 ab = B - A;
+      //Vec3 ac = -A;
+      //Vec3 bc = -simplex[1];
+
+      //calc baryzenctric coordinats
+      // compare "Real-Time Collision Detection" by Christer Ericson page 129
+      //double t = ac*ab;
+      real_t t     = real_t(-1.0) * (A * ab);
+      real_t denom = std::sqrt(ab.sqrLength());
+      u = t / denom;
+      v = real_t(1.0) - u;
+      Vec3 closestPoint = u*A + v*B;
+      dist = std::sqrt(closestPoint.sqrLength());
+      // compare "Real-Time Collision Detection" by Christer Ericson page 130
+      //double& e = t;
+      //double& f = denom;
+      //dist = ac.sqrLength() -  e*e/f;
+      break;
+   }
+   case 3:
+   {
+      //origin is surly in the voronoi region of the face itself
+      //not the bordering lines or one of the 3 points
+      //to be more precise it is also in normal direction.
+      // compare "Real-Time Collision Detection" by Christer Ericson page 139
+      //TODO: evlt kann man das berechnen ohne den projektionspunkt zu bestimmen
+
+      //Vec3 ab= B - A;
+      //Vec3 ac= C - A;
+      //Vec3 bc= C - B;
+      Vec3& n = d_; //we already know the normal
+      Vec3  nT = n;
+
+      real_t vc = nT * (A % B);
+      real_t va = nT * (B % C);
+      real_t vb = nT * (C % A);
+      real_t denom = real_t(1.0) / (va + vb + vc);
+      u = va * denom;
+      v = vb * denom;
+      w = real_t(1.0) - u - v;
+      //std::cerr << u << " " << v << " " << w << std::endl;
+      Vec3 closestPoint = u*A + v*B + w*C;
+      dist = std::sqrt(closestPoint.sqrLength());
+
+      break;
+   }
+   default:
+   {
+      std::cout << "falsche anzahl an Punkten im simplex" <<std::endl;
+      break;
+   }
+   }
+
+   Vec3 pointOnA = u * supportA_[0];
+   Vec3 pointOnB = u * supportB_[0];
+   for( size_t i = 1; i < numPoints_; ++i) {
+      pointOnA += barCoords[i] * supportA_[i];
+      pointOnB += barCoords[i] * supportB_[i];
+   }
+
+   normal = (pointOnA - pointOnB).getNormalized();
+   contactPoint = (pointOnA + pointOnB) * real_t(0.5);
+
+
+   return dist;
+}
+//*************************************************************************************************
+
+
+
+//=================================================================================================
+//
+//  UTILITY FUNCTIONS
+//
+//=================================================================================================
+
+//*************************************************************************************************
+/*! \brief Process a simplex with two nodes.
+ */
+bool GJK::simplex2(Vec3& d)
+{
+   //the simplex is a line
+   const Vec3& A = simplex_[1];  //The Point last added to the simplex
+   const Vec3& B = simplex_[0];  //The Point that was already in the simplex
+   const Vec3  AO  = -A;         //The vector A->O with 0 the origin
+   const Vec3  AOt = AO;         //The transposed vector A->O with O the origin
+   const Vec3  AB  = B-A;        //The vector A->B
+
+   if( sameDirection(AOt, AB) ) {
+      //The origin O is in the same direction as B is so the line AB is closest to the origin
+      //=> keep A and B in the simplex
+      d = AB % AO % AB;
+   }
+   else {
+      //The origin is not in the direction of B seen from A.
+      //So O lies in the voronoi region of A
+      //=> simplex is just A
+      simplex_[0] = A; //aka simplex_[1]
+      supportA_[0] = supportA_[1];
+      supportB_[0] = supportB_[1];
+      numPoints_  = 1;
+      d = AO;
+   }
+
+   //if the new search direction has zero length
+   //than the origin is on the simplex
+   if(zeroLengthVector(d)) {
+      d_ = Vec3(real_t(0.0),real_t(0.6),real_t(0.8)); // give the GJK a chance to rerun
+      return true;
+   }
+   return false;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Process a simplex with three nodes.
+ */
+bool GJK::simplex3(Vec3& d)
+{
+   //the simplex is a triangle
+   const Vec3& A = simplex_[2];  //The Point last added to the simplex
+   const Vec3& B = simplex_[1];  //One Point that was already in the simplex
+   const Vec3& C = simplex_[0];  //One Point that was already in the simplex
+   //ABC is a conterclockwise triangle
+
+   const Vec3  AO  = -A;        //The vector A->O with 0 the origin
+   const Vec3  AOt = AO;        //The transposed vector A->O with O the origin
+   const Vec3  AB  = B-A;       //The vector A->B
+   const Vec3  AC  = C-A;       //The vector A->C
+   const Vec3  ABC = AB%AC;     //The the normal pointing towards the viewer if he sees a CCW triangle ABC
+
+   if( sameDirection(AOt, (AB % ABC)) ) {
+      //Origin is on the outside of the triangle of the line AB
+      if( AOt * AB > 0.0) {
+         //Origin in the voronoi region of AB outside the triangle
+         //=> AB is the new simplex
+         simplex_[0] = B; //aka simplex_[1]
+         simplex_[1] = A; //aka simplex_[2]
+         supportA_[0] = supportA_[1];
+         supportA_[1] = supportA_[2];
+         supportB_[0] = supportB_[1];
+         supportB_[1] = supportB_[2];
+         numPoints_  = 2;
+         d = AB % AO % AB;
+
+
+      }
+      else {
+         //STAR
+         if( sameDirection(AOt,AC) ) {
+            //Origin is on a subspace of the voronio region of AC
+            //=> AC is the new simplex
+            //simplex_[0] = C; //aka simplex_[0] already there
+            simplex_[1] = A; //aka simplex_[2]
+            supportA_[1] = supportA_[2];
+            supportB_[1] = supportB_[2];
+            numPoints_  = 2;
+            d = AC % AO % AC;
+         }
+         else {
+            //Origin is in the voronio region of A
+            //=> A is the new simplex
+            simplex_[0] = A; //aka simplex_[2]
+            supportA_[0] = supportA_[2];
+            supportB_[0] = supportB_[2];
+            numPoints_  = 1;
+            d = AO;
+         }
+      }
+   }
+   else {
+      if( sameDirection(AOt, (ABC % AC)) ) {
+         //Origin is on the outside of the triangle of the line AC
+         //STAR
+         if( AOt * AC > 0.0) {
+            //Origin is on a subspace of the voronio region of AC
+            //=> AC is the new simplex
+            //simplex_[0] = C; //aka simplex_[0] already there
+            simplex_[1] = A; //aka simplex_[2]
+            supportA_[1] = supportA_[2];
+            supportB_[1] = supportB_[2];
+            numPoints_  = 2;
+            d = AC % AO % AC;
+         }
+         else {
+            //Origin is in the voronio region of A
+            //=> A is the new simplex
+            simplex_[0] = A; //aka simplex_[2]
+            supportA_[0] = supportA_[2];
+            supportB_[0] = supportB_[2];
+            numPoints_  = 1;
+            d = AO;
+         }
+      }
+      else {
+         //origin is above or below the triangle ABC but its mapping on the plane ABC lies within ABC
+         if( sameDirection(AOt, ABC) ) {
+            //Origin is above the triangle
+            //=>Keep triangle as simplex seen from the origin it is already CCW
+            d = ABC;
+         }
+         else {
+            if( sameDirection(AOt, -ABC) ) {
+               //Origin is below the triangle
+               //=>Keep triangle as simplex.
+               //seen from the origin ABC is CW so change the winding
+               Vec3 temp = B; //aka simplex_[1]
+               simplex_[1] = C; //aka simplex_[0]
+               simplex_[0] = temp;
+               //simplex_[2] = A; //aka simplex_[2] already there
+               //old simplex 2:A 1:B 0:C
+               //simplex now contains 2:A 1:C 0:B
+
+               temp = supportA_[1];
+               supportA_[1] = supportA_[0];
+               supportA_[0] = temp;
+               temp = supportB_[1];
+               supportB_[1] = supportB_[0];
+               supportB_[0] = temp;
+
+               d = -ABC;
+            }
+            else{
+               //Origin lies in the triangle
+               return true;
+            }
+         }
+      }
+   }
+
+   //if the new search direction has zero length
+   //than the origin is on the boundary of the simplex
+   if(zeroLengthVector(d)) {
+      d_ = Vec3(real_t(0.0),real_t(0.6),real_t(0.8)); // give the GJK a chance to rerun
+      return true;
+   }
+   return false;
+}
+//*************************************************************************************************
+
+
+//*************************************************************************************************
+/*! \brief Process a simplex with four nodes.
+ */
+bool GJK::simplex4(Vec3& d)
+{
+   //the simplex is a tetrahedron
+   const Vec3& A  = simplex_[3];  //The Point last added to the tetrahedron
+   //t in front mens just a temp varialble
+   const Vec3& B = simplex_[2];  //One Point that was already in the simplex
+   const Vec3& C = simplex_[1];  //One Point that was already in the simplex
+   const Vec3& D = simplex_[0];
+   //BCD is a clockwise triangle wenn seen from A
+
+   const Vec3  AO  = -A;      //The vector A->O with 0 the origin
+   const Vec3  AOt = AO;      //The transposed vector A->O with O the origin
+   const Vec3  AB  = B-A;     //The vector A->B
+   const Vec3  AC  = C-A;     //The vector A->C
+   const Vec3  AD  = D-A;     //The vector A-D
+
+   //https://mollyrocket.com/forums/viewtopic.php?p=1829#1829
+   unsigned char testWhere = 0;
+
+   const Vec3 ABC = AB % AC; //The the normal pointing out of the tetrahedron towards the viewer if he sees a CCW triangle ABC
+   const Vec3 ACD = AC % AD; //The the normal pointing out of the tetrahedron towards the viewer if he sees a CCW triangle ACD
+   const Vec3 ADB = AD % AB; //The the normal pointing out of the tetrahedron towards the viewer if he sees a CCW triangle ADB
+
+   if(sameDirection(AOt, ABC)) {
+      testWhere |= 0x1;
+   }
+
+   if(sameDirection(AOt, ACD)) {
+      testWhere |= 0x2;
+   }
+
+   if(sameDirection(AOt, ADB)) {
+      testWhere |= 0x4;
+   }
+
+   switch(testWhere)
+   {
+   case 0:
+   {
+      //origin is in the tetrahedro
+      //=> the two triangle mashes overlap
+      //std::cout << "Origin is within the tetrahedron\nA=" << A << " B=" << B << " C="<< C << " D="<< D << std::endl;
+      return true;
+   } break;
+
+   case 1:
+   {
+      // In front of ABC only
+      //Origin is outside the tetrahedron above ABC
+      //=> rearrange simplex to use the triangle case
+      simplex_[0] = C;  //aka simplex_[1] 0:C
+      simplex_[1] = B;  //aka simplex_[2] 1:B
+      simplex_[2] = A;  //aka simplex_[3] 2:A
+
+      supportA_[0] = supportA_[1];
+      supportA_[1] = supportA_[2];
+      supportA_[2] = supportA_[3];
+      supportB_[0] = supportB_[1];
+      supportB_[1] = supportB_[2];
+      supportB_[2] = supportB_[3];
+
+      numPoints_ = 3;
+
+      return simplex3(d);
+   } break;
+
+   case 2:
+   {
+      // In front of ACD only
+      //Origin is outside the tetrahedron above ACD
+      //=> rearrange simplex to use the triangle case
+      //simplex_[0] = D; //aka simplex_[0] 0:D already the case
+      //simplex_[1] = C; //aka simplex_[1] 1:C already the case
+      simplex_[2] = A;   //aka simplex_[3] 2:A
+
+      supportA_[2] = supportA_[3];
+      supportB_[2] = supportB_[3];
+
+      numPoints_ = 3;
+
+      return simplex3(d);
+   } break;
+
+   case 4:
+   {
+      // In front of ADB only
+      //Origin is outside the tetrahedron above ADB
+      //=> rearrange simplex to use the triangle case
+      simplex_[1] = D; //aka simplex_[0] 1:D
+      simplex_[0] = B; //aka simplex_[2] 0:B already there
+      simplex_[2] = A; //aka simplex_[3] 2:A
+
+      supportA_[1] = supportA_[0];
+      supportA_[0] = supportA_[2];
+      supportA_[2] = supportA_[3];
+      supportB_[1] = supportB_[0];
+      supportB_[0] = supportB_[2];
+      supportB_[2] = supportB_[3];
+
+      numPoints_ = 3;
+
+      return simplex3(d);
+   } break;
+
+   case 3:
+   {
+      // In front of ABC and ACD
+      if(sameDirection(AOt, ABC%AC)) {
+         if(sameDirection(AOt, AC%ACD)) {
+            if(sameDirection(AOt, AC)) {
+               //AddEdgeSimplex(A, C);
+               simplex_[0] = C; //aka simplex_[1] 0:C
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[0] = supportA_[1];
+               supportA_[1] = supportA_[3];
+               supportB_[0] = supportB_[1];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AC % AO % AC;
+            }
+            else {
+               //AddPointSimplex;
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+         else
+         {
+            if(sameDirection(AOt, ACD%AD)) {
+               //AddEdgeSimplex(A, D);
+               //simplex_[0] = D; //aka simplex_[0] 0:D already there
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[1] = supportA_[3];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AD % AO % AD;
+            }
+            else {
+               //AddTriangleSimplex(A, C, D);
+               //simplex_[0] = D; //aka simplex_[0] 0:D already there
+               //simplex_[1] = C; //aka simplex_[1] 1:C already there
+               simplex_[2] = A; //aka simplex_[3] 2:A
+
+               supportA_[2] = supportA_[3];
+               supportB_[2] = supportB_[3];
+
+               numPoints_ = 3;
+               d = ACD;
+            }
+         }
+      }
+      else
+      {
+         if(sameDirection(AOt, AB%ABC)) {
+            if(sameDirection(AOt, AB)) {
+               //AddEdgeSimplex(A, B);
+               simplex_[0] = B; //aka simplex_[2] 0:B
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[0] = supportA_[2];
+               supportA_[1] = supportA_[3];
+               supportB_[0] = supportB_[2];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AB % AO % AB;
+            }
+            else {
+               //AddPointSimplex;
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+         else {
+            //AddTriangleSimplex(A, B, C);
+            simplex_[0] = C; //aka simplex_[1] 0:C
+            simplex_[1] = B; //aka simplex_[2] 1:B
+            simplex_[2] = A; //aka simplex_[3] 2:A
+
+            supportA_[0] = supportA_[1];
+            supportA_[1] = supportA_[2];
+            supportA_[2] = supportA_[3];
+            supportB_[0] = supportB_[1];
+            supportB_[1] = supportB_[2];
+            supportB_[2] = supportB_[3];
+
+            numPoints_ = 3;
+            d = ABC;
+         }
+      }
+   } break;
+
+
+   case 5:
+   {
+      // In front of ADB and ABC
+      if(sameDirection(AOt, ADB%AB)) {
+         if(sameDirection(AOt, AB%ABC)) {
+            if(sameDirection(AOt, AB)) {
+               //AddEdgeSimplex(A, B);
+               simplex_[0] = B; //aka simplex_[2] 0:B
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[0] = supportA_[2];
+               supportA_[1] = supportA_[3];
+               supportB_[0] = supportB_[2];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AB % AO % AB;
+            }
+            else {
+               //AddPointSimplex;
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+         else
+         {
+            if(sameDirection(AOt, ABC%AC)) {
+               //AddEdgeSimplex(A, C);
+               simplex_[0] = C; //aka simplex_[1] 0:C
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[0] = supportA_[1];
+               supportA_[1] = supportA_[3];
+               supportB_[0] = supportB_[1];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AC % AO % AC;
+            }
+            else {
+               //AddTriangleSimplex(A, B, C);
+               simplex_[0] = C; //aka simplex_[1] 0:C
+               simplex_[1] = B; //aka simplex_[2] 1:B
+               simplex_[2] = A; //aka simplex_[3] 2:A
+
+               supportA_[0] = supportA_[1];
+               supportA_[1] = supportA_[2];
+               supportA_[2] = supportA_[3];
+               supportB_[0] = supportB_[1];
+               supportB_[1] = supportB_[2];
+               supportB_[2] = supportB_[3];
+
+               numPoints_ = 3;
+               d = ABC;
+            }
+         }
+      }
+      else
+      {
+         if(sameDirection(AOt, AD%ADB)) {
+            if(sameDirection(AOt, AD)) {
+               //AddEdgeSimplex(A, D);
+               //simplex_[0] = D; //aka simplex_[0] 0:D already there
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[1] = supportA_[3];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AD % AO % AD;
+            }
+            else {
+               //AddPointSimplex;
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+         else {
+            //AddTriangleSimplex(A, D, B);
+            simplex_[1] = D; //aka simplex[0] 1:D
+            simplex_[0] = B; //aka simplex[2] 0:B
+            simplex_[2] = A;  //aka simplex[3] 2:A
+
+            supportA_[1] = supportA_[0];
+            supportA_[0] = supportA_[2];
+            supportA_[2] = supportA_[3];
+            supportB_[1] = supportB_[0];
+            supportB_[0] = supportB_[2];
+            supportB_[2] = supportB_[3];
+
+            numPoints_  = 3;
+
+            numPoints_ = 3;
+            d = ADB;
+         }
+      }
+   } break;
+
+   case 6:
+   {
+      // In front of ACD and ADB
+      if(sameDirection(AOt, ACD%AD)) {
+         if(sameDirection(AOt, AD%ADB)) {
+            if(sameDirection(AOt, AD)) {
+               //AddEdgeSimplex(A, D);
+               //simplex_[0] = D; //aka simplex_[0] 0:D already there
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[1] = supportA_[3];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AD % AO % AD;
+            }
+            else {
+               //AddPointSimplex;
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+         else
+         {
+            if(sameDirection(AOt, ADB%AB)) {
+               //AddEdgeSimplex(A, B);
+               simplex_[0] = B; //aka simplex_[2] 0:B
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[0] = supportA_[2];
+               supportA_[1] = supportA_[3];
+               supportB_[0] = supportB_[2];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AB % AO % AB;
+            }
+            else {
+               //AddTriangleSimplex(A, D, B);
+               simplex_[1] = D; //aka simplex[0] 1:D
+               simplex_[0] = B; //aka simplex[2] 0:B
+               simplex_[2] = A;  //aka simplex[3] 2:A
+
+               supportA_[1] = supportA_[0];
+               supportA_[0] = supportA_[2];
+               supportA_[2] = supportA_[3];
+               supportB_[1] = supportB_[0];
+               supportB_[0] = supportB_[2];
+               supportB_[2] = supportB_[3];
+
+               numPoints_  = 3;
+
+               numPoints_ = 3;
+               d = ADB;
+            }
+         }
+      }
+      else
+      {
+         if(sameDirection(AOt, AC%ACD)) {
+            if(sameDirection(AOt, AC)) {
+               //AddEdgeSimplex(A, C);
+               simplex_[0] = C; //aka simplex_[1] 0:C
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[0] = supportA_[1];
+               supportA_[1] = supportA_[3];
+               supportB_[0] = supportB_[1];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AC % AO % AC;
+            }
+            else
+            {
+               //AddPointSimplex;
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+         else
+         {
+            //AddTriangleSimplex(A, C, D);
+            //simplex_[0] = D; //aka simplex_[0] 0:D already there
+            //simplex_[1] = C; //aka simplex_[1] 1:C already there
+            simplex_[2] = A; //aka simplex_[3] 2:A
+
+            supportA_[2] = supportA_[3];
+            supportB_[2] = supportB_[3];
+
+            numPoints_ = 3;
+            d = ACD;
+         }
+      }
+   } break;
+
+   case 7:
+   {
+      // In front of ABC, ACD and ADB
+      if(sameDirection(AOt, AB)) {
+         simplex_[0] = B; //aka simplex_[2] 0:B
+         simplex_[1] = A; //aka simplex_[3] 1:A
+
+         supportA_[0] = supportA_[2];
+         supportA_[1] = supportA_[3];
+         supportB_[0] = supportB_[2];
+         supportB_[1] = supportB_[3];
+
+         numPoints_ = 2;
+         d = AB % AO % AB;
+      }
+      else
+      {
+         if(sameDirection(AOt, AC)) {
+            simplex_[0] = C; //aka simplex_[1] 0:C
+            simplex_[1] = A; //aka simplex_[3] 1:A
+
+            supportA_[0] = supportA_[1];
+            supportA_[1] = supportA_[3];
+            supportB_[0] = supportB_[1];
+            supportB_[1] = supportB_[3];
+
+            numPoints_ = 2;
+            d = AC % AO % AC;
+
+         }
+         else
+         {
+            if(sameDirection(AOt, AD)) {
+               //simplex_[0] = D; //aka simplex_[1] 0:D already there
+               simplex_[1] = A; //aka simplex_[3] 1:A
+
+               supportA_[1] = supportA_[3];
+               supportB_[1] = supportB_[3];
+
+               numPoints_ = 2;
+               d = AD % AO % AD;
+            }
+            else {
+               simplex_[0] = A; //aka simplex_[3] 0:A
+
+               supportA_[0] = supportA_[3];
+               supportB_[0] = supportB_[3];
+
+               numPoints_ = 1;
+               d = AO;
+            }
+         }
+      }
+   } break;
+   default:
+   {
+      //all 8 cases 0-7 are covered
+   } break;
+   }
+
+   return false;
+}
+//*************************************************************************************************
+
+} //fcd
+} //pe
+} //walberla
diff --git a/src/pe/fcd/IterativeFCD.h b/src/pe/fcd/IterativeFCD.h
index 5634f8bb6..61c2195c3 100644
--- a/src/pe/fcd/IterativeFCD.h
+++ b/src/pe/fcd/IterativeFCD.h
@@ -64,7 +64,7 @@ private:
    bool performIterativeDetection(GeomPrimitive &a, GeomPrimitive &b, Vec3& normal, Vec3& contactPoint, real_t& penetrationDepth){
       real_t margin = real_t(1e-4);
       GJK gjk;
-      if(gjk.doGJKcontactThreshold(a, b, margin)){
+      if(gjk.doGJKmargin(a, b, margin)){
          //2. If collision is possible perform EPA.
          EPA epa;
          return epa.doEPAmargin(a, b, gjk, normal, contactPoint, penetrationDepth, margin);
diff --git a/tests/pe/CollisionTobiasGJK.cpp b/tests/pe/CollisionTobiasGJK.cpp
index 9eeae6d64..3ce9c22fc 100644
--- a/tests/pe/CollisionTobiasGJK.cpp
+++ b/tests/pe/CollisionTobiasGJK.cpp
@@ -58,7 +58,7 @@ bool gjkEPAcollideHybrid(GeomPrimitive &geom1, GeomPrimitive &geom2, Vec3& norma
    //1. Run GJK with considerably enlarged objects.
    real_t margin = real_t(1e-4);
    GJK gjk;
-   if(gjk.doGJKcontactThreshold(geom1, geom2, margin)){
+   if(gjk.doGJKmargin(geom1, geom2, margin)){
       //2. If collision is possible perform EPA.
       //std::cerr << "Peforming EPA.";
       EPA epa;
-- 
GitLab