Salome HOME
Implemented [bos #35094] [EDF] (2023-T1) X,Y,Z to U,V.
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IMeasureOperations.cxx
index 1c8c7add37667c3ecbc3179336a1e8b890cb29c8..00bcb04e05f406c872801c81edc1cdf8ac1c8902 100644 (file)
@@ -25,7 +25,9 @@
 #include <GEOMImpl_MeasureDriver.hxx>
 
 #include <GEOMImpl_IPatchFace.hxx>
+#include <GEOMImpl_IProximity.hxx>
 #include <GEOMImpl_PatchFaceDriver.hxx>
+#include <GEOMImpl_ShapeProximityDriver.hxx>
 
 #include <GEOMImpl_Types.hxx>
 
@@ -2791,6 +2793,216 @@ 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
@@ -3278,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;
+}