Salome HOME
Implemented [bos #35094] [EDF] (2023-T1) X,Y,Z to U,V.
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IMeasureOperations.cxx
index aa141c2888c9a1ba326fda763f96b421452dbc61..00bcb04e05f406c872801c81edc1cdf8ac1c8902 100644 (file)
 #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>
@@ -46,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>
@@ -2787,6 +2793,549 @@ Handle(GEOM_Object) GEOMImpl_IMeasureOperations::SurfaceCurvatureByPointAndDirec
   return aCV;
 }
 
+//=============================================================================
+/*!
+ *  XYZtoUV
+ */
+ //=============================================================================
+Handle(TColStd_HArray1OfReal) GEOMImpl_IMeasureOperations::XYZtoUV
+                                                  (Handle(GEOM_Object) theSurf,
+                                                   const Handle(TColStd_HArray1OfReal)& theXYZlist,
+                                                   bool isNormalized)
+{
+  SetErrorCode(KO);
+
+  Handle(TColStd_HArray1OfReal) aRet;
+
+  // Check list of coordinates
+  int nbC = theXYZlist->Length();
+  int nbP = nbC / 3;
+  if (nbP * 3 != nbC) {
+    SetErrorCode("Coordinates list length is not divisible by 3");
+    return aRet;
+  }
+
+  // Check face
+  if (theSurf.IsNull()) {
+    SetErrorCode("The shape is NULL");
+    return aRet;
+  }
+
+  Handle(GEOM_Function) aRefShape = theSurf->GetLastFunction();
+  if (aRefShape.IsNull()) {
+    SetErrorCode("The shape is NULL");
+    return aRet;
+  }
+
+  TopoDS_Shape aShape = aRefShape->GetValue();
+  if (aShape.IsNull()) {
+    SetErrorCode("The shape is NULL");
+    return aRet;
+  }
+
+  // The shape can be a face, a shell of one face or a compound with one face
+  TopoDS_Face F;
+  if (aShape.ShapeType() == TopAbs_FACE) {
+    F = TopoDS::Face(aShape);
+  }
+  else if (aShape.ShapeType() < TopAbs_FACE) {
+    TopExp_Explorer Exp (aShape, TopAbs_FACE);
+    if (Exp.More()) {
+      F = TopoDS::Face(Exp.Current());
+      Exp.Next();
+      if (Exp.More()) {
+        SetErrorCode("There should be only one face");
+        return aRet;
+      }
+    }
+  }
+  if (F.IsNull()) {
+    SetErrorCode("There are no faces");
+    return aRet;
+  }
+
+  // Face tolerance
+  Standard_Real squareTolerance = BRep_Tool::Tolerance(F);
+  squareTolerance = squareTolerance * squareTolerance;
+
+  // Compute parameters
+  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(F);
+  aRet = new TColStd_HArray1OfReal (0, nbP * 2 - 1);
+
+  Standard_Real U1,U2, V1,V2;
+  BRepTools::UVBounds(F, U1, U2, V1, V2);
+  Standard_Real dU = U2 - U1;
+  Standard_Real dV = V2 - V1;
+
+  int iCLower = theXYZlist->Lower();
+  for (int iP = 0; iP < nbP; iP++) {
+    gp_Pnt aP (theXYZlist->Value(iCLower + iP * 3),
+               theXYZlist->Value(iCLower + iP * 3 + 1),
+               theXYZlist->Value(iCLower + iP * 3 + 2));
+    Standard_Real U, V;
+    gp_Pnt aPonF = GEOMUtils::ProjectPointOnFace(aP, F, U, V);
+    if (aP.SquareDistance(aPonF) < squareTolerance) {
+      if (isNormalized) {
+        // Normalize parameters to be in [0, 1]
+        U = (U - U1) / dU;
+        V = (V - V1) / dV;
+      }
+      aRet->SetValue(iP * 2    , U);
+      aRet->SetValue(iP * 2 + 1, V);
+    }
+    else {
+      SetErrorCode("Point too far from face");
+      return aRet;
+    }
+  }
+
+  SetErrorCode(OK);
+  return aRet;
+}
+
+//=============================================================================
+/*!
+ *  UVtoXYZ
+ */
+ //=============================================================================
+Handle(TColStd_HArray1OfReal) GEOMImpl_IMeasureOperations::UVtoXYZ
+                                                  (Handle(GEOM_Object) theSurf,
+                                                   const Handle(TColStd_HArray1OfReal)& theUVlist,
+                                                   bool isNormalized)
+{
+  SetErrorCode(KO);
+
+  Handle(TColStd_HArray1OfReal) aRet;
+
+  // Check list of parameters
+  int nbC = theUVlist->Length();
+  int nbP = nbC / 2;
+  if (nbP * 2 != nbC) {
+    SetErrorCode("Parameters list length is not divisible by 2");
+    return aRet;
+  }
+
+  // Check face
+  if (theSurf.IsNull()) {
+    SetErrorCode("The shape is NULL");
+    return aRet;
+  }
+
+  Handle(GEOM_Function) aRefShape = theSurf->GetLastFunction();
+  if (aRefShape.IsNull()) {
+    SetErrorCode("The shape is NULL");
+    return aRet;
+  }
+
+  TopoDS_Shape aShape = aRefShape->GetValue();
+  if (aShape.IsNull()) {
+    SetErrorCode("The shape is NULL");
+    return aRet;
+  }
+
+  // The shape can be a face, a shell of one face or a compound with one face
+  TopoDS_Face F;
+  if (aShape.ShapeType() == TopAbs_FACE) {
+    F = TopoDS::Face(aShape);
+  }
+  else if (aShape.ShapeType() < TopAbs_FACE) {
+    TopExp_Explorer Exp (aShape, TopAbs_FACE);
+    if (Exp.More()) {
+      F = TopoDS::Face(Exp.Current());
+      Exp.Next();
+      if (Exp.More()) {
+        SetErrorCode("There should be only one face");
+        return aRet;
+      }
+    }
+  }
+  if (F.IsNull()) {
+    SetErrorCode("There are no faces");
+    return aRet;
+  }
+
+  // Face tolerance
+  Standard_Real squareTolerance = BRep_Tool::Tolerance(F);
+  squareTolerance = squareTolerance * squareTolerance;
+
+  // Compute coordinates
+  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(F);
+  aRet = new TColStd_HArray1OfReal (0, nbP * 3 - 1);
+
+  Standard_Real U1,U2, V1,V2;
+  BRepTools::UVBounds(F, U1, U2, V1, V2);
+  Standard_Real dU = U2 - U1;
+  Standard_Real dV = V2 - V1;
+
+  Standard_Real tol = 1.e-4;
+  Standard_Real pc = Precision::Confusion();
+
+  int iCLower = theUVlist->Lower();
+  for (int iP = 0; iP < nbP; iP++) {
+    Standard_Real U = theUVlist->Value(iCLower + iP * 2);
+    Standard_Real V = theUVlist->Value(iCLower + iP * 2 + 1);
+
+    if (isNormalized) {
+      // Get real parameters from given normalized ones in [0, 1]
+      if (!(-pc < U && U < 1 + pc) || !(-pc < V && V < 1 + pc)) {
+        SetErrorCode("Normalized parameter is out of range [0,1]");
+        return aRet;
+      }
+      U = U1 + dU * U;
+      V = V1 + dV * V;
+    }
+
+    gp_Pnt2d aP2d (U, V);
+
+    BRepClass_FaceClassifier aClsf (F, aP2d, tol);
+    if (aClsf.State() != TopAbs_IN && aClsf.State() != TopAbs_ON) {
+      SetErrorCode("Given parameters are out of face");
+      return aRet;
+    }
+    gp_Pnt surfPnt = aSurf->Value(U, V);
+
+    aRet->SetValue(iP * 3    , surfPnt.X());
+    aRet->SetValue(iP * 3 + 1, surfPnt.Y());
+    aRet->SetValue(iP * 3 + 2, surfPnt.Z());
+  }
+
+  SetErrorCode(OK);
+  return aRet;
+}
+
+//=============================================================================
+/*!
+ *  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.
@@ -2941,3 +3490,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;
+}