+// 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 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
+// <pkv@PETREX>
+
+#include <BOPAlgo_ShellSplitter.ixx>
+//
+#include <TopoDS_Shape.hxx>
+#include <TopoDS_Shell.hxx>
+#include <TopoDS_Edge.hxx>
+
+#include <BRep_Builder.hxx>
+#include <TopExp_Explorer.hxx>
+//
+#include <BOPCol_TBB.hxx>
+#include <BOPCol_IndexedMapOfShape.hxx>
+#include <BOPCol_MapOfShape.hxx>
+#include <BOPCol_MapOfOrientedShape.hxx>
+#include <BOPCol_NCVector.hxx>
+#include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
+//
+#include <BOPInt_Context.hxx>
+//
+#include <BOPTools.hxx>
+#include <BOPTools_AlgoTools.hxx>
+#include <BOPTools_CoupleOfShape.hxx>
+//
+typedef BOPCol_NCVector<BOPTools_ConnexityBlock> \
+ BOPAlgo_ShellSplitter_VectorOfConnexityBlock;
+//
+static
+ Standard_Boolean IsClosedShell(const TopoDS_Shell& );
+static
+ void MakeShell(const BOPCol_ListOfShape& ,
+ TopoDS_Shell& );
+
+//=======================================================================
+//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 BOPCol_ListOfShape& BOPAlgo_ShellSplitter::StartElements()const
+{
+ return myStartShapes;
+}
+//=======================================================================
+//function : Loops
+//purpose :
+//=======================================================================
+const BOPCol_ListOfShape& BOPAlgo_ShellSplitter::Shells()const
+{
+ return myShells;
+}
+//=======================================================================
+//function : Perform
+//purpose :
+//=======================================================================
+void BOPAlgo_ShellSplitter::Perform()
+{
+ myErrorStatus=0;
+ //
+ MakeConnexityBlocks();
+ if (myErrorStatus) {
+ return;
+ }
+ //
+ MakeShells();
+}
+//=======================================================================
+//function : MakeConnexityBlocks
+//purpose :
+//=======================================================================
+void BOPAlgo_ShellSplitter::MakeConnexityBlocks()
+{
+ Standard_Boolean bRegular;
+ Standard_Integer i, j, aNbE, aNbES, aNbEP, k, aNbCB;
+ TopoDS_Shape aFR;
+ TopExp_Explorer aExpF;
+ BOPCol_IndexedDataMapOfShapeListOfShape aMEF(100, myAllocator);
+ BOPCol_IndexedMapOfShape aMEP(100, myAllocator);
+ BOPCol_IndexedMapOfShape aMFC(100, myAllocator);
+ BOPCol_MapOfShape aMER(100, myAllocator);
+ BOPCol_MapOfShape aMFP(100, myAllocator);
+ BOPCol_IndexedMapOfShape aMEAdd(100, myAllocator);
+ BOPCol_MapOfShape aMES(100, myAllocator);
+ BOPCol_ListIteratorOfListOfShape aIt;
+ //
+ myErrorStatus=0;
+ //
+ myLCB.Clear();
+ //
+ const BOPCol_ListOfShape& aLSE=myStartShapes;
+ aIt.Initialize(aLSE);
+ for (i=1; aIt.More(); aIt.Next(), ++i) {
+ const TopoDS_Shape& aSE=aIt.Value();
+ if (!aMEP.Contains(aSE)) {
+ aMEP.Add(aSE);
+ BOPTools::MapShapesAndAncestors(aSE,
+ TopAbs_EDGE, TopAbs_FACE,
+ aMEF);
+ }
+ else {
+ aMER.Add(aSE);
+ }
+ }
+ //
+ // 2
+ aNbE=aMEF.Extent();
+ for (i=1; i<=aNbE; ++i) {
+ aNbES=aMES.Extent();
+ if (aNbES==aNbE) {
+ break;
+ }
+ //
+ const TopoDS_Shape& aE=aMEF.FindKey(i);
+ //
+ if (!aMES.Add(aE)) {
+ continue;
+ }
+ // aMES - globally processed edges
+ //
+ //------------------------------------- goal: aMEC
+ aMFC.Clear(); // aMEC - edges of CB
+ aMEP.Clear(); // aMVP - edges to process right now
+ aMEAdd.Clear(); // aMVAdd edges to process on next step of for(;;) {
+ //
+ aMEP.Add(aE);
+ //
+ for(;;) {
+ aNbEP=aMEP.Extent();
+ for (k=1; k<=aNbEP; ++k) {
+ const TopoDS_Shape& aEP=aMEP(k);
+ const BOPCol_ListOfShape& aLF=aMEF.FindFromKey(aEP);
+ aIt.Initialize(aLF);
+ for (; aIt.More(); aIt.Next()) {
+ const TopoDS_Shape& aF=aIt.Value();
+ if (aMFC.Add(aF)) {
+ aExpF.Init(aF, TopAbs_EDGE);
+ for (; aExpF.More(); aExpF.Next()) {
+ const TopoDS_Shape& aEF=aExpF.Current();
+ if (aMES.Add(aEF)) {
+ aMEAdd.Add(aEF);
+ }
+ }
+ }
+ }
+ }
+ //
+ aNbEP=aMEAdd.Extent();
+ if (!aNbEP) {
+ break; // from for(;;) {
+ }
+ //
+ aMEP.Clear();
+ //
+ for (k=1; k<=aNbEP; ++k) {
+ const TopoDS_Shape& aEF=aMEAdd(k);
+ aMEP.Add(aEF);
+ }
+ aMEAdd.Clear();
+ }// for(;;) {
+ //
+ //-------------------------------------
+ BOPTools_ConnexityBlock aCB(myAllocator);
+ //
+ BOPCol_ListOfShape& aLECB=aCB.ChangeShapes();
+ BOPCol_IndexedDataMapOfShapeListOfShape aMEFR(100, myAllocator);
+ //
+ bRegular=Standard_True;
+ aNbCB = aMFC.Extent();
+ for (j=1; j<=aNbCB; ++j) {
+ aFR = aMFC(j);
+ //
+ if (aMER.Contains(aFR)) {
+ aFR.Orientation(TopAbs_FORWARD);
+ aLECB.Append(aFR);
+ aFR.Orientation(TopAbs_REVERSED);
+ aLECB.Append(aFR);
+ bRegular=Standard_False;
+ }
+ else {
+ aLECB.Append(aFR);
+ }
+ //
+ if (bRegular) {
+ BOPTools::MapShapesAndAncestors(aFR,
+ TopAbs_EDGE, TopAbs_FACE,
+ aMEFR);
+ }
+ }
+ //
+ if (bRegular) {
+ Standard_Integer aNbER, aNbFR;
+ //
+ aNbER=aMEFR.Extent();
+ for (k=1; k<=aNbER; ++k) {
+ const BOPCol_ListOfShape& aLFR=aMEFR(k);
+ aNbFR=aLFR.Extent();
+ if (aNbFR>2) {
+ bRegular=!bRegular;
+ break;
+ }
+ }
+ }
+ //
+ aCB.SetRegular(bRegular);
+ myLCB.Append(aCB);
+ }
+}
+//=======================================================================
+//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;
+ BOPCol_ListIteratorOfListOfShape aItF;
+ BOPTools_CoupleOfShape aCSOff;
+ BOPCol_MapOfOrientedShape AddedFacesMap;
+ BOPCol_IndexedDataMapOfShapeListOfShape aEFMap, aMEFP;
+ //
+ Handle (BOPInt_Context) aContext=new BOPInt_Context;
+ //
+ const BOPCol_ListOfShape& myShapes=aCB.Shapes();
+ //
+ BOPCol_ListOfShape& myLoops=aCB.ChangeLoops();
+ myLoops.Clear();
+ //
+ // 1. Shells Usual
+ aItF.Initialize (myShapes);
+ for (; aItF.More(); aItF.Next()) {
+ const TopoDS_Shape& aFF = aItF.Value();
+ BOPTools::MapShapesAndAncestors
+ (aFF, TopAbs_EDGE, TopAbs_FACE, aEFMap);
+ }
+ //
+ aItF.Initialize (myShapes);
+ for (i=1; aItF.More(); aItF.Next(), ++i) {
+ const TopoDS_Shape& aFF = aItF.Value();
+ if (!AddedFacesMap.Add(aFF)) {
+ continue;
+ }
+ //
+ // make a new shell
+ TopoDS_Shell aShell;
+ aBB.MakeShell(aShell);
+ aBB.Add(aShell, aFF);
+ //
+ aMEFP.Clear();
+ BOPTools::MapShapesAndAncestors(aFF,
+ 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()));
+ //
+ // 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()));
+ //
+ //1
+ if (aMEFP.Contains(aE)) {
+ const BOPCol_ListOfShape& aLFP=aMEFP.FindFromKey(aE);
+ aNbFP=aLFP.Extent();
+ if (aNbFP>1) {
+ continue;
+ }
+ }
+ //2
+ anOr=aE.Orientation();
+ if (anOr==TopAbs_INTERNAL) {
+ continue;
+ }
+ //3
+ if (BRep_Tool::Degenerated(aE)) {
+ continue;
+ }
+ //
+ // candidate faces list
+ const BOPCol_ListOfShape& aLF=aEFMap.FindFromKey(aE);
+ aNbLF=aLF.Extent();
+ if (!aNbLF) {
+ continue;
+ }
+ //
+ // try to select one of neighbors
+ // check if a face already added to Shell shares E
+ Standard_Boolean bFound;
+ BOPCol_ListIteratorOfListOfShape aItLF;
+ BOPTools_ListOfCoupleOfShape aLCSOff;
+ //
+ aItLF.Initialize(aLF);
+ for (; aItLF.More(); aItLF.Next()) {
+ const TopoDS_Face& aFL=(*(TopoDS_Face*)(&aItLF.Value()));
+ if (aF.IsSame(aFL)) {
+ continue;
+ }
+ if (AddedFacesMap.Contains(aFL)){
+ continue;
+ }
+ //
+ bFound=BOPTools_AlgoTools::GetEdgeOff(aE, aFL, aEL);
+ if (!bFound) {
+ continue;
+ }
+ //
+ aCSOff.SetShape1(aEL);
+ aCSOff.SetShape2(aFL);
+ aLCSOff.Append(aCSOff);
+ }//for (; aItLF.More(); aItLF.Next()) {
+ //
+ aNbOff=aLCSOff.Extent();
+ if (!aNbOff){
+ continue;
+ }
+ //
+ TopoDS_Face aSelF;
+ 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);
+ BOPTools::MapShapesAndAncestors(aSelF,
+ TopAbs_EDGE, TopAbs_FACE,
+ aMEFP);
+ }
+ } // for (; aEdgeExp.More(); aEdgeExp.Next()) {
+ } //for (; aItAddedF.More(); aItAddedF.Next()) {
+ //
+ if (IsClosedShell(aShell)) {
+ myLoops.Append(aShell);
+ }
+ } // for (; aItF.More(); aItF.Next()) {
+}
+//=======================================================================
+//class : ShellSplitterFunctor
+//purpose : Auxiliary class
+//=======================================================================
+class BOPAlgo_ShellSplitterFunctor {
+ protected:
+ TopoDS_Face myFace;
+ BOPAlgo_ShellSplitter_VectorOfConnexityBlock* myPVCB;
+ //
+ public:
+ BOPAlgo_ShellSplitterFunctor
+ (BOPAlgo_ShellSplitter_VectorOfConnexityBlock& aVCB)
+ : myPVCB(&aVCB) {
+ }
+ //
+ void operator()( const flexible_range<Standard_Size>& aBR ) const{
+ Standard_Size i, iBeg, iEnd;
+ //
+ BOPAlgo_ShellSplitter_VectorOfConnexityBlock& aVCB=*myPVCB;
+ //
+ iBeg=aBR.begin();
+ iEnd=aBR.end();
+ for(i=iBeg; i!=iEnd; ++i) {
+ BOPTools_ConnexityBlock& aCB=aVCB((Standard_Integer)i);
+ //
+ BOPAlgo_ShellSplitter::SplitBlock(aCB);
+ }
+ }
+};
+//=======================================================================
+//class : BOPAlgo_ShellSplitterCnt
+//purpose : Auxiliary class
+//=======================================================================
+class BOPAlgo_ShellSplitterCnt {
+ public:
+ //-------------------------------
+ // Perform
+ Standard_EXPORT
+ static void Perform
+ (const Standard_Boolean bRunParallel,
+ BOPAlgo_ShellSplitter_VectorOfConnexityBlock& aVCB) {
+ //
+ BOPAlgo_ShellSplitterFunctor aSSF(aVCB);
+ Standard_Size aNbVCB=aVCB.Extent();
+ //
+ if (bRunParallel) {
+ flexible_for(flexible_range<Standard_Size>(0,aNbVCB), aSSF);
+ }
+ else {
+ aSSF.operator()(flexible_range<Standard_Size>(0,aNbVCB));
+ }
+ }
+};
+//=======================================================================
+//function : MMakeShells
+//purpose :
+//=======================================================================
+void BOPAlgo_ShellSplitter::MakeShells()
+{
+ Standard_Boolean bIsRegular;
+ Standard_Integer aNbVCB, k;
+ BOPTools_ListIteratorOfListOfConnexityBlock aItCB;
+ BOPCol_ListIteratorOfListOfShape aIt;
+ BOPAlgo_ShellSplitter_VectorOfConnexityBlock aVCB;
+ //
+ myErrorStatus=0;
+ myShells.Clear();
+ //
+ aItCB.Initialize(myLCB);
+ for (; aItCB.More(); aItCB.Next()) {
+ BOPTools_ConnexityBlock& aCB=aItCB.ChangeValue();
+ bIsRegular=aCB.IsRegular();
+ if (bIsRegular) {
+ TopoDS_Shell aShell;
+ //
+ const BOPCol_ListOfShape& aLF=aCB.Shapes();
+ MakeShell(aLF, aShell);
+ myShells.Append(aShell);
+ }
+ else {
+ aVCB.Append(aCB);
+ }
+ }
+ //
+ aNbVCB=aVCB.Extent();
+ //===================================================
+ BOPAlgo_ShellSplitterCnt::Perform(myRunParallel, aVCB);
+ //===================================================
+ for (k=0; k<aNbVCB; ++k) {
+ const BOPTools_ConnexityBlock& aCB=aVCB(k);
+ const BOPCol_ListOfShape& aLS=aCB.Loops();
+ aIt.Initialize(aLS);
+ for (; aIt.More(); aIt.Next()) {
+ const TopoDS_Shape& aShell=aIt.Value();
+ myShells.Append(aShell);
+ }
+ }
+}
+//=======================================================================
+//function : IsClosedShell
+//purpose :
+//=======================================================================
+Standard_Boolean IsClosedShell(const TopoDS_Shell& theShell)
+{
+ Standard_Integer aNbE;
+ Standard_Boolean bRet;
+ TopoDS_Iterator aIt;
+ TopExp_Explorer aExp;
+ BOPCol_MapOfShape aM;
+ //
+ bRet=Standard_False;
+ aIt.Initialize(theShell);
+ for(; aIt.More(); aIt.Next()) {
+ const TopoDS_Face& aF=(*(TopoDS_Face*)(&aIt.Value()));
+ aExp.Init(aF, TopAbs_EDGE);
+ for (; aExp.More(); aExp.Next()) {
+ const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current()));
+ if (BRep_Tool::Degenerated(aE)) {
+ continue;
+ }
+ //
+ if (aE.Orientation()==TopAbs_INTERNAL) {
+ continue;
+ }
+ if (!aM.Add(aE)) {
+ aM.Remove(aE);
+ }
+ }
+ }
+ //
+ aNbE=aM.Extent();
+ if (!aNbE) {
+ bRet=!bRet;
+ }
+ return bRet;
+}
+//=======================================================================
+//function : MakeShell
+//purpose :
+//=======================================================================
+void MakeShell(const BOPCol_ListOfShape& aLS,
+ TopoDS_Shell& aShell)
+{
+ BRep_Builder aBB;
+ BOPCol_ListIteratorOfListOfShape aIt;
+ //
+ aBB.MakeShell(aShell);
+ //
+ aIt.Initialize(aLS);
+ for (; aIt.More(); aIt.Next()) {
+ const TopoDS_Shape& aF=aIt.Value();
+ aBB.Add(aShell, aF);
+ }
+}