-// 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>
#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>
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IMeasureOperations::GetVertexByIndex
(Handle(GEOM_Object) theShape,
- Standard_Integer theIndex)
+ Standard_Integer theIndex,
+ Standard_Boolean theUseOri)
{
SetErrorCode(KO);
GEOMImpl_IMeasure aCI (aFunction);
aCI.SetBase(aRefShape);
aCI.SetIndex(theIndex);
+ aCI.SetUseOri(theUseOri);
//Compute
try {
}
//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;
// 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()) {
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());
}
+//=============================================================================
+/*!
+ * 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
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::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.
}
}
}
+
+//=======================================================================
+//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;
+}