diff --git a/idl/hpp/corbaserver/rbprm/rbprmbuilder.idl b/idl/hpp/corbaserver/rbprm/rbprmbuilder.idl
index 5baed51b0af5d58eea245c5ae41c639acd0c6618..42ddf5ec84b5a3d5ec064f55b05645873e27a853 100644
--- a/idl/hpp/corbaserver/rbprm/rbprmbuilder.idl
+++ b/idl/hpp/corbaserver/rbprm/rbprmbuilder.idl
@@ -737,11 +737,16 @@ module hpp
     Names_t getContactsVariations(in unsigned short stateIdFrom,in unsigned short stateIdTo) raises (Error);
 
 
-    /// For a given limb, returns all the contact surfaces in collision with the limb's reachable workspace
+    /// For a given limb, returns the names of all the contact surfaces in collisions with the limb's reachable workspace
     /// \param configuration : root configuration
     /// \param limbName : name of the considered limb
     Names_t getCollidingObstacleAtConfig(in floatSeq configuration,in string limbName) raises (Error);
 
+    /// For a given limb, return all the intersections between the limb reachable workspace and a contact surface
+    /// \param configuration : root configuration
+    /// \param limbName : name of the considered limb
+    floatSeqSeq getContactSurfacesAtConfig(in floatSeq configuration,in string limbName) raises (Error);
+
     /// return a list of all the limbs names
     Names_t getAllLimbsNames() raises (Error);
     /// tries to add a new contact to the state
diff --git a/src/hpp/corbaserver/rbprm/rbprmbuilder.py b/src/hpp/corbaserver/rbprm/rbprmbuilder.py
index 9b6308ffca4604dbc22b7bd0711cd99eabb9bf84..1984763e48297dd6a6b3afe7a6570e4898d67399 100755
--- a/src/hpp/corbaserver/rbprm/rbprmbuilder.py
+++ b/src/hpp/corbaserver/rbprm/rbprmbuilder.py
@@ -103,3 +103,14 @@ class Builder (Robot):
   # \param ref the 3D reference position of the end effector, expressed in the root frame
   def setReferenceEndEffector(self,romName,ref):
     return self.clientRbprm.rbprm.setReferenceEndEffector(romName,ref)
+
+  ## For a given limb, return all the intersections between the limb reachable workspace and a contact surface
+  # \param configuration the root configuration
+  # \param limbName name of the considered limb
+  # \return a 3D list : first id is the different surfaces, second id is the different vertex of a surface, last id is the 3 coordinate of each vertex
+  def getContactSurfacesAtConfig(self,configuration,limbName):
+    surfaces = self.clientRbprm.rbprm.getContactSurfacesAtConfig(configuration,limbName)
+    res = []
+    for surface in surfaces:
+        res += [[surface[i:i+3] for i in range(0, len(surface),3)]] # split list of coordinate every 3 points (3D points)
+    return res
diff --git a/src/rbprmbuilder.impl.cc b/src/rbprmbuilder.impl.cc
index b08d542c199a0269ca3f347ea6a48a331fad7ff3..314c953875afd701112627d7f22903bb171ad4dd 100644
--- a/src/rbprmbuilder.impl.cc
+++ b/src/rbprmbuilder.impl.cc
@@ -50,6 +50,8 @@
 #include <hpp/rbprm/sampling/heuristic-tools.hh>
 #include <hpp/rbprm/contact_generation/reachability.hh>
 #include <hpp/pinocchio/urdf/util.hh>
+#include "hpp/rbprm/utils/algorithms.h"
+
 #ifdef PROFILE
     #include "hpp/rbprm/rbprm-profiler.hh"
 #endif
@@ -1508,6 +1510,78 @@ namespace hpp {
       }
     }
 
+      floatSeqSeq* RbprmBuilder::getContactSurfacesAtConfig(const ::hpp::floatSeq& configuration,const char* limbName)throw (hpp::Error){
+      try
+      {
+          hppDout(notice,"begin getContactSurfacesAtConfig");
+          std::string name (limbName);
+          //hpp::pinocchio::RbPrmDevicePtr_t rbprmDevice = boost::dynamic_pointer_cast<hpp::pinocchio::RbPrmDevice>(problemSolver()->robot ());
+          const hpp::pinocchio::DevicePtr_t romDevice = romDevices_[name];
+          pinocchio::Configuration_t q = dofArrayToConfig(romDevice, configuration);
+          romDevice->currentConfiguration(q);
+          RbPrmPathValidationPtr_t rbprmPathValidation_ (boost::dynamic_pointer_cast<hpp::rbprm::RbPrmPathValidation>(problemSolver()->problem()->pathValidation()));
+          rbprmPathValidation_->getValidator()->computeAllContacts(true);
+          core::ValidationReportPtr_t report;
+          hppDout(notice,"begin collision check");
+          problemSolver()->problem()->configValidations()->validate(q,report);
+          hppDout(notice,"done.");
+          core::RbprmValidationReportPtr_t rbReport = boost::dynamic_pointer_cast<hpp::core::RbprmValidationReport> (report);
+          hppDout(notice,"try to find rom name");
+          if(rbReport->ROMReports.find(name) == rbReport->ROMReports.end()){
+            throw std::runtime_error ("The given ROM name is not in collision in the given configuration.");
+          }
+          hppDout(notice,"try to cast report");
+          core::AllCollisionsValidationReportPtr_t romReports = boost::dynamic_pointer_cast<core::AllCollisionsValidationReport>(rbReport->ROMReports.at(name));
+          if(!romReports){
+            throw std::runtime_error ("Error while retrieving collision reports.");
+          }
+          hppDout(notice,"try deviceSync");
+          pinocchio::DeviceSync deviceSync (romDevice);
+          hppDout(notice,"done.");
+          hpp::floatSeqSeq *res;
+          res = new hpp::floatSeqSeq ();
+          res->length ((_CORBA_ULong)romReports->collisionReports.size());
+          std::size_t idSurface=0;
+          geom::Point pn;
+          hppDout(notice,"Number of collision reports for the rom : "<<romReports->collisionReports.size());
+          // for all collision report of the given ROM, compute the intersection surface between the affordance object and the rom :
+          for(std::vector<CollisionValidationReportPtr_t>::const_iterator itReport = romReports->collisionReports.begin() ; itReport != romReports->collisionReports.end() ; ++itReport){
+            // compute the intersection for itReport :
+            core::CollisionObjectConstPtr_t obj_rom = (*itReport)->object1;
+            core::CollisionObjectConstPtr_t obj_env = (*itReport)->object2;
+            // convert the two objects  :
+            geom::BVHModelOBConst_Ptr_t model_rom =  geom::GetModel(obj_rom,deviceSync.d());
+            geom::BVHModelOBConst_Ptr_t model_env =  geom::GetModel(obj_env,deviceSync.d());
+            geom::T_Point plane = geom::intersectPolygonePlane(model_rom,model_env,pn);
+            // plane contains a list of points : the intersections between model_rom and the infinite plane defined by model_env.
+            // but they may not be contained inside the shape defined by model_env
+            if(plane.size() > 0){
+              geom::T_Point inter = geom::compute3DIntersection(plane,geom::convertBVH(model_env)); // hull contain only points inside the model_env shape
+              if(inter.size() > 0){
+                hppDout(notice,"Number of points for the intersection rom/surface : "<<inter.size());
+                // add inter points to res list:
+                _CORBA_ULong size = (_CORBA_ULong) (inter.size()*3);
+                double* dofArray = hpp::floatSeq::allocbuf(size);
+                hpp::floatSeq floats (size, size, dofArray, true);
+                //convert the config in dofseq
+                for (pinocchio::size_type j=0 ; j < (pinocchio::size_type)inter.size() ; ++j) {
+                  dofArray[3*j] = inter[j][0];
+                  dofArray[3*j+1] = inter[j][1];
+                  dofArray[3*j+2] = inter[j][2];
+                }
+                (*res) [(_CORBA_ULong)idSurface] = floats;
+                ++idSurface;
+              }
+            }
+          }
+          return res;
+      }
+      catch(std::runtime_error& e)
+      {
+          throw Error(e.what());
+      }
+    }
+
     std::vector<State> TimeStatesToStates(const T_StateFrame& ref)
     {
         std::vector<State> res;
diff --git a/src/rbprmbuilder.impl.hh b/src/rbprmbuilder.impl.hh
index 2116a55e9d9005fe9e1de0b038c73069e0102f41..a10049d3fed11f8ffd1bb7ff0e133d89d31f4eb3 100644
--- a/src/rbprmbuilder.impl.hh
+++ b/src/rbprmbuilder.impl.hh
@@ -348,6 +348,8 @@ namespace hpp {
         virtual double getTimeAtState(unsigned short stateId)throw (hpp::Error);
         virtual Names_t* getContactsVariations(unsigned short stateIdFrom,unsigned short stateIdTo )throw (hpp::Error);        
         virtual Names_t* getCollidingObstacleAtConfig(const ::hpp::floatSeq& configuration,const char* limbName)throw (hpp::Error);
+        virtual floatSeqSeq* getContactSurfacesAtConfig(const ::hpp::floatSeq& configuration,const char* limbName)throw (hpp::Error);
+
         virtual Names_t* getAllLimbsNames()throw (hpp::Error);
         virtual CORBA::Short addNewContact(unsigned short stateId, const char* limbName,
                                             const hpp::floatSeq& position, const hpp::floatSeq& normal, unsigned short max_num_sample, bool lockOtherJoints) throw (hpp::Error);