// Created by: Peter KURNEV // Copyright (c) 2010-2014 OPEN CASCADE SAS // Copyright (c) 2007-2010 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 // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. // #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 #include #include #include #include #include #include #include #include // static Standard_Boolean IsGrowthShell(const TopoDS_Shape& , const BOPCol_IndexedMapOfShape& ); static Standard_Boolean IsHole(const TopoDS_Shape& , Handle(IntTools_Context)& ); static Standard_Boolean IsInside(const TopoDS_Shape& , const TopoDS_Shape& , Handle(IntTools_Context)& ); static void MakeInternalShells(const BOPCol_IndexedMapOfShape& , BOPCol_ListOfShape& ); //======================================================================= //function : BOPAlgo_FacePnt //purpose : //======================================================================= class BOPAlgo_FacePnt { public: BOPAlgo_FacePnt() { } // virtual ~BOPAlgo_FacePnt() { } // void SetFace(const TopoDS_Face& aFace) { myFace=aFace; } // const TopoDS_Face& Face()const { return myFace; } // void SetPnt(const gp_Pnt& aPnt) { myPnt=aPnt; } // const gp_Pnt& Pnt()const { return myPnt; } // protected: gp_Pnt myPnt; TopoDS_Face myFace; }; // typedef BOPCol_NCVector BOPAlgo_VectorOfFacePnt; // //======================================================================= //function : BOPAlgo_FaceSolid //purpose : //======================================================================= class BOPAlgo_FaceSolid : public BOPAlgo_Algo { public: DEFINE_STANDARD_ALLOC BOPAlgo_FaceSolid() : myIsInternalFace(Standard_False) { } // virtual ~BOPAlgo_FaceSolid() { } // void SetFace(const TopoDS_Face& aFace) { myFace=aFace; } // const TopoDS_Face& Face()const { return myFace; } // void SetSolid(const TopoDS_Solid& aSolid) { mySolid=aSolid; } // const TopoDS_Solid& Solid()const { return mySolid; } // void SetPnt(const gp_Pnt& aPnt) { myPnt=aPnt; } // const gp_Pnt& Pnt()const { return myPnt; } void SetContext(const Handle(IntTools_Context)& aContext) { myContext=aContext; } // const Handle(IntTools_Context)& Context()const { return myContext; } // Standard_Boolean IsInternalFace() const { return myIsInternalFace; } // virtual void Perform () { TopAbs_State aState; // BOPAlgo_Algo::UserBreak(); // aState=BOPTools_AlgoTools::ComputeState(myPnt, mySolid, Precision::Confusion(), myContext); // myIsInternalFace=(aState==TopAbs_IN); } // protected: Standard_Boolean myIsInternalFace; gp_Pnt myPnt; TopoDS_Face myFace; TopoDS_Solid mySolid; Handle(IntTools_Context) myContext; }; //======================================================================= typedef BOPCol_NCVector BOPAlgo_VectorOfFaceSolid; // typedef BOPCol_ContextFunctor BOPAlgo_FaceSolidFunctor; // typedef BOPCol_ContextCnt BOPAlgo_FaceSolidCnt; // //======================================================================= //======================================================================= //function : //purpose : //======================================================================= BOPAlgo_BuilderSolid::BOPAlgo_BuilderSolid() : BOPAlgo_BuilderArea() { } //======================================================================= //function : //purpose : //======================================================================= BOPAlgo_BuilderSolid::BOPAlgo_BuilderSolid (const Handle(NCollection_BaseAllocator)& theAllocator) : BOPAlgo_BuilderArea(theAllocator) { } //======================================================================= //function : ~ //purpose : //======================================================================= BOPAlgo_BuilderSolid::~BOPAlgo_BuilderSolid() { } //======================================================================= //function : SetSolid //purpose : //======================================================================= void BOPAlgo_BuilderSolid::SetSolid(const TopoDS_Solid& aS) { mySolid=aS; } //======================================================================= //function : Solid //purpose : //======================================================================= const TopoDS_Solid& BOPAlgo_BuilderSolid::Solid()const { return mySolid; } //======================================================================= //function : Perform //purpose : //======================================================================= void BOPAlgo_BuilderSolid::Perform() { GetReport()->Clear(); // if (myShapes.IsEmpty()) return; if (myContext.IsNull()) { myContext=new IntTools_Context; } // TopoDS_Compound aC; BRep_Builder aBB; BOPCol_ListIteratorOfListOfShape aIt; // aBB.MakeCompound(aC); aIt.Initialize(myShapes); for(; aIt.More(); aIt.Next()) { const TopoDS_Shape& aF=aIt.Value(); aBB.Add(aC, aF); } // UserBreak(); // PerformShapesToAvoid(); if (HasErrors()) { return; } // UserBreak(); // PerformLoops(); if (HasErrors()) { return; } // UserBreak(); // PerformAreas(); if (HasErrors()) { return; } // UserBreak(); // PerformInternalShapes(); if (HasErrors()) { return; } } //======================================================================= //function :PerformShapesToAvoid //purpose : //======================================================================= void BOPAlgo_BuilderSolid::PerformShapesToAvoid() { Standard_Boolean bFound; Standard_Integer i, iCnt, aNbE, aNbF; TopAbs_Orientation aOrE; BOPCol_IndexedDataMapOfShapeListOfShape aMEF; BOPCol_ListIteratorOfListOfShape aIt; // myShapesToAvoid.Clear(); // iCnt=0; for(;;) { ++iCnt; bFound=Standard_False; // // 1. MEF aMEF.Clear(); aIt.Initialize (myShapes); for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aF=aIt.Value(); if (!myShapesToAvoid.Contains(aF)) { BOPTools::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF); } } aNbE=aMEF.Extent(); // // 2. myFacesToAvoid for (i=1; i<=aNbE; ++i) { const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aMEF.FindKey(i))); if (BRep_Tool::Degenerated(aE)) { continue; } // BOPCol_ListOfShape& aLF=aMEF.ChangeFromKey(aE); aNbF=aLF.Extent(); if (!aNbF) { continue; } // aOrE=aE.Orientation(); // const TopoDS_Face& aF1=(*(TopoDS_Face*)(&aLF.First())); if (aNbF==1) { if (aOrE==TopAbs_INTERNAL) { continue; } bFound=Standard_True; myShapesToAvoid.Add(aF1); } else if (aNbF==2) { const TopoDS_Face& aF2=(*(TopoDS_Face*)(&aLF.Last())); if (aF2.IsSame(aF1)) { if (BRep_Tool::IsClosed(aE, aF1)) { continue; } // if (aOrE==TopAbs_INTERNAL) { continue; } // bFound=Standard_True; myShapesToAvoid.Add(aF1); myShapesToAvoid.Add(aF2); } } }// for (i=1; i<=aNbE; ++i) { // if (!bFound) { break; } // }//for(;;) { } //======================================================================= //function : PerformLoops //purpose : //======================================================================= void BOPAlgo_BuilderSolid::PerformLoops() { Standard_Integer i, aNbSh; BOPCol_ListIteratorOfListOfShape aIt; TopoDS_Iterator aItS; Handle(NCollection_BaseAllocator) aAlr; // myLoops.Clear(); // aAlr= NCollection_BaseAllocator::CommonBaseAllocator(); BOPAlgo_ShellSplitter aSSp(aAlr); // // 1. Shells Usual aIt.Initialize (myShapes); for (; aIt.More(); aIt.Next()) { const TopoDS_Face& aF=*((TopoDS_Face*)&aIt.Value()); if (myContext->IsInfiniteFace(aF)) { TopoDS_Shell aSh; BRep_Builder aBB; // aBB.MakeShell(aSh); aBB.Add(aSh, aF); myLoops.Append(aSh); continue; } // if (!myShapesToAvoid.Contains(aF)) { aSSp.AddStartElement(aF); } } // aSSp.SetRunParallel(myRunParallel); aSSp.Perform(); if (aSSp.HasErrors()) { // add warning status { TopoDS_Compound aFacesSp; BRep_Builder().MakeCompound(aFacesSp); BOPCol_ListIteratorOfListOfShape aItLF(aSSp.StartElements()); for (; aItLF.More(); aItLF.Next()) { BRep_Builder().Add(aFacesSp, aItLF.Value()); } AddWarning (new BOPAlgo_AlertShellSplitterFailed (aFacesSp)); } return; } // const BOPCol_ListOfShape& aLSh=aSSp.Shells(); aIt.Initialize (aLSh); for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aSh=aIt.Value(); myLoops.Append(aSh); } //================================================= // // 2. Post Treatment BRep_Builder aBB; BOPCol_MapOfOrientedShape AddedFacesMap; BOPCol_IndexedDataMapOfShapeListOfShape aEFMap; BOPCol_MapOfOrientedShape aMP; // // a. collect all edges that are in loops aIt.Initialize (myLoops); for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aS=aIt.Value(); aItS.Initialize(aS); for (; aItS.More(); aItS.Next()) { const TopoDS_Shape& aF=aItS.Value(); aMP.Add(aF); } } // // b. collect all edges that are to avoid aNbSh = myShapesToAvoid.Extent(); for (i = 1; i <= aNbSh; ++i) { const TopoDS_Shape& aF = myShapesToAvoid(i); aMP.Add(aF); } // // c. add all edges that are not processed to myShapesToAvoid aIt.Initialize (myShapes); for (; aIt.More(); aIt.Next()) { const TopoDS_Face& aF=*((TopoDS_Face*)&aIt.Value()); if (!myContext->IsInfiniteFace(aF)) { if (!aMP.Contains(aF)) { myShapesToAvoid.Add(aF); } } } //================================================= // // 3.Internal Shells myLoopsInternal.Clear(); // aEFMap.Clear(); AddedFacesMap.Clear(); // aNbSh = myShapesToAvoid.Extent(); for (i = 1; i <= aNbSh; ++i) { const TopoDS_Shape& aFF = myShapesToAvoid(i); BOPTools::MapShapesAndAncestors(aFF, TopAbs_EDGE, TopAbs_FACE, aEFMap); } // for (i = 1; i <= aNbSh; ++i) { const TopoDS_Shape& aFF = myShapesToAvoid(i); if (!AddedFacesMap.Add(aFF)) { continue; } // // make a new shell TopExp_Explorer aExp; TopoDS_Shell aShell; aBB.MakeShell(aShell); aBB.Add(aShell, aFF); // aItS.Initialize(aShell); for (; aItS.More(); aItS.Next()) { const TopoDS_Face& aF = (*(TopoDS_Face*)(&aItS.Value())); // aExp.Init(aF, TopAbs_EDGE); for (; aExp.More(); aExp.Next()) { const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current())); const BOPCol_ListOfShape& aLF=aEFMap.FindFromKey(aE); aIt.Initialize(aLF); for (; aIt.More(); aIt.Next()) { const TopoDS_Face& aFL=(*(TopoDS_Face*)(&aIt.Value())); if (AddedFacesMap.Add(aFL)){ aBB.Add(aShell, aFL); } } } } aShell.Closed (BRep_Tool::IsClosed (aShell)); myLoopsInternal.Append(aShell); } } //======================================================================= //function : PerformAreas //purpose : //======================================================================= void BOPAlgo_BuilderSolid::PerformAreas() { myAreas.Clear(); BRep_Builder aBB; // The new solids BOPCol_ListOfShape aNewSolids; // The hole shells which has to be classified relatively new solids BOPCol_IndexedMapOfShape aHoleShells; // Map of the faces of the hole shells for quick check of the growths. // If the analyzed shell contains any of the hole faces, it is considered as growth. BOPCol_IndexedMapOfShape aMHF; // Analyze the shells BOPCol_ListIteratorOfListOfShape aItLL(myLoops); for (; aItLL.More(); aItLL.Next()) { const TopoDS_Shape& aShell = aItLL.Value(); Standard_Boolean bIsGrowth = IsGrowthShell(aShell, aMHF); if (!bIsGrowth) { // Fast check did not give the result, run classification bIsGrowth = !IsHole(aShell, myContext); } // Save the solid if (bIsGrowth) { TopoDS_Solid aSolid; aBB.MakeSolid(aSolid); aBB.Add (aSolid, aShell); aNewSolids.Append (aSolid); } else { aHoleShells.Add(aShell); BOPTools::MapShapes(aShell, TopAbs_FACE, aMHF); } } if (aHoleShells.IsEmpty()) { // No holes, stop the analysis myAreas.Append(aNewSolids); return; } // Classify holes relatively solids // Prepare tree filler with the boxes of the hole shells BOPCol_BoxBndTree aBBTree; NCollection_UBTreeFiller aTreeFiller(aBBTree); Standard_Integer i, aNbH = aHoleShells.Extent(); for (i = 1; i <= aNbH; ++i) { const TopoDS_Shape& aHShell = aHoleShells(i); // Bnd_Box aBox; BRepBndLib::Add(aHShell, aBox); aTreeFiller.Add(i, aBox); } // Shake TreeFiller aTreeFiller.Fill(); // Find outer growth shell that is most close to each hole shell BOPCol_IndexedDataMapOfShapeShape aHoleSolidMap; BOPCol_ListIteratorOfListOfShape aItLS(aNewSolids); for (; aItLS.More(); aItLS.Next()) { const TopoDS_Shape& aSolid = aItLS.Value(); // Build box Bnd_Box aBox; BRepBndLib::Add(aSolid, aBox); BOPCol_BoxBndTreeSelector aSelector; aSelector.SetBox(aBox); aBBTree.Select(aSelector); const BOPCol_ListOfInteger& aLI = aSelector.Indices(); BOPCol_ListIteratorOfListOfInteger aItLI(aLI); for (; aItLI.More(); aItLI.Next()) { Standard_Integer k = aItLI.Value(); const TopoDS_Shape& aHole = aHoleShells(k); // Check if it is inside if (!IsInside(aHole, aSolid, myContext)) continue; // Save the relation TopoDS_Shape* pSolidWas = aHoleSolidMap.ChangeSeek(aHole); if (pSolidWas) { if (IsInside(aSolid, *pSolidWas, myContext)) { *pSolidWas = aSolid; } } else { aHoleSolidMap.Add(aHole, aSolid); } } } // Make the back map from solids to holes BOPCol_IndexedDataMapOfShapeListOfShape aSolidHolesMap; aNbH = aHoleSolidMap.Extent(); for (i = 1; i <= aNbH; ++i) { const TopoDS_Shape& aHole = aHoleSolidMap.FindKey(i); const TopoDS_Shape& aSolid = aHoleSolidMap(i); // BOPCol_ListOfShape* pLHoles = aSolidHolesMap.ChangeSeek(aSolid); if (!pLHoles) pLHoles = &aSolidHolesMap(aSolidHolesMap.Add(aSolid, BOPCol_ListOfShape())); pLHoles->Append(aHole); } // Add Holes to Solids and add them to myAreas aItLS.Initialize(aNewSolids); for ( ; aItLS.More(); aItLS.Next()) { TopoDS_Solid& aSolid = *(TopoDS_Solid*)&aItLS.Value(); const BOPCol_ListOfShape* pLHoles = aSolidHolesMap.Seek(aSolid); if (pLHoles) { // update solid BOPCol_ListIteratorOfListOfShape aItLH(*pLHoles); for (; aItLH.More(); aItLH.Next()) { const TopoDS_Shape& aHole = aItLH.Value(); aBB.Add(aSolid, aHole); } // update classifier myContext->SolidClassifier(aSolid).Load(aSolid); } myAreas.Append(aSolid); } // Add holes that outside the solids to myAreas aNbH = aHoleShells.Extent(); for (i = 1; i <= aNbH; ++i) { const TopoDS_Shape& aHole = aHoleShells(i); if (!aHoleSolidMap.Contains(aHole)) { TopoDS_Solid aSolid; aBB.MakeSolid(aSolid); aBB.Add (aSolid, aHole); // myAreas.Append(aSolid); } } } //======================================================================= //function : PerformInternalShapes //purpose : //======================================================================= void BOPAlgo_BuilderSolid::PerformInternalShapes() { if (myAvoidInternalShapes) { return; } // Standard_Integer aNbFI=myLoopsInternal.Extent(); if (!aNbFI) {// nothing to do return; } // Standard_Boolean bIsInternalFace; Standard_Integer k, aNbVFS, aNbSLF, aNbVFP, aNbA; BRep_Builder aBB; TopoDS_Iterator aIt; TopExp_Explorer aExp; BOPCol_ListIteratorOfListOfShape aItLS; BOPCol_IndexedMapOfShape aMFs; BOPCol_ListOfShape aLSI; BOPAlgo_VectorOfFaceSolid aVFS; BOPAlgo_VectorOfFacePnt aVFP; BOPCol_ListIteratorOfListOfInteger aItLI; BOPCol_BoxBndTreeSelector aSelector; BOPCol_BoxBndTree aBBTree; NCollection_UBTreeFiller aTreeFiller(aBBTree); // aNbA=myAreas.Extent(); // // 1. aVFP aItLS.Initialize(myLoopsInternal); for (; aItLS.More(); aItLS.Next()) { const TopoDS_Shape& aShell=aItLS.Value(); aIt.Initialize(aShell); for (; aIt.More(); aIt.Next()) { const TopoDS_Face& aF=*((TopoDS_Face*)&aIt.Value()); // if (!aMFs.Contains(aF)) { aMFs.Add(aF); // gp_Pnt aP; gp_Pnt2d aP2D; // if (aNbA) { BOPTools_AlgoTools3D::PointInFace(aF, aP, aP2D, myContext); } // BOPAlgo_FacePnt& aFP=aVFP.Append1(); aFP.SetFace(aF); aFP.SetPnt(aP); } } } // if (!aNbA) { // 7b. "Rest" faces treatment TopoDS_Solid aSolid; aBB.MakeSolid(aSolid); // MakeInternalShells(aMFs, aLSI); // aItLS.Initialize(aLSI); for (; aItLS.More(); aItLS.Next()) { const TopoDS_Shape& aSI=aItLS.Value(); aBB.Add (aSolid, aSI); } myAreas.Append(aSolid); // return; // => }//if (!aNbA) { // // 2. Prepare TreeFiller aNbVFP=aVFP.Extent(); for(k=0; kSolidClassifier(*pS2); // aClsf.PerformInfinitePoint(::RealSmall()); // return (aClsf.State()==TopAbs_IN); } //======================================================================= //function : IsInside //purpose : //======================================================================= Standard_Boolean IsInside(const TopoDS_Shape& theS1, const TopoDS_Shape& theS2, Handle(IntTools_Context)& theContext) { TopExp_Explorer aExp; TopAbs_State aState; // TopoDS_Solid *pS2=(TopoDS_Solid *)&theS2; // aExp.Init(theS1, TopAbs_FACE); if (!aExp.More()){ BRepClass3d_SolidClassifier& aClsf=theContext->SolidClassifier(*pS2); aClsf.PerformInfinitePoint(::RealSmall()); aState=aClsf.State(); } else { BOPCol_IndexedMapOfShape aBounds; BOPTools::MapShapes(*pS2, TopAbs_EDGE, aBounds); const TopoDS_Face& aF = (*(TopoDS_Face*)(&aExp.Current())); aState=BOPTools_AlgoTools::ComputeState(aF, *pS2, Precision::Confusion(), aBounds, theContext); } return (aState==TopAbs_IN); } //======================================================================= //function : IsGrowthShell //purpose : //======================================================================= Standard_Boolean IsGrowthShell(const TopoDS_Shape& theShell, const BOPCol_IndexedMapOfShape& theMHF) { if (theMHF.Extent()) { TopoDS_Iterator aIt(theShell); for(; aIt.More(); aIt.Next()) { if (theMHF.Contains(aIt.Value())) return Standard_True; } } return Standard_False; }