X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGEOMImpl%2FGEOMImpl_IMeasureOperations.cxx;h=00bcb04e05f406c872801c81edc1cdf8ac1c8902;hb=refs%2Ftags%2FV9_11_0b1;hp=a06332644285efcee503ab9dcc6dbfac9d83bc89;hpb=e5d35ef4b2616bfd846c320f801fe06c620000b7;p=modules%2Fgeom.git diff --git a/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx b/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx index a06332644..00bcb04e0 100644 --- a/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx @@ -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 @@ -23,8 +23,17 @@ #include #include #include + +#include +#include +#include +#include + #include +#include +#include + #include #include @@ -42,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -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; @@ -2139,16 +2154,16 @@ 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; + + Standard_Real Dist = P1.Distance(P2); + singularBetter = singularBetter && dist < Dist; } } @@ -2353,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 @@ -2653,6 +2736,606 @@ 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; +} + +//============================================================================= +/*! + * 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::SelfIntersected2D(const std::list& theChecks) +{ + SetErrorCode(KO); + MESSAGE("GEOMImpl_IMeasureOperations::selfIntersected2D"); + + std::list aSelfInters2D; + try + { + OCC_CATCH_SIGNALS; + for (std::list::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::InterferingSubshapes + (const std::list& theChecks, + const int theShapeType1, + const int theShapeType2) +{ + SetErrorCode(KO); + MESSAGE("GEOMImpl_IMeasureOperations::interferingSubshapes"); + + std::list anInterfer; + try + { + OCC_CATCH_SIGNALS; + for (std::list::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& theChecks) +{ + SetErrorCode(KO); + MESSAGE("GEOMImpl_IMeasureOperations::smallEdges"); + + Handle(TColStd_HSequenceOfTransient) aSmallEdges = new TColStd_HSequenceOfTransient; + try + { + OCC_CATCH_SIGNALS; + for (std::list::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::DistantShapes + (const std::list& theChecks, + const int theShapeType, + const int theSubShapeType, + double theTolerance) +{ + SetErrorCode(KO); + MESSAGE("GEOMImpl_IMeasureOperations::distantShapes"); + + std::list aDistShapes; + try + { + OCC_CATCH_SIGNALS; + for (std::list::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& 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 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. @@ -2807,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; +}