Salome HOME
bos #29468: Advanced geometry features: distance Edge-Edge & Face-Face
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IMeasureOperations.cxx
index ebb5d83d3b0ff0d85eb2a95d40643d3d96841829..7bfc35b5f19243ae780e2a1823a8ec67b8d441a0 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 #include <GEOMImpl_IMeasureOperations.hxx>
 #include <GEOMImpl_IMeasure.hxx>
 #include <GEOMImpl_MeasureDriver.hxx>
+
+#include <GEOMImpl_IPatchFace.hxx>
+#include <GEOMImpl_IProximity.hxx>
+#include <GEOMImpl_PatchFaceDriver.hxx>
+#include <GEOMImpl_ShapeProximityDriver.hxx>
+
 #include <GEOMImpl_Types.hxx>
 
+#include <GEOMImpl_IConformity.hxx>
+#include <GEOMImpl_ConformityDriver.hxx>
+
 #include <GEOMUtils.hxx>
 
 #include <GEOMAlgo_AlgoTools.hxx>
@@ -42,6 +51,7 @@
 #include <BOPDS_DS.hxx>
 #include <BOPDS_MapOfPair.hxx>
 #include <BOPDS_Pair.hxx>
+#include <BOPTools_AlgoTools.hxx>
 #include <BRepBndLib.hxx>
 #include <BRepBuilderAPI_Copy.hxx>
 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
@@ -179,7 +189,7 @@ GEOMImpl_IMeasureOperations::ShapeKind GEOMImpl_IMeasureOperations::KindOfShape
     return SK_LCS;
   }
 
-  // Interprete results
+  // Interpret results
   TopAbs_ShapeEnum aType = anInfo.Type();
   switch (aType)
   {
@@ -850,7 +860,8 @@ Handle(GEOM_Object) GEOMImpl_IMeasureOperations::GetCentreOfMass
 //=============================================================================
 Handle(GEOM_Object) GEOMImpl_IMeasureOperations::GetVertexByIndex
                                                 (Handle(GEOM_Object) theShape,
-                                                 Standard_Integer theIndex)
+                                                 Standard_Integer theIndex,
+                                                 Standard_Boolean theUseOri)
 {
   SetErrorCode(KO);
 
@@ -873,6 +884,7 @@ Handle(GEOM_Object) GEOMImpl_IMeasureOperations::GetVertexByIndex
   GEOMImpl_IMeasure aCI (aFunction);
   aCI.SetBase(aRefShape);
   aCI.SetIndex(theIndex);
+  aCI.SetUseOri(theUseOri);
 
   //Compute
   try {
@@ -888,7 +900,10 @@ Handle(GEOM_Object) GEOMImpl_IMeasureOperations::GetVertexByIndex
   }
 
   //Make a Python command
-  GEOM::TPythonDump(aFunction) << aVertex << " = geompy.GetVertexByIndex(" << theShape << ", " << theIndex << ")";
+  GEOM::TPythonDump(aFunction) << aVertex << " = geompy.GetVertexByIndex("
+                               << theShape << ", "
+                               << theIndex << ", "
+                               << theUseOri << ")";
 
   SetErrorCode(OK);
   return aVertex;
@@ -2126,21 +2141,9 @@ Standard_Integer GEOMImpl_IMeasureOperations::ClosestPoints (Handle(GEOM_Object)
 
     // skl 30.06.2008
     // additional workaround for bugs 19899, 19908 and 19910 from Mantis
-    gp_Pnt P1, P2;
-    double dist = GEOMUtils::GetMinDistanceSingular(aShape1, aShape2, P1, P2);
-    if (dist > -1.0) {
-      nbSolutions = 1;
-
-      theDoubles->Append(P1.X());
-      theDoubles->Append(P1.Y());
-      theDoubles->Append(P1.Z());
-      theDoubles->Append(P2.X());
-      theDoubles->Append(P2.Y());
-      theDoubles->Append(P2.Z());
-
-      SetErrorCode(OK);
-      return nbSolutions;
-    }
+    gp_Pnt P1s, P2s;
+    double dist = GEOMUtils::GetMinDistanceSingular(aShape1, aShape2, P1s, P2s);
+    bool singularBetter = dist >= 0;
 
     BRepExtrema_DistShapeShape dst (aShape1, aShape2);
     if (dst.IsDone()) {
@@ -2151,15 +2154,32 @@ Standard_Integer GEOMImpl_IMeasureOperations::ClosestPoints (Handle(GEOM_Object)
       for (int i = 1; i <= nbSolutions; i++) {
         P1 = dst.PointOnShape1(i);
         P2 = dst.PointOnShape2(i);
-
+        
         theDoubles->Append(P1.X());
         theDoubles->Append(P1.Y());
         theDoubles->Append(P1.Z());
         theDoubles->Append(P2.X());
         theDoubles->Append(P2.Y());
         theDoubles->Append(P2.Z());
+        
+        Standard_Real Dist = P1.Distance(P2);
+        singularBetter = singularBetter && dist < Dist;
       }
     }
+
+    if (singularBetter) {
+      if (theDoubles.IsNull()) theDoubles = new TColStd_HSequenceOfReal;
+      else theDoubles->Clear();
+
+      nbSolutions = 1;
+    
+      theDoubles->Append(P1s.X());
+      theDoubles->Append(P1s.Y());
+      theDoubles->Append(P1s.Z());
+      theDoubles->Append(P2s.X());
+      theDoubles->Append(P2s.Y());
+      theDoubles->Append(P2s.Z());
+    }
   }
   catch (Standard_Failure& aFail) {
     SetErrorCode(aFail.GetMessageString());
@@ -2348,6 +2368,74 @@ Standard_Real GEOMImpl_IMeasureOperations::GetAngleBtwVectors (Handle(GEOM_Objec
 }
 
 
+//=============================================================================
+/*!
+ *  PatchFace
+ */
+ //=============================================================================
+Handle(TColStd_HSequenceOfTransient) GEOMImpl_IMeasureOperations::PatchFace(Handle(GEOM_Object) theShape)
+{
+  SetErrorCode(KO);
+
+  if (theShape.IsNull()) return NULL;
+
+  Handle(GEOM_Object) aPatchFace = GetEngine()->AddObject(GEOM_PATCH_FACE);
+  Handle(GEOM_Function) aFunction = aPatchFace->AddFunction(GEOMImpl_PatchFaceDriver::GetID(), 1);
+  if (aFunction.IsNull()) return NULL;
+
+  //Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_PatchFaceDriver::GetID()) return NULL;
+
+  GEOMImpl_IPatchFace aPI(aFunction);
+  Handle(GEOM_Function) aRefShape = theShape->GetLastFunction();
+  if (aRefShape.IsNull()) return NULL;
+
+  aPI.SetShape(aRefShape);
+  Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
+
+  // Perform
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction))
+    {
+      SetErrorCode("patch face driver failed");
+      return NULL;
+    }
+
+    // Get result compound and collect all faces into result sequence
+    TopoDS_Shape aResCompound = aFunction->GetValue();
+    TopTools_IndexedMapOfShape anIndices;
+    TopExp::MapShapes(aResCompound, anIndices);
+
+    Handle(TColStd_HArray1OfInteger) anArray;
+    for (TopExp_Explorer anExpW(aResCompound, TopAbs_FACE); anExpW.More(); anExpW.Next())
+    {
+      TopoDS_Shape aValue = anExpW.Value();
+      anArray = new TColStd_HArray1OfInteger(1, 1);
+      anArray->SetValue(1, anIndices.FindIndex(aValue));
+
+      Handle(GEOM_Object) anObj = GetEngine()->AddSubShape(aPatchFace, anArray);
+      if (!anObj.IsNull())
+      {
+        aSeq->Append(anObj);
+      }
+    }
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return aSeq;
+  }
+
+  //Make a Python command
+  GEOM::TPythonDump(aFunction, true)
+    << "[" << aSeq << "] = geompy.PatchFace(" << theShape << ")";
+
+  SetErrorCode(OK);
+  return aSeq;
+}
+
 //=============================================================================
 /*!
  *  CurveCurvatureByParam
@@ -2648,6 +2736,396 @@ Standard_Real GEOMImpl_IMeasureOperations::MinSurfaceCurvatureByPoint
   return getSurfaceCurvatures(aSurf, UV.X(), UV.Y(), false);
 }
 
+//=============================================================================
+/*!
+ *  SurfaceCurvatureByPointAndDirection
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IMeasureOperations::SurfaceCurvatureByPointAndDirection
+                                                 (Handle(GEOM_Object) theSurf,
+                                                  Handle(GEOM_Object) thePoint,
+                                                  Handle(GEOM_Object) theDirection)
+{
+  SetErrorCode(KO);
+
+  if (theSurf.IsNull() || thePoint.IsNull() || theDirection.IsNull()) return NULL;
+
+  Handle(GEOM_Function) aSurf = theSurf->GetLastFunction();
+  Handle(GEOM_Function) aPoint = thePoint->GetLastFunction();
+  Handle(GEOM_Function) aDirection = theDirection->GetLastFunction();
+  if (aSurf.IsNull() || aPoint.IsNull() || aDirection.IsNull()) return NULL;
+
+  //Add a new CurvatureVector object
+  //Handle(GEOM_Object) aCV = GetEngine()->AddObject(GEOM_CURVATURE_VEC);
+  Handle(GEOM_Object) aCV = GetEngine()->AddObject(GEOM_VECTOR);
+
+  //Add a new CurvatureVector function
+  Handle(GEOM_Function) aFunction =
+    aCV->AddFunction(GEOMImpl_MeasureDriver::GetID(), CURVATURE_VEC_MEASURE);
+  if (aFunction.IsNull()) return NULL;
+
+  //Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_MeasureDriver::GetID()) return NULL;
+
+  GEOMImpl_IMeasure aCI (aFunction);
+  aCI.SetBase(aSurf);
+  aCI.SetPoint(aPoint);
+  aCI.SetDirection(aDirection);
+
+  //Compute the CurvatureVector
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction)) {
+      SetErrorCode("Measure driver failed to compute a surface curvature");
+      return NULL;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
+  //Make a Python command
+  GEOM::TPythonDump(aFunction) << aCV << " = geompy.CurvatureOnFace(" << theSurf
+                               << ", " << thePoint << ", " << theDirection << ")";
+
+  SetErrorCode(OK);
+  return aCV;
+}
+
+//=============================================================================
+/*!
+ *  SelfIntersected2D
+ *  Find all self-intersected 2D curves.
+ *  \param theChecks list of failed checks, contains type of check and failed shapes
+ */
+ //=============================================================================
+std::list<GEOMImpl_IMeasureOperations::CoupleOfObjects>
+  GEOMImpl_IMeasureOperations::SelfIntersected2D(const std::list<FailedChecks>& theChecks)
+{
+  SetErrorCode(KO);
+  MESSAGE("GEOMImpl_IMeasureOperations::selfIntersected2D");
+
+  std::list<GEOMImpl_IMeasureOperations::CoupleOfObjects> aSelfInters2D;
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    for (std::list<FailedChecks>::const_iterator anIter(theChecks.begin());
+         anIter != theChecks.end(); ++anIter)
+    {
+      if (anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_InvalidCurveOnSurface)
+        aSelfInters2D.push_back(anIter->FailedShapes);
+    }
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return aSelfInters2D;
+  }
+
+  SetErrorCode(OK);
+  return aSelfInters2D;
+}
+
+namespace
+{
+  static bool checkTypes(const GEOMImpl_IMeasureOperations::CoupleOfObjects& theShapes,
+                         const int theShapeType1,
+                         const int theShapeType2)
+  {
+    if (theShapeType1 == -1 && theShapeType2 == -1)
+      return true;
+
+    TopAbs_ShapeEnum aShapeType1 = theShapes.first.IsNull()
+      ? TopAbs_SHAPE
+      : theShapes.first->GetValue().ShapeType();
+    TopAbs_ShapeEnum aShapeType2 = theShapes.second.IsNull()
+      ? TopAbs_SHAPE
+      : theShapes.second->GetValue().ShapeType();
+
+    if (theShapeType1 == -1)
+      return aShapeType1 == theShapeType2 || aShapeType2 == theShapeType2;
+    else if (theShapeType2 == -1)
+      return aShapeType1 == theShapeType1 || aShapeType2 == theShapeType1;
+    return (aShapeType1 == theShapeType1 && aShapeType2 == theShapeType2) ||
+      (aShapeType1 == theShapeType2 && aShapeType2 == theShapeType1);
+  }
+} // namespace
+
+//=============================================================================
+/*!
+ *  InterferingSubshapes
+ *  Find pairs of interfering sub-shapes, by default all pairs of interfering shapes are returned.
+ *  \param theChecks list of failed checks, contains type of check and failed shapes
+ *  \param theShapeType1 Type of shape.
+ *  \param theShapeType2 Type of shape.
+ */
+ //=============================================================================
+std::list<GEOMImpl_IMeasureOperations::CoupleOfObjects>
+  GEOMImpl_IMeasureOperations::InterferingSubshapes
+    (const std::list<FailedChecks>& theChecks,
+     const int                      theShapeType1,
+     const int                      theShapeType2)
+{
+  SetErrorCode(KO);
+  MESSAGE("GEOMImpl_IMeasureOperations::interferingSubshapes");
+
+  std::list<GEOMImpl_IMeasureOperations::CoupleOfObjects> anInterfer;
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    for (std::list<FailedChecks>::const_iterator anIter(theChecks.begin());
+         anIter != theChecks.end(); ++anIter)
+    {
+      if (anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_SelfIntersect &&
+          checkTypes(anIter->FailedShapes, theShapeType1, theShapeType2))
+        anInterfer.push_back(anIter->FailedShapes);
+    }
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return anInterfer;
+  }
+
+  SetErrorCode(OK);
+  return anInterfer;
+}
+
+//=============================================================================
+/*!
+ *  SmallEdges
+ *  Find edges, which are fully covered by tolerances of vertices.
+ *  \param theChecks list of failed checks, contains type of check and failed shapes
+ */
+ //=============================================================================
+Handle(TColStd_HSequenceOfTransient) GEOMImpl_IMeasureOperations::SmallEdges(
+    const std::list<FailedChecks>& theChecks)
+{
+  SetErrorCode(KO);
+  MESSAGE("GEOMImpl_IMeasureOperations::smallEdges");
+
+  Handle(TColStd_HSequenceOfTransient) aSmallEdges = new TColStd_HSequenceOfTransient;
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    for (std::list<FailedChecks>::const_iterator anIter(theChecks.begin());
+         anIter != theChecks.end(); ++anIter)
+    {
+      if (anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_TooSmallEdge)
+        aSmallEdges->Append(anIter->FailedShapes.first);
+    }
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return NULL;
+  }
+
+  SetErrorCode(OK);
+  return aSmallEdges;
+}
+
+//=============================================================================
+/*!
+ *  DistantShapes
+ *  find remote objects (sub-shape on a shape).
+ *  \param theShape Shape for check.
+ *  \param theShapeType Type of shape.
+ *  \param theSubShapeType Type of sub-shape.
+ *  \param theTolerance tolerance.
+ */
+ //=============================================================================
+std::list<GEOMImpl_IMeasureOperations::CoupleOfObjects>
+  GEOMImpl_IMeasureOperations::DistantShapes
+    (const std::list<FailedChecks>& theChecks,
+     const int                      theShapeType,
+     const int                      theSubShapeType,
+     double                         theTolerance)
+{
+  SetErrorCode(KO);
+  MESSAGE("GEOMImpl_IMeasureOperations::distantShapes");
+
+  std::list<GEOMImpl_IMeasureOperations::CoupleOfObjects> aDistShapes;
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    for (std::list<FailedChecks>::const_iterator anIter(theChecks.begin());
+         anIter != theChecks.end(); ++anIter)
+    {
+      Handle(GEOM_Object) aSubShape = anIter->FailedShapes.first;
+      Handle(GEOM_Object) aShape = anIter->FailedShapes.second;
+      if ((anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_InvalidCurveOnSurface ||
+           anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_IncompatibilityOfVertex ||
+           anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_IncompatibilityOfEdge ||
+           anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_IncompatibilityOfFace) &&
+          aShape && (theShapeType == -1 || aShape->GetValue().ShapeType() == theShapeType) &&
+          aSubShape && (theSubShapeType == -1 || aSubShape->GetValue().ShapeType() == theSubShapeType))
+      {
+        gp_XYZ aP1, aP2;
+        Standard_Real aDist = Precision::Infinite();
+        if (anIter->TypeOfCheck == BOPAlgo_CheckStatus::BOPAlgo_InvalidCurveOnSurface)
+          aDist = ComputeTolerance(aSubShape, aShape);
+        if (aDist > theTolerance)
+          aDistShapes.push_back(anIter->FailedShapes);
+      }
+    }
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return aDistShapes;
+  }
+
+  SetErrorCode(OK);
+  return aDistShapes;
+}
+
+//=============================================================================
+/*!
+ *  CheckConformityShape
+ *  Perform analyse of shape and find imperfections in the shape.
+ *  \param theShape Shape for analyse.
+ */
+ //=============================================================================
+void GEOMImpl_IMeasureOperations::CheckConformityShape(Handle(GEOM_Object) theShape, std::list<FailedChecks>& theChecks)
+{
+  SetErrorCode(KO);
+  MESSAGE("GEOMImpl_IMeasureOperations::checkShape");
+
+  Handle(GEOM_Object) aConformity = GetEngine()->AddObject(GEOM_CHECKCONFORMITY);
+  Handle(GEOM_Function) aFunction = aConformity->AddFunction(GEOMImpl_ConformityDriver::GetID(), CONFORMITY_CHECK_SHAPE);
+  if (aFunction.IsNull()) return;
+
+  //Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_ConformityDriver::GetID()) return;
+
+  GEOMImpl_IConformity aCI(aFunction);
+
+  Handle(GEOM_Function) aRefShape = theShape->GetLastFunction();
+  if (aRefShape.IsNull()) return;
+
+  aCI.SetShape(aRefShape);
+
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction))
+    {
+      SetErrorCode("Failed: checkShape");
+      return;
+    }
+    Handle(TColStd_HArray1OfInteger) aTypesChecks = aFunction->GetIntegerArray(CHECKCONFORMITY_RET_TYPES_CHECKS);
+    Handle(TColStd_HArray2OfInteger) aRes = aCI.GetListOfShapesIndices();
+    if (aRes.IsNull())
+      return;
+
+    for (Standard_Integer anIndex = 1; anIndex <= aRes->NbRows(); ++anIndex)
+    {
+      std::pair<Handle(GEOM_Object), Handle(GEOM_Object)> aPair;
+      Handle(TColStd_HArray1OfInteger) anArray;
+      anArray = new TColStd_HArray1OfInteger(1, 1);
+      anArray->SetValue(1, aRes->Value(anIndex, 1));
+
+      Handle(GEOM_Object) anObj = GetEngine()->AddSubShape(theShape, anArray);
+      if (!anObj.IsNull())
+        aPair.first = anObj;
+
+      anArray = new TColStd_HArray1OfInteger(1, 1);
+      anArray->SetValue(1, aRes->Value(anIndex, 2));
+
+      anObj = GetEngine()->AddSubShape(theShape, anArray);
+      if (!anObj.IsNull())
+        aPair.second = anObj;
+      theChecks.push_back({ aTypesChecks->Value(anIndex), aPair });
+    }
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return;
+  }
+
+  SetErrorCode(OK);
+  return;
+}
+
+//=============================================================================
+/*!
+ *  UpdateTolerance
+ *  Compute possible tolerance for the shape, minimize tolerance of shape as well
+ *  as tolerance of sub-shapes as much as possible
+ *  \param theShape Shape for compute tolerance.
+ */
+ //=============================================================================
+double GEOMImpl_IMeasureOperations::UpdateTolerance(Handle(GEOM_Object) theShape)
+{
+  SetErrorCode(KO);
+  MESSAGE("GEOMImpl_IMeasureOperations::updateTolerance");
+
+  double aResTol = -1;
+  Handle(GEOM_Object) aConformity = GetEngine()->AddObject(GEOM_CHECKCONFORMITY);
+  Handle(GEOM_Function) aFunction = aConformity->AddFunction(GEOMImpl_ConformityDriver::GetID(), CONFORMITY_UPDATE_TOL);
+  if (aFunction.IsNull()) return aResTol;
+
+  //Check if the function is set correctly
+  if (aFunction->GetDriverGUID() != GEOMImpl_ConformityDriver::GetID()) return aResTol;
+
+  GEOMImpl_IConformity aCI(aFunction);
+
+  Handle(GEOM_Function) aRefShape = theShape->GetLastFunction();
+  if (aRefShape.IsNull()) return aResTol;
+
+  aCI.SetShape(aRefShape);
+
+  try
+  {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aFunction))
+    {
+      SetErrorCode("Failed: updateTolerance");
+      return aResTol;
+    }
+    aResTol = aFunction->GetReal(CHECKCONFORMITY_RET_TOLERANCE);
+  }
+  catch (Standard_Failure& aFail)
+  {
+    SetErrorCode(aFail.GetMessageString());
+    return aResTol;
+  }
+
+  SetErrorCode(OK);
+  return aResTol;
+}
+
+//=============================================================================
+/*!
+ *  ComputeTolerance
+ *  Compute distance from the edge to the face.
+ */
+ //=============================================================================
+double GEOMImpl_IMeasureOperations::ComputeTolerance(Handle(GEOM_Object) theEdge,
+                                                     Handle(GEOM_Object) theFace)
+{
+  double aMaxDist = Precision::Infinite();
+  if (theEdge.IsNull() || theFace.IsNull())
+    return aMaxDist;
+
+  Handle(GEOM_Function) aRefEdge = theEdge->GetLastFunction();
+  Handle(GEOM_Function) aRefFace = theFace->GetLastFunction();
+  if (aRefEdge.IsNull() || aRefFace.IsNull())
+    return aMaxDist;
+
+  TopoDS_Edge aEdge = TopoDS::Edge(aRefEdge->GetValue());
+  TopoDS_Face aFace = TopoDS::Face(aRefFace->GetValue());
+  if (aEdge.IsNull() || aFace.IsNull())
+    return aMaxDist;
+
+  double aParam = 0.0;
+  BOPTools_AlgoTools::ComputeTolerance(aFace, aEdge, aMaxDist, aParam);
+  return aMaxDist;
+}
+
 //=======================================================================
 //function : FillErrorsSub
 //purpose  : Fill the errors list of subshapes on shape.
@@ -2802,3 +3280,191 @@ void GEOMImpl_IMeasureOperations::FillErrors
     }
   }
 }
+
+//=======================================================================
+//function : ShapeProximityCalculator
+//purpose  : returns an object to compute the proximity value
+//=======================================================================
+Handle(GEOM_Object) GEOMImpl_IMeasureOperations::ShapeProximityCalculator
+                                          (Handle(GEOM_Object) theShape1,
+                                           Handle(GEOM_Object) theShape2)
+{
+  SetErrorCode(KO);
+
+  if (theShape1.IsNull() || theShape2.IsNull())
+    return NULL;
+
+  Handle(GEOM_Function) aShapeFunc1 = theShape1->GetLastFunction();
+  Handle(GEOM_Function) aShapeFunc2 = theShape2->GetLastFunction();
+  if (aShapeFunc1.IsNull() || aShapeFunc2.IsNull())
+    return NULL;
+
+  Handle(GEOM_Object) aProximityCalc = GetEngine()->AddObject(GEOM_SHAPE_PROXIMITY);
+  if (aProximityCalc.IsNull())
+    return NULL;
+
+  Handle(GEOM_Function) aProximityFuncCoarse =
+      aProximityCalc->AddFunction(GEOMImpl_ShapeProximityDriver::GetID(), PROXIMITY_COARSE);
+  //Check if the function is set correctly
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID())
+    return NULL;
+
+  GEOMImpl_IProximity aProximity (aProximityFuncCoarse);
+  aProximity.SetShapes(aShapeFunc1, aShapeFunc2);
+
+  //Make a Python command
+  GEOM::TPythonDump pd (aProximityFuncCoarse);
+  pd << "p = geompy.ShapeProximity()\n";
+  pd << "p.setShapes(" << theShape1 << ", " << theShape2 << ")";
+
+  SetErrorCode(OK);
+  return aProximityCalc;
+}
+
+//=======================================================================
+//function : SetShapeSampling
+//purpose  : set number sample points to compute the coarse proximity
+//=======================================================================
+void GEOMImpl_IMeasureOperations::SetShapeSampling(Handle(GEOM_Object) theCalculator,
+                                                   Handle(GEOM_Object) theShape,
+                                                   const Standard_Integer theNbSamples)
+{
+  SetErrorCode(KO);
+  if (theShape.IsNull() ||
+      theCalculator.IsNull() ||
+      theCalculator->GetNbFunctions() <= 0 ||
+      theNbSamples <= 0)
+    return ;
+
+  Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1);
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID())
+    return ;
+
+  Handle(GEOM_Function) aShapeFunc = theShape->GetLastFunction();
+  if (aShapeFunc.IsNull())
+    return ;
+
+  GEOMImpl_IProximity aProximity(aProximityFuncCoarse);
+  Handle(GEOM_Function) aShape1, aShape2;
+  aProximity.GetShapes(aShape1, aShape2);
+  if (aShape1->GetValue() == aShapeFunc->GetValue())
+    aProximity.SetNbSamples(PROXIMITY_ARG_SAMPLES1, theNbSamples);
+  else if (aShape2->GetValue() == aShapeFunc->GetValue())
+    aProximity.SetNbSamples(PROXIMITY_ARG_SAMPLES2, theNbSamples);
+
+  //Make a Python command
+  GEOM::TPythonDump(aProximityFuncCoarse, /*append=*/true) <<
+    "p.setSampling(" << theShape << ", " << theNbSamples << ")";
+
+  SetErrorCode(OK);
+}
+
+//=======================================================================
+//function : GetCoarseProximity
+//purpose  : compute coarse proximity
+//=======================================================================
+Standard_Real GEOMImpl_IMeasureOperations::GetCoarseProximity(Handle(GEOM_Object) theCalculator,
+                                                              bool doPythonDump)
+{
+  SetErrorCode(KO);
+  if (theCalculator.IsNull())
+    return -1;
+
+  Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1);
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID() ||
+      aProximityFuncCoarse->GetType() != PROXIMITY_COARSE)
+    return -1;
+
+  // Perform
+  // We have to recompute the function each time,
+  // because the number of samples can be changed
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aProximityFuncCoarse)) {
+      SetErrorCode("shape proximity driver failed");
+      return -1;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return -1;
+  }
+
+  //Make a Python command
+  if (doPythonDump)
+    GEOM::TPythonDump(aProximityFuncCoarse, /*append=*/true) << "value = p.coarseProximity()";
+
+  SetErrorCode(OK);
+  GEOMImpl_IProximity aProximity (aProximityFuncCoarse);
+  return aProximity.GetValue();
+}
+
+//=======================================================================
+//function : GetPreciseProximity
+//purpose  : compute precise proximity
+//=======================================================================
+Standard_Real GEOMImpl_IMeasureOperations::GetPreciseProximity(Handle(GEOM_Object) theCalculator)
+{
+  SetErrorCode(KO);
+  if (theCalculator.IsNull())
+    return -1;
+
+  Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1);
+  Handle(GEOM_Function) aProximityFuncFine = theCalculator->GetFunction(2);
+  if (aProximityFuncFine.IsNull())
+    aProximityFuncFine = theCalculator->AddFunction
+      (GEOMImpl_ShapeProximityDriver::GetID(), PROXIMITY_PRECISE);
+
+  //Check if the functions are set correctly
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID() ||
+      aProximityFuncFine.IsNull() ||
+      aProximityFuncFine->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID())
+    return -1;
+
+  // perform coarse computation beforehand
+  GetCoarseProximity(theCalculator, /*doPythonDump=*/false);
+
+  // transfer parameters from the coarse to precise calculator
+  GEOMImpl_IProximity aCoarseProximity (aProximityFuncCoarse);
+  Handle(GEOM_Function) aShape1, aShape2;
+  aCoarseProximity.GetShapes(aShape1, aShape2);
+  if (aShape1.IsNull() || aShape2.IsNull())
+    return -1;
+  gp_Pnt aProxPnt1, aProxPnt2;
+  Standard_Integer intStatus1, intStatus2;
+  aCoarseProximity.GetProximityPoints(aProxPnt1, aProxPnt2);
+  aCoarseProximity.GetStatusOfPoints(intStatus1, intStatus2);
+  Standard_Real aResultValue = aCoarseProximity.GetValue();
+
+  GEOMImpl_IProximity aFineProximity (aProximityFuncFine);
+  aFineProximity.SetShapes(aShape1, aShape2);
+  aFineProximity.SetProximityPoints(aProxPnt1, aProxPnt2);
+  aFineProximity.SetStatusOfPoints(intStatus1, intStatus2);
+  aFineProximity.SetValue(aResultValue); // in some cases this value cannot be precised
+
+  // Perform
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aProximityFuncFine)) {
+      SetErrorCode("shape proximity driver failed");
+      return -1;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return -1;
+  }
+
+  aResultValue = aFineProximity.GetValue();
+  aFineProximity.GetProximityPoints(aProxPnt1, aProxPnt2);
+
+  //Make a Python command
+  GEOM::TPythonDump(aProximityFuncCoarse, /*append=*/true) << "value = p.preciseProximity()";
+
+  SetErrorCode(OK);
+  return aResultValue;
+}