// Created by: Peter KURNEV // Copyright (c) 1999-2014 OPEN CASCADE SAS // // 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. // File: BOPAlgo_ShellSplitter.cxx // Created: Thu Jan 16 08:33:50 2014 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // static void MakeShell(const TopTools_ListOfShape& , TopoDS_Shell& ); // static void RefineShell(TopoDS_Shell& theShell, const TopTools_IndexedDataMapOfShapeListOfShape& theMEF, TopTools_ListOfShape& aLShX); //======================================================================= //class : BOPAlgo_CBK //purpose : //======================================================================= class BOPAlgo_CBK { public: BOPAlgo_CBK() : myPCB (NULL) { } // ~BOPAlgo_CBK() { } // void SetConnexityBlock (const BOPTools_ConnexityBlock& aCB) { myPCB=(BOPTools_ConnexityBlock*)&aCB; } // BOPTools_ConnexityBlock& ConnexityBlock () { return *myPCB; } // void Perform() { BOPAlgo_ShellSplitter::SplitBlock(*myPCB); } protected: BOPTools_ConnexityBlock *myPCB; }; //======================================================================= typedef NCollection_Vector BOPAlgo_VectorOfCBK; //======================================================================= //function : //purpose : //======================================================================= BOPAlgo_ShellSplitter::BOPAlgo_ShellSplitter() : BOPAlgo_Algo(), myStartShapes(myAllocator), myShells(myAllocator), myLCB(myAllocator) { } //======================================================================= //function : //purpose : //======================================================================= BOPAlgo_ShellSplitter::BOPAlgo_ShellSplitter (const Handle(NCollection_BaseAllocator)& theAllocator) : BOPAlgo_Algo(theAllocator), myStartShapes(theAllocator), myShells(theAllocator), myLCB(myAllocator) { } //======================================================================= //function : ~ //purpose : //======================================================================= BOPAlgo_ShellSplitter::~BOPAlgo_ShellSplitter() { } //======================================================================= //function : AddStartElement //purpose : //======================================================================= void BOPAlgo_ShellSplitter::AddStartElement(const TopoDS_Shape& aE) { myStartShapes.Append(aE); } //======================================================================= //function : StartElements //purpose : //======================================================================= const TopTools_ListOfShape& BOPAlgo_ShellSplitter::StartElements()const { return myStartShapes; } //======================================================================= //function : Loops //purpose : //======================================================================= const TopTools_ListOfShape& BOPAlgo_ShellSplitter::Shells()const { return myShells; } //======================================================================= //function : Perform //purpose : //======================================================================= void BOPAlgo_ShellSplitter::Perform() { GetReport()->Clear(); // BOPTools_AlgoTools::MakeConnexityBlocks (myStartShapes, TopAbs_EDGE, TopAbs_FACE, myLCB); // MakeShells(); } //======================================================================= //function : SplitBlock //purpose : //======================================================================= void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB) { Standard_Integer aNbLF, aNbOff, aNbFP; Standard_Integer i; TopAbs_Orientation anOr; TopoDS_Edge aEL; BRep_Builder aBB; TopoDS_Iterator aItS; TopExp_Explorer aExp; TopTools_ListIteratorOfListOfShape aItF; BOPTools_CoupleOfShape aCSOff; TopTools_MapOfOrientedShape AddedFacesMap; TopTools_IndexedDataMapOfShapeListOfShape aEFMap, aMEFP; Handle (IntTools_Context) aContext; // aContext=new IntTools_Context; // const TopTools_ListOfShape& myShapes=aCB.Shapes(); // TopTools_ListOfShape& myLoops=aCB.ChangeLoops(); myLoops.Clear(); // // Copy faces into the map, for recursive search of free bounds TopTools_MapOfOrientedShape aMFaces; aItF.Initialize (myShapes); for (; aItF.More(); aItF.Next()) { aMFaces.Add(aItF.Value()); } // // remove the faces with free edges from processing for (;;) { // map the shapes aEFMap.Clear(); aItF.Initialize(myShapes); for (; aItF.More(); aItF.Next()) { const TopoDS_Shape& aF = aItF.Value(); if (aMFaces.Contains(aF)) { TopExp::MapShapesAndAncestors (aF, TopAbs_EDGE, TopAbs_FACE, aEFMap); } } // Standard_Integer aNbBegin = aMFaces.Extent(); // check the free edges Standard_Integer aNbE = aEFMap.Extent(); for (i = 1; i <= aNbE; ++i) { const TopoDS_Edge& aE = TopoDS::Edge(aEFMap.FindKey(i)); if (!(BRep_Tool::Degenerated(aE) || aE.Orientation() == TopAbs_INTERNAL)) { const TopTools_ListOfShape& aLF = aEFMap(i); if (aLF.Extent() == 1) { // remove the face aMFaces.Remove(aLF.First()); } } } // // check if any faces have been removed Standard_Integer aNbEnd = aMFaces.Extent(); if ((aNbEnd == aNbBegin) || (aNbEnd == 0)) { break; } } // if (aMFaces.IsEmpty()) { return; } // // use only connected faces TopTools_ListOfShape aLFConnected; // Boundary faces TopTools_MapOfShape aBoundaryFaces; aItF.Initialize (myShapes); for (; aItF.More(); aItF.Next()) { const TopoDS_Shape& aF = aItF.Value(); if (aMFaces.Contains(aF)) { aLFConnected.Append(aF); if (!aBoundaryFaces.Add (aF)) aBoundaryFaces.Remove (aF); } } // const Standard_Integer aNbShapes = aLFConnected.Extent(); Standard_Boolean bAllFacesTaken = Standard_False; // // Build the shells aItF.Initialize (aLFConnected); for (i = 1; aItF.More() && !bAllFacesTaken; aItF.Next(), ++i) { const TopoDS_Shape& aFF = aItF.Value(); if (!AddedFacesMap.Add(aFF)) { continue; } // // make a new shell TopoDS_Shell aShellStart; aBB.MakeShell(aShellStart); aBB.Add(aShellStart, aFF); // TopTools_ListOfShape aLShells; aLShells.Append(aShellStart); // TopTools_ListIteratorOfListOfShape aItLShells(aLShells); for (; aItLShells.More(); aItLShells.Next()) { TopoDS_Shell& aShell = TopoDS::Shell(aItLShells.ChangeValue()); // aMEFP.Clear(); TopExp::MapShapesAndAncestors(aShell, TopAbs_EDGE, TopAbs_FACE, aMEFP); // // loop on faces added to Shell; // add their neighbor faces to Shell and so on aItS.Initialize(aShell); for (; aItS.More(); aItS.Next()) { const TopoDS_Face& aF = (*(TopoDS_Face*)(&aItS.Value())); Standard_Boolean isBoundary = aBoundaryFaces.Contains (aF); // // loop on edges of aF; find a good neighbor face of aF by aE aExp.Init(aF, TopAbs_EDGE); for (; aExp.More(); aExp.Next()) { const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current())); // // proceed only free edges in this shell if (aMEFP.Contains(aE)) { const TopTools_ListOfShape& aLFP = aMEFP.FindFromKey(aE); aNbFP = aLFP.Extent(); if (aNbFP > 1) { continue; } } // avoid processing of internal edges anOr = aE.Orientation(); if (anOr == TopAbs_INTERNAL) { continue; } // avoid processing of degenerated edges if (BRep_Tool::Degenerated(aE)) { continue; } // // candidate faces list const TopTools_ListOfShape& aLF = aEFMap.FindFromKey(aE); aNbLF = aLF.Extent(); if (!aNbLF) { continue; } // // prepare for selecting the next face // take only not-processed faces as a candidates BOPTools_ListOfCoupleOfShape aLCSOff; // Standard_Integer aNbWaysInside = 0; TopoDS_Face aSelF; TopTools_ListIteratorOfListOfShape aItLF(aLF); for (; aItLF.More(); aItLF.Next()) { const TopoDS_Face& aFL = (*(TopoDS_Face*)(&aItLF.Value())); if (aF.IsSame(aFL) || AddedFacesMap.Contains(aFL)) { continue; } // // find current edge in the face if (!BOPTools_AlgoTools::GetEdgeOff(aE, aFL, aEL)) { continue; } // if (isBoundary && !aBoundaryFaces.Contains (aFL)) { ++aNbWaysInside; aSelF = aFL; } aCSOff.SetShape1(aEL); aCSOff.SetShape2(aFL); aLCSOff.Append(aCSOff); }//for (; aItLF.More(); aItLF.Next()) { // aNbOff = aLCSOff.Extent(); if (!aNbOff){ continue; } // // among all the adjacent faces chose one with the minimal // angle to the current one if (!isBoundary || aNbWaysInside != 1) { if (aNbOff == 1) { aSelF = (*(TopoDS_Face*)(&aLCSOff.First().Shape2())); } else if (aNbOff > 1) { BOPTools_AlgoTools::GetFaceOff(aE, aF, aLCSOff, aSelF, aContext); } } // if (!aSelF.IsNull() && AddedFacesMap.Add(aSelF)) { aBB.Add(aShell, aSelF); TopExp::MapShapesAndAncestors(aSelF, TopAbs_EDGE, TopAbs_FACE, aMEFP); } } // for (; aExp.More(); aExp.Next()) { } // for (; aItS.More(); aItS.Next()) { // // split the shell on multi-connected edges TopTools_ListOfShape aLShSp; RefineShell(aShell, aMEFP, aLShSp); // // collect the not closed shells for further processing TopTools_ListOfShape aLShNC; // TopTools_ListIteratorOfListOfShape aItLShSp(aLShSp); for (; aItLShSp.More(); aItLShSp.Next()) { TopoDS_Shell& aShSp = *((TopoDS_Shell*)&aItLShSp.Value()); // if (BRep_Tool::IsClosed(aShSp)) { aShSp.Closed(Standard_True); myLoops.Append(aShSp); } else { aLShNC.Append(aShSp); } } // bAllFacesTaken = (AddedFacesMap.Extent() == aNbShapes); if (bAllFacesTaken) { break; } // if (aLShSp.Extent() == 1) { // not further processing of not closed shells is needed, // as it will not bring any new results continue; } // Standard_Integer aNbShNC = aLShNC.Extent(); if (aNbShNC == 1) { // try to complete the shell with other faces aLShells.Append(aLShNC); } else if (aNbShNC > 1) { // remove th faces of not closed shells from the map of processed faces // and try to rebuild the shells using all not processed faces, // because faces of one shell might be needed for building the other TopTools_ListIteratorOfListOfShape aItLShNC(aLShNC); for (; aItLShNC.More(); aItLShNC.Next()) { TopoDS_Iterator aItNC(aItLShNC.Value()); for (; aItNC.More(); aItNC.Next()) { AddedFacesMap.Remove(aItNC.Value()); } } } } } // for (; aItF.More(); aItF.Next()) { } //======================================================================= //function : RefineShell //purpose : //======================================================================= void RefineShell(TopoDS_Shell& theShell, const TopTools_IndexedDataMapOfShapeListOfShape& theMEF, TopTools_ListOfShape& theLShSp) { TopoDS_Iterator aIt(theShell); if(!aIt.More()) { return; } // // Find edges with more than 2 adjacent faces - branch edges - // edges on which the input shell should be split TopTools_MapOfShape aMEStop; // Standard_Integer i, aNbMEF = theMEF.Extent(); for (i = 1; i <= aNbMEF; ++i) { const TopoDS_Edge& aE = TopoDS::Edge(theMEF.FindKey(i)); const TopTools_ListOfShape& aLF = theMEF(i); if (aLF.Extent() > 2) { aMEStop.Add(aE); continue; } // // check for internal edges - count faces, in which the edge // is internal, twice Standard_Integer aNbF = 0; TopTools_ListIteratorOfListOfShape aItLF(aLF); for (; aItLF.More() && aNbF <= 2; aItLF.Next()) { const TopoDS_Face& aF = TopoDS::Face(aItLF.Value()); ++aNbF; TopExp_Explorer aExp(aF, TopAbs_EDGE); for (; aExp.More(); aExp.Next()) { const TopoDS_Shape& aEF = aExp.Current(); if (aEF.IsSame(aE)) { if (aEF.Orientation() == TopAbs_INTERNAL) { ++aNbF; } break; } } } // if (aNbF > 2) { aMEStop.Add(aE); } } // if (aMEStop.IsEmpty()) { theLShSp.Append(theShell); return; } // TopoDS_Builder aBB; TopExp_Explorer aExp; TopTools_IndexedMapOfShape aMFB; TopTools_MapOfOrientedShape aMFProcessed; TopTools_ListOfShape aLFP, aLFP1; TopTools_ListIteratorOfListOfShape aItLF, aItLFP; // // The first Face for (; aIt.More(); aIt.Next()) { const TopoDS_Shape& aF1 = aIt.Value(); if (!aMFProcessed.Add(aF1)) { continue; } // aMFB.Clear(); aLFP.Clear(); // aMFB.Add(aF1); aLFP.Append(aF1); // // Trying to reach the branch point for (;;) { aItLFP.Initialize(aLFP); for (; aItLFP.More(); aItLFP.Next()) { const TopoDS_Shape& aFP = aItLFP.Value(); // aExp.Init(aFP, TopAbs_EDGE); for (; aExp.More(); aExp.Next()) { const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current())); if (aMEStop.Contains(aE)) { continue; } // if (aE.Orientation() == TopAbs_INTERNAL) { continue; } // if (BRep_Tool::Degenerated(aE)) { continue; } // const TopTools_ListOfShape& aLF = theMEF.FindFromKey(aE); // aItLF.Initialize(aLF); for (; aItLF.More(); aItLF.Next()) { const TopoDS_Shape& aFP1 = aItLF.Value(); if (aFP1.IsSame(aFP)) { continue; } if (aMFB.Contains(aFP1)) { continue; } // if (aMFProcessed.Add(aFP1)) { aMFB.Add(aFP1); aLFP1.Append(aFP1); } }// for (; aItLF.More(); aItLF.Next()) { }// for (; aExp.More(); aExp.Next()) { } // for (; aItLFP.More(); aItLFP.Next()) { // // if (aLFP1.IsEmpty()) { break; } // aLFP.Clear(); aLFP.Append(aLFP1); }// for (;;) { // Standard_Integer aNbMFB = aMFB.Extent(); if (aNbMFB) { TopoDS_Shell aShSp; aBB.MakeShell(aShSp); // for (i = 1; i <= aNbMFB; ++i) { const TopoDS_Shape& aFB = aMFB(i); aBB.Add(aShSp, aFB); } theLShSp.Append(aShSp); } }//for (; aIt.More(); aIt.Next()) { } //======================================================================= //function : MakeShells //purpose : //======================================================================= void BOPAlgo_ShellSplitter::MakeShells() { Standard_Boolean bIsRegular; Standard_Integer aNbVCBK, k; BOPTools_ListIteratorOfListOfConnexityBlock aItCB; TopTools_ListIteratorOfListOfShape aIt; BOPAlgo_VectorOfCBK aVCBK; // myShells.Clear(); // aItCB.Initialize(myLCB); for (; aItCB.More(); aItCB.Next()) { BOPTools_ConnexityBlock& aCB=aItCB.ChangeValue(); bIsRegular=aCB.IsRegular(); if (bIsRegular) { TopoDS_Shell aShell; // const TopTools_ListOfShape& aLF=aCB.Shapes(); MakeShell(aLF, aShell); aShell.Closed(Standard_True); myShells.Append(aShell); } else { BOPAlgo_CBK& aCBK=aVCBK.Appended(); aCBK.SetConnexityBlock(aCB); } } // aNbVCBK=aVCBK.Length(); //=================================================== BOPTools_Parallel::Perform (myRunParallel, aVCBK); //=================================================== for (k=0; k