// File: BOP_ArgumentAnalyzer.cxx // Created: 02.09.04 16:26:31 // Copyright: Open Cascade 2004 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static Standard_Boolean TestShapeType(const TopoDS_Shape & TheShape); static Standard_Boolean CheckEdge(const TopoDS_Edge& theEdge); static Standard_Boolean TestSubShapeType(const TopAbs_ShapeEnum theT1, const TopAbs_ShapeEnum theT2, const BOP_Operation theOP); // ================================================================================ // function: Constructor // purpose: // ================================================================================ BOP_ArgumentAnalyzer::BOP_ArgumentAnalyzer() : myStopOnFirst(Standard_False), myOperation(BOP_UNKNOWN), myArgumentTypeMode(Standard_False), mySelfInterMode(Standard_False), mySmallEdgeMode(Standard_False), myRebuildFaceMode(Standard_False), myTangentMode(Standard_False), myMergeVertexMode(Standard_False), myMergeEdgeMode(Standard_False) // myMergeFaceMode(Standard_False) { } // ================================================================================ // function: SetShape1 // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::SetShape1(const TopoDS_Shape & TheShape) { myShape1 = TheShape; } // ================================================================================ // function: SetShape2 // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::SetShape2(const TopoDS_Shape & TheShape) { myShape2 = TheShape; } // ================================================================================ // function: GetShape1 // purpose: // ================================================================================ const TopoDS_Shape & BOP_ArgumentAnalyzer::GetShape1() const { return myShape1; } // ================================================================================ // function: GetShape2 // purpose: // ================================================================================ const TopoDS_Shape & BOP_ArgumentAnalyzer::GetShape2() const { return myShape2; } // ================================================================================ // function: OperationType // purpose: // ================================================================================ BOP_Operation& BOP_ArgumentAnalyzer::OperationType() { return myOperation; } // ================================================================================ // function: StopOnFirstFaulty // purpose: // ================================================================================ Standard_Boolean & BOP_ArgumentAnalyzer::StopOnFirstFaulty() { return myStopOnFirst; } // ================================================================================ // function: Perform // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::Perform() { try { OCC_CATCH_SIGNALS myResult.Clear(); if(myArgumentTypeMode) { TestTypes(); } if(mySelfInterMode) { TestSelfInterferences(); } if(mySmallEdgeMode) { if(!(!myResult.IsEmpty() && myStopOnFirst)) TestSmallEdge(); } if(myRebuildFaceMode) { if(!(!myResult.IsEmpty() && myStopOnFirst)) TestRebuildFace(); } if(myTangentMode) { if(!(!myResult.IsEmpty() && myStopOnFirst)) TestTangent(); } if(myMergeVertexMode) { if(!(!myResult.IsEmpty() && myStopOnFirst)) TestMergeVertex(); } if(myMergeEdgeMode) { if(!(!myResult.IsEmpty() && myStopOnFirst)) TestMergeEdge(); } // if(myMergeFaceMode) { // TestMergeFace(); // } } catch(Standard_Failure) { BOP_CheckResult aResult; aResult.SetCheckStatus(BOP_CheckUnknown); myResult.Append(aResult); } } // ================================================================================ // function: HasFaulty // purpose: // ================================================================================ Standard_Boolean BOP_ArgumentAnalyzer::HasFaulty() const { return ( !myResult.IsEmpty()); } // ================================================================================ // function: GetCheckResult // purpose: // ================================================================================ const BOP_ListOfCheckResult& BOP_ArgumentAnalyzer::GetCheckResult() const { return myResult; } // ================================================================================ // function: TestTypes // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestTypes() { Standard_Boolean isS1 = myShape1.IsNull(), isS2 = myShape2.IsNull(); if(isS1 && isS2) { BOP_CheckResult aResult; aResult.SetCheckStatus(BOP_BadType); myResult.Append(aResult); return; } Standard_Boolean testS1 = TestShapeType(myShape1); Standard_Boolean testS2 = TestShapeType(myShape2); // single shape check (begin) if((isS1 && !isS2) || (!isS1 && isS2)) { // Standard_Boolean testS = (isS1) ? testS1 : testS2; Standard_Boolean testS = (isS1) ? testS2 : testS1; if(!testS) { const TopoDS_Shape & aS = (isS1) ? myShape1 : myShape2; BOP_CheckResult aResult; aResult.SetShape1(aS); aResult.SetCheckStatus(BOP_BadType); myResult.Append(aResult); return; } } // single shape is set (end) // two shapes check (begin) else { // test compounds and compsolids if(!testS1 || !testS2) { BOP_CheckResult aResult; if(!testS1 && !testS2) { aResult.SetShape1(myShape1); aResult.SetShape2(myShape2); } else { const TopoDS_Shape & aS = (!testS1) ? myShape1 : myShape2; if(!testS1) aResult.SetShape1(aS); else aResult.SetShape2(aS); } aResult.SetCheckStatus(BOP_BadType); myResult.Append(aResult); return; } // test faces, wires, edges TopAbs_ShapeEnum aT1 = myShape1.ShapeType(), aT2 = myShape2.ShapeType(); if(aT1 != TopAbs_COMPOUND && aT2 != TopAbs_COMPOUND) { Standard_Boolean aTestRes = TestSubShapeType(aT1,aT2,myOperation); if(!aTestRes) { BOP_CheckResult aResult; aResult.SetShape1(myShape1); aResult.SetShape2(myShape2); aResult.SetCheckStatus(BOP_BadType); myResult.Append(aResult); return; } } else { Standard_Boolean aTestRes = Standard_True; if(aT1 == TopAbs_COMPOUND && aT2 != TopAbs_COMPOUND) { TopoDS_Iterator itS1(myShape1); while(itS1.More()) { aT1 = itS1.Value().ShapeType(); aTestRes = TestSubShapeType(aT1,aT2,myOperation); if(!aTestRes) break; itS1.Next(); } } else if(aT1 != TopAbs_COMPOUND && aT2 == TopAbs_COMPOUND) { TopoDS_Iterator itS2(myShape2); while(itS2.More()) { aT2 = itS2.Value().ShapeType(); aTestRes = TestSubShapeType(aT1,aT2,myOperation); if(!aTestRes) break; itS2.Next(); } } else { TopoDS_Iterator itS1(myShape1); while(itS1.More()) { aT1 = itS1.Value().ShapeType(); TopoDS_Iterator itS2(myShape2); while(itS2.More()) { aT2 = itS2.Value().ShapeType(); aTestRes = TestSubShapeType(aT1,aT2,myOperation); if(!aTestRes) break; itS2.Next(); } if(!aTestRes) break; itS1.Next(); } } if(!aTestRes) { BOP_CheckResult aResult; aResult.SetShape1(myShape1); aResult.SetShape2(myShape2); aResult.SetCheckStatus(BOP_BadType); myResult.Append(aResult); return; } } } // both shapes are set (end) } // ================================================================================ // function: TestSelfInterferences // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestSelfInterferences() { Standard_Integer i = 0; for(i = 0; i < 2; i++) { TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2; if(aS.IsNull()) continue; BOPTools_Checker aChecker(aS); aChecker.Perform(); if (aChecker.HasFaulty()) { const BOPTools_ListOfCheckResults& aResultList = aChecker.GetCheckResult(); BOPTools_ListIteratorOfListOfCheckResults anIt(aResultList); for(; anIt.More(); anIt.Next()) { const BOPTools_CheckResult& aCheckResult = anIt.Value(); if((aCheckResult.GetCheckStatus() == BOPTools_CHKUNKNOWN) || (aCheckResult.GetCheckStatus() == BOPTools_BADSHRANKRANGE) || (aCheckResult.GetCheckStatus() == BOPTools_NULLSRANKRANGE)) { continue; } BOP_CheckResult aResult; if(i == 0) aResult.SetShape1(myShape1); else aResult.SetShape2(myShape2); TopTools_ListIteratorOfListOfShape anIt2(aCheckResult.GetShapes()); for(; anIt2.More(); anIt2.Next()) { if(i == 0) aResult.AddFaultyShape1(anIt2.Value()); else aResult.AddFaultyShape2(anIt2.Value()); } aResult.SetCheckStatus(BOP_SelfIntersect); myResult.Append(aResult); if(myStopOnFirst) { return; } } } } } // ================================================================================ // function: TestSmallEdge // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestSmallEdge() { Standard_Integer i = 0; BRepExtrema_DistShapeShape aDist; for(i = 0; i < 2; i++) { TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2; if(aS.IsNull()) continue; TopExp_Explorer anExp(aS, TopAbs_EDGE); for(; anExp.More(); anExp.Next()) { TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current()); if(!CheckEdge(anEdge)) { Standard_Boolean bKeepResult = Standard_True; if(myOperation == BOP_SECTION) { TopoDS_Shape anOtherS = (i == 0) ? myShape2 : myShape1; if(!anOtherS.IsNull()) { // BRepExtrema_DistShapeShape aDist; aDist.LoadS2(anOtherS); Standard_Boolean bVertexIsOnShape = Standard_False; Standard_Integer ii = 0; TopExp_Explorer anExpV(anEdge, TopAbs_VERTEX); for(; anExpV.More(); anExpV.Next()) { TopoDS_Shape aV = anExpV.Current(); aDist.LoadS1(aV); aDist.Perform(); if(aDist.IsDone()) { for(ii = 1; ii <= aDist.NbSolution(); ii++) { Standard_Real aTolerance = BRep_Tool::Tolerance(TopoDS::Vertex(aV)); TopoDS_Shape aSupportShape = aDist.SupportOnShape2(ii); switch(aSupportShape.ShapeType()) { case TopAbs_VERTEX: { aTolerance += BRep_Tool::Tolerance(TopoDS::Vertex(aSupportShape)); break; } case TopAbs_EDGE: { aTolerance += BRep_Tool::Tolerance(TopoDS::Edge(aSupportShape)); break; } case TopAbs_FACE: { aTolerance += BRep_Tool::Tolerance(TopoDS::Face(aSupportShape)); break; } default: break; } if(aDist.Value() < aTolerance) { bVertexIsOnShape = Standard_True; break; } } } } if(!bVertexIsOnShape) { bKeepResult = Standard_False; } } } if(bKeepResult) { BOP_CheckResult aResult; if(i == 0) { aResult.SetShape1(myShape1); aResult.AddFaultyShape1(anEdge); } else { aResult.SetShape2(myShape2); aResult.AddFaultyShape2(anEdge); } aResult.SetCheckStatus(BOP_TooSmallEdge); myResult.Append(aResult); if(myStopOnFirst) { return; } } } } } } // ================================================================================ // function: TestRebuildFace // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestRebuildFace() { if((myOperation == BOP_SECTION) || (myOperation == BOP_UNKNOWN)) return; Standard_Integer i = 0; for(i = 0; i < 2; i++) { TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2; if(aS.IsNull()) continue; TopExp_Explorer anExp(aS, TopAbs_FACE); for(; anExp.More(); anExp.Next()) { TopoDS_Face aFace = TopoDS::Face(anExp.Current()); BOP_WireEdgeSet aWES (aFace); TopExp_Explorer anExpE(aFace, TopAbs_EDGE); Standard_Integer nbstartedges = 0; for(; anExpE.More(); anExpE.Next()) { aWES.AddStartElement(anExpE.Current()); nbstartedges++; } BOP_FaceBuilder aFB; aFB.Do(aWES); const TopTools_ListOfShape& aLF = aFB.NewFaces(); Standard_Boolean bBadFace = Standard_False; if(aLF.Extent() != 1) { bBadFace = Standard_True; } else { Standard_Integer nbedgeused = 0; anExpE.Init(aLF.First(), TopAbs_EDGE); for(; anExpE.More(); anExpE.Next(), nbedgeused++) {} if(nbstartedges != nbedgeused) { bBadFace = Standard_True; } } if(bBadFace) { BOP_CheckResult aResult; if(i == 0) { aResult.SetShape1(myShape1); aResult.AddFaultyShape1(aFace); } else { aResult.SetShape2(myShape2); aResult.AddFaultyShape2(aFace); } aResult.SetCheckStatus(BOP_NonRecoverableFace); myResult.Append(aResult); if(myStopOnFirst) { return; } } } } } // ================================================================================ // function: TestTangent // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestTangent() { // not implemented } // ================================================================================ // function: TestMergeSubShapes // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestMergeSubShapes(const TopAbs_ShapeEnum theType) { if(myShape1.IsNull() || myShape2.IsNull()) return; BOP_CheckStatus aStatus = BOP_CheckUnknown; switch(theType) { case TopAbs_VERTEX: { aStatus = BOP_IncompatibilityOfVertex; break; } case TopAbs_EDGE: { aStatus = BOP_IncompatibilityOfEdge; break; } case TopAbs_FACE: { aStatus = BOP_IncompatibilityOfFace; break; } default: return; } TopExp_Explorer anExp1(myShape1, theType); TopExp_Explorer anExp2(myShape2, theType); TopTools_SequenceOfShape aSeq1, aSeq2; TopTools_MapOfShape aMap1, aMap2; for(; anExp1.More(); anExp1.Next()) { TopoDS_Shape aS1 = anExp1.Current(); if(aMap1.Contains(aS1)) continue; aSeq1.Append(aS1); aMap1.Add(aS1); } for(; anExp2.More(); anExp2.Next()) { TopoDS_Shape aS2 = anExp2.Current(); if(aMap2.Contains(aS2)) continue; aSeq2.Append(aS2); aMap2.Add(aS2); } TColStd_Array2OfBoolean anArrayOfFlag(1, aSeq1.Length(), 1, aSeq2.Length()); Standard_Integer i = 0, j = 0; for(i = 1; i <= aSeq1.Length(); i++) for(j = 1; j <= aSeq2.Length(); j++) anArrayOfFlag.SetValue(i, j, Standard_False); for(i = 1; i <= aSeq1.Length(); i++) { TopoDS_Shape aS1 = aSeq1.Value(i); TopTools_ListOfShape aListOfS2; Standard_Integer nbs = 0; for(j = 1; j <= aSeq2.Length(); j++) { TopoDS_Shape aS2 = aSeq2.Value(j); Standard_Boolean bIsEqual = Standard_False; if(theType == TopAbs_VERTEX) { TopoDS_Vertex aV1 = TopoDS::Vertex(aS1); TopoDS_Vertex aV2 = TopoDS::Vertex(aS2); gp_Pnt aP1 = BRep_Tool::Pnt(aV1); gp_Pnt aP2 = BRep_Tool::Pnt(aV2); Standard_Real aDist = aP1.Distance(aP2); if(aDist <= (BRep_Tool::Tolerance(aV1) + BRep_Tool::Tolerance(aV2))) { bIsEqual = Standard_True; } } else if(theType == TopAbs_EDGE) { Standard_Integer aDiscretize = 30; Standard_Real aDeflection = 0.01; TopoDS_Edge aE1 = TopoDS::Edge(aS1); TopoDS_Edge aE2 = TopoDS::Edge(aS2); IntTools_EdgeEdge aEE; aEE.SetEdge1 (aE1); aEE.SetEdge2 (aE2); aEE.SetTolerance1 (BRep_Tool::Tolerance(aE1)); aEE.SetTolerance2 (BRep_Tool::Tolerance(aE2)); aEE.SetDiscretize (aDiscretize); aEE.SetDeflection (aDeflection); Standard_Real f = 0., l = 0.; BRep_Tool::Range(aE1, f, l); aEE.SetRange1(f, l); BRep_Tool::Range(aE2, f, l); aEE.SetRange2(f, l); aEE.Perform(); if (aEE.IsDone()) { const IntTools_SequenceOfCommonPrts& aCPrts = aEE.CommonParts(); Standard_Integer ii = 0; for (ii = 1; ii <= aCPrts.Length(); ii++) { const IntTools_CommonPrt& aCPart = aCPrts(ii); if (aCPart.Type() == TopAbs_EDGE) { bIsEqual = Standard_True; } } } } else if(theType == TopAbs_FACE) { // not yet implemented! } if(bIsEqual) { anArrayOfFlag.SetValue(i, j, Standard_True ); aListOfS2.Append(aS2); nbs++; } } if(nbs > 1) { BOP_CheckResult aResult; aResult.SetShape1(myShape1); aResult.SetShape2(myShape2); aResult.AddFaultyShape1(aS1); TopTools_ListIteratorOfListOfShape anIt(aListOfS2); for(; anIt.More(); anIt.Next()) { aResult.AddFaultyShape2(anIt.Value()); } aResult.SetCheckStatus(aStatus); myResult.Append(aResult); if(myStopOnFirst) { return; } } } for(i = 1; i <= aSeq2.Length(); i++) { TopoDS_Shape aS2 = aSeq2.Value(i); TopTools_ListOfShape aListOfS1; Standard_Integer nbs = 0; for(j = 1; j <= aSeq1.Length(); j++) { TopoDS_Shape aS1 = aSeq1.Value(j); if(anArrayOfFlag.Value(j, i)) { aListOfS1.Append(aS1); nbs++; } } if(nbs > 1) { BOP_CheckResult aResult; aResult.SetShape1(myShape1); aResult.SetShape2(myShape2); TopTools_ListIteratorOfListOfShape anIt(aListOfS1); for(; anIt.More(); anIt.Next()) { aResult.AddFaultyShape1(anIt.Value()); } aResult.AddFaultyShape2(aS2); aResult.SetCheckStatus(aStatus); myResult.Append(aResult); if(myStopOnFirst) { return; } } } } // ================================================================================ // function: TestMergeVertex // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestMergeVertex() { TestMergeSubShapes(TopAbs_VERTEX); } // ================================================================================ // function: TestMergeEdge // purpose: // ================================================================================ void BOP_ArgumentAnalyzer::TestMergeEdge() { TestMergeSubShapes(TopAbs_EDGE); } // ================================================================================ // function: TestMergeFace // purpose: // ================================================================================ // void BOP_ArgumentAnalyzer::TestMergeFace() // { // not implemented // } // ---------------------------------------------------------------------- // static function: TestShapeType // purpose: // ---------------------------------------------------------------------- Standard_Boolean TestShapeType(const TopoDS_Shape & TheShape) { if(TheShape.IsNull()) return Standard_False; TopAbs_ShapeEnum aT = TheShape.ShapeType(); if(aT == TopAbs_COMPOUND && BOPTools_Tools3D::IsEmptyShape(TheShape)) return Standard_False; TopoDS_Iterator anIt; TopoDS_Shape aSTmp, aShape; Standard_Integer aNbShapes, TreatRes = 0; if(aT==TopAbs_COMPOUND || aT==TopAbs_COMPSOLID) { aNbShapes=0; anIt.Initialize(TheShape); for (; anIt.More(); anIt.Next()) { if(!aNbShapes) { aSTmp=anIt.Value(); } aNbShapes++; if(aNbShapes>1) { break; } } if(aT == TopAbs_COMPOUND) { if (aNbShapes==1) { TreatRes = BOPTools_DSFiller::TreatCompound(TheShape, aSTmp); if(TreatRes != 0) return Standard_False; aShape=aSTmp; aT = aShape.ShapeType(); } else if (aNbShapes>1) { TreatRes = BOPTools_DSFiller::TreatCompound(TheShape, aSTmp); if(TreatRes != 0) return Standard_False; aShape=aSTmp; aT=aShape.ShapeType(); } } } if(aT==TopAbs_COMPOUND || aT==TopAbs_COMPSOLID) { return Standard_False; } return Standard_True; } // ---------------------------------------------------------------------- // static function: CheckEdge // purpose: // ---------------------------------------------------------------------- Standard_Boolean CheckEdge(const TopoDS_Edge& theEdge) { IntTools_Context aContext; TopoDS_Vertex aV1, aV2; TopExp::Vertices(theEdge, aV1, aV2); if(aV1.IsNull() || aV2.IsNull() || BRep_Tool::Degenerated(theEdge)) return Standard_True; Standard_Real aFirst = 0., aLast = 0.; BRep_Tool::Range(theEdge, aFirst, aLast); IntTools_Range aRange(aFirst, aLast); IntTools_ShrunkRange aSR(theEdge, aV1, aV2, aRange, aContext); if (!aSR.IsDone() || aSR.ErrorStatus() == 6) { return Standard_False; } return Standard_True; } // ---------------------------------------------------------------------- // static function: TestSubShapeType // purpose: // ---------------------------------------------------------------------- Standard_Boolean TestSubShapeType(const TopAbs_ShapeEnum theT1, const TopAbs_ShapeEnum theT2, const BOP_Operation theOP) { TopAbs_ShapeEnum aT1 = theT1, aT2 = theT2; if(aT1==TopAbs_FACE) { if(aT2==TopAbs_SOLID || aT2==TopAbs_SHELL || aT2==TopAbs_FACE || aT2==TopAbs_WIRE || aT2==TopAbs_EDGE) { aT1=TopAbs_SHELL; } } if(aT2==TopAbs_FACE) { if(aT1==TopAbs_SOLID || aT1==TopAbs_SHELL || aT1==TopAbs_WIRE || aT1==TopAbs_EDGE) { aT2=TopAbs_SHELL; } } if(aT1==TopAbs_EDGE) { if(aT2==TopAbs_SOLID || aT2==TopAbs_SHELL || aT2==TopAbs_WIRE || aT2==TopAbs_EDGE) { aT1=TopAbs_WIRE; } } if(aT2==TopAbs_EDGE) { if(aT1==TopAbs_SOLID || aT1==TopAbs_SHELL || aT1==TopAbs_WIRE) { aT2=TopAbs_WIRE; } } // test operations if(theOP!=BOP_UNKNOWN) { Standard_Boolean opOk; if(aT1==TopAbs_SHELL && aT2==TopAbs_SHELL) opOk = Standard_True; else if(aT1==TopAbs_SOLID && aT2==TopAbs_SOLID) opOk = Standard_True; else if((aT1==TopAbs_SOLID && aT2==TopAbs_SHELL) || (aT2==TopAbs_SOLID && aT1==TopAbs_SHELL)) opOk = Standard_True; else if(aT1==TopAbs_WIRE && aT2==TopAbs_WIRE) opOk = Standard_True; else if((aT1==TopAbs_WIRE && aT2==TopAbs_SHELL) || (aT2==TopAbs_WIRE && aT1==TopAbs_SHELL)) opOk = Standard_True; else if((aT1==TopAbs_WIRE && aT2==TopAbs_SOLID) || (aT2==TopAbs_WIRE && aT1==TopAbs_SOLID)) opOk = Standard_True; else opOk = Standard_False; if(!opOk) { return Standard_False; } if((aT1==TopAbs_SHELL && aT2==TopAbs_SOLID) || (aT2==TopAbs_SHELL && aT1==TopAbs_SOLID)) { if(!BOP_ShellSolid::CheckArgTypes(aT1,aT2,theOP)) { return Standard_False; } } if((aT1==TopAbs_WIRE && aT2==TopAbs_SOLID) || (aT2==TopAbs_WIRE && aT1==TopAbs_SOLID)) { if(!BOP_WireSolid::CheckArgTypes(aT1,aT2,theOP)) { return Standard_False; } } if((aT1==TopAbs_WIRE && aT2==TopAbs_SHELL) || (aT1==TopAbs_WIRE && aT2==TopAbs_SHELL)) { if(!BOP_WireShell::CheckArgTypes(aT1,aT2,theOP)) { return Standard_False; } } } return Standard_True; }