62d08b2eb1bf4e15cfae42f42d4cf283e82901b4
[occt.git] / src / BOPAlgo / BOPAlgo_ShellSplitter.cxx
1 // Created by: Peter KURNEV
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 // File:        BOPAlgo_ShellSplitter.cxx
16 // Created:     Thu Jan 16 08:33:50 2014
17 //              <pkv@PETREX>
18
19 #include <BOPAlgo_ShellSplitter.ixx>
20 //
21 #include <TopoDS_Shape.hxx>
22 #include <TopoDS_Shell.hxx>
23 #include <TopoDS_Edge.hxx>
24
25 #include <BRep_Builder.hxx>
26 #include <TopExp_Explorer.hxx>
27 //
28 #include <BOPCol_TBB.hxx>
29 #include <BOPCol_IndexedMapOfShape.hxx>
30 #include <BOPCol_MapOfShape.hxx>
31 #include <BOPCol_MapOfOrientedShape.hxx>
32 #include <BOPCol_NCVector.hxx>
33 #include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
34 //
35 #include <BOPInt_Context.hxx>
36 //
37 #include <BOPTools.hxx>
38 #include <BOPTools_AlgoTools.hxx>
39 #include <BOPTools_CoupleOfShape.hxx>
40 //
41 typedef BOPCol_NCVector<BOPTools_ConnexityBlock> \
42   BOPAlgo_ShellSplitter_VectorOfConnexityBlock;
43 //
44 static
45   Standard_Boolean IsClosedShell(const TopoDS_Shell& );
46 static
47   void MakeShell(const BOPCol_ListOfShape& , 
48                  TopoDS_Shell& );
49
50 //=======================================================================
51 //function : 
52 //purpose  : 
53 //=======================================================================
54 BOPAlgo_ShellSplitter::BOPAlgo_ShellSplitter()
55 :
56   BOPAlgo_Algo(),
57   myStartShapes(myAllocator),
58   myShells(myAllocator),
59   myLCB(myAllocator)
60 {
61 }
62 //=======================================================================
63 //function : 
64 //purpose  : 
65 //=======================================================================
66 BOPAlgo_ShellSplitter::BOPAlgo_ShellSplitter
67   (const Handle(NCollection_BaseAllocator)& theAllocator)
68 :
69   BOPAlgo_Algo(theAllocator),
70   myStartShapes(theAllocator),
71   myShells(theAllocator),
72   myLCB(myAllocator)
73 {
74 }
75 //=======================================================================
76 //function : ~
77 //purpose  : 
78 //=======================================================================
79 BOPAlgo_ShellSplitter::~BOPAlgo_ShellSplitter()
80 {
81 }
82 //=======================================================================
83 //function : AddStartElement
84 //purpose  : 
85 //=======================================================================
86 void BOPAlgo_ShellSplitter::AddStartElement(const TopoDS_Shape& aE)
87 {
88   myStartShapes.Append(aE);
89 }
90 //=======================================================================
91 //function : StartElements
92 //purpose  : 
93 //=======================================================================
94 const BOPCol_ListOfShape& BOPAlgo_ShellSplitter::StartElements()const
95 {
96   return myStartShapes;
97 }
98 //=======================================================================
99 //function : Loops
100 //purpose  : 
101 //=======================================================================
102 const BOPCol_ListOfShape& BOPAlgo_ShellSplitter::Shells()const
103 {
104   return myShells;
105 }
106 //=======================================================================
107 //function : Perform
108 //purpose  : 
109 //=======================================================================
110 void BOPAlgo_ShellSplitter::Perform()
111 {
112   myErrorStatus=0;
113   //
114   MakeConnexityBlocks();
115   if (myErrorStatus) {
116     return;
117   }
118   //
119   MakeShells();
120 }
121 //=======================================================================
122 //function : MakeConnexityBlocks
123 //purpose  : 
124 //=======================================================================
125 void BOPAlgo_ShellSplitter::MakeConnexityBlocks()
126 {
127   Standard_Boolean bRegular;
128   Standard_Integer i, j, aNbE, aNbES, aNbEP, k, aNbCB;
129   TopoDS_Shape aFR;
130   TopExp_Explorer aExpF;
131   BOPCol_IndexedDataMapOfShapeListOfShape aMEF(100, myAllocator);
132   BOPCol_IndexedMapOfShape aMEP(100, myAllocator);
133   BOPCol_IndexedMapOfShape aMFC(100, myAllocator);
134   BOPCol_MapOfShape aMER(100, myAllocator);
135   BOPCol_MapOfShape aMFP(100, myAllocator);
136   BOPCol_IndexedMapOfShape aMEAdd(100, myAllocator);
137   BOPCol_MapOfShape aMES(100, myAllocator);
138   BOPCol_ListIteratorOfListOfShape aIt;
139   //
140   myErrorStatus=0;
141   //
142   myLCB.Clear();
143   //
144   const BOPCol_ListOfShape& aLSE=myStartShapes;
145   aIt.Initialize(aLSE);
146   for (i=1; aIt.More(); aIt.Next(), ++i) {
147     const TopoDS_Shape& aSE=aIt.Value();
148     if (!aMEP.Contains(aSE)) {
149       aMEP.Add(aSE);
150       BOPTools::MapShapesAndAncestors(aSE, 
151                                       TopAbs_EDGE, TopAbs_FACE, 
152                                       aMEF);
153     }
154     else {
155       aMER.Add(aSE);
156     }
157   }
158   //
159   // 2
160   aNbE=aMEF.Extent();
161   for (i=1; i<=aNbE; ++i) {
162     aNbES=aMES.Extent();
163     if (aNbES==aNbE) {
164       break;
165     }
166     //
167     const TopoDS_Shape& aE=aMEF.FindKey(i);
168     //
169     if (!aMES.Add(aE)) {
170       continue;
171     }
172     // aMES - globally processed edges
173     //
174     //------------------------------------- goal: aMEC
175     aMFC.Clear();    // aMEC - edges of CB
176     aMEP.Clear();    // aMVP - edges to process right now 
177     aMEAdd.Clear();  // aMVAdd edges to process on next step of for(;;) {
178     //
179     aMEP.Add(aE);
180     //
181     for(;;) {
182       aNbEP=aMEP.Extent();
183       for (k=1; k<=aNbEP; ++k) {
184         const TopoDS_Shape& aEP=aMEP(k);
185         const BOPCol_ListOfShape& aLF=aMEF.FindFromKey(aEP);
186         aIt.Initialize(aLF);
187         for (; aIt.More(); aIt.Next()) {
188           const TopoDS_Shape& aF=aIt.Value();
189           if (aMFC.Add(aF)) {
190             aExpF.Init(aF, TopAbs_EDGE);
191             for (; aExpF.More(); aExpF.Next()) {
192               const TopoDS_Shape& aEF=aExpF.Current();
193               if (aMES.Add(aEF)) {
194                 aMEAdd.Add(aEF);
195               }
196             }
197           }
198         }
199       }
200       //
201       aNbEP=aMEAdd.Extent();
202       if (!aNbEP) {
203         break; // from for(;;) {
204       }
205       //
206       aMEP.Clear();
207       //
208       for (k=1; k<=aNbEP; ++k) {
209         const TopoDS_Shape& aEF=aMEAdd(k);
210         aMEP.Add(aEF);
211       }
212       aMEAdd.Clear();
213     }// for(;;) {
214     //
215     //-------------------------------------
216     BOPTools_ConnexityBlock aCB(myAllocator);
217     //
218     BOPCol_ListOfShape& aLECB=aCB.ChangeShapes();
219     BOPCol_IndexedDataMapOfShapeListOfShape aMEFR(100, myAllocator);
220     //
221     bRegular=Standard_True;
222     aNbCB = aMFC.Extent();
223     for (j=1; j<=aNbCB; ++j) {
224       aFR = aMFC(j);
225       //
226       if (aMER.Contains(aFR)) {
227         aFR.Orientation(TopAbs_FORWARD);
228         aLECB.Append(aFR);
229         aFR.Orientation(TopAbs_REVERSED);
230         aLECB.Append(aFR);
231         bRegular=Standard_False;
232       }
233       else {
234         aLECB.Append(aFR);
235       }
236       //
237       if (bRegular) {
238         BOPTools::MapShapesAndAncestors(aFR,
239                                         TopAbs_EDGE, TopAbs_FACE, 
240                                         aMEFR);
241       }
242     }
243     //
244     if (bRegular) {
245       Standard_Integer aNbER, aNbFR; 
246       //
247       aNbER=aMEFR.Extent();
248       for (k=1; k<=aNbER; ++k) {
249         const BOPCol_ListOfShape& aLFR=aMEFR(k);
250         aNbFR=aLFR.Extent();
251         if (aNbFR>2) {
252           bRegular=!bRegular;
253           break;
254         }
255       }
256     }
257     //
258     aCB.SetRegular(bRegular);
259     myLCB.Append(aCB);
260   }
261 }
262 //=======================================================================
263 //function : SplitBlock
264 //purpose  : 
265 //=======================================================================
266 void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
267 {
268   Standard_Integer aNbLF, aNbOff, aNbFP;
269   Standard_Integer i;
270   TopAbs_Orientation anOr;
271   TopoDS_Edge aEL;
272   BRep_Builder aBB;
273   TopoDS_Iterator aItS;
274   TopExp_Explorer aExp;
275   BOPCol_ListIteratorOfListOfShape aItF;
276   BOPTools_CoupleOfShape aCSOff;
277   BOPCol_MapOfOrientedShape AddedFacesMap;
278   BOPCol_IndexedDataMapOfShapeListOfShape aEFMap, aMEFP;
279   // 
280   Handle (BOPInt_Context) aContext=new BOPInt_Context;
281   //
282   const BOPCol_ListOfShape& myShapes=aCB.Shapes();
283   //
284   BOPCol_ListOfShape& myLoops=aCB.ChangeLoops();
285   myLoops.Clear();
286   //
287   // 1. Shells Usual
288   aItF.Initialize (myShapes);
289   for (; aItF.More(); aItF.Next()) {
290     const TopoDS_Shape& aFF = aItF.Value();
291     BOPTools::MapShapesAndAncestors
292       (aFF, TopAbs_EDGE, TopAbs_FACE, aEFMap);
293   }
294   //
295   aItF.Initialize (myShapes);
296   for (i=1; aItF.More(); aItF.Next(), ++i) {
297     const TopoDS_Shape& aFF = aItF.Value();
298     if (!AddedFacesMap.Add(aFF)) {
299       continue;
300     }
301     //
302     // make a new shell
303     TopoDS_Shell aShell;
304     aBB.MakeShell(aShell);
305     aBB.Add(aShell, aFF);
306     //
307     aMEFP.Clear();
308     BOPTools::MapShapesAndAncestors(aFF, 
309                                     TopAbs_EDGE, TopAbs_FACE, 
310                                     aMEFP);
311     //
312     // loop on faces added to Shell; 
313     // add their neighbor faces to Shell and so on
314     aItS.Initialize (aShell);
315     for (; aItS.More(); aItS.Next()) {
316       const TopoDS_Face& aF = (*(TopoDS_Face*)(&aItS.Value()));
317       //
318       // loop on edges of aF; find a good neighbor face of aF by aE
319       aExp.Init(aF, TopAbs_EDGE);
320       for (; aExp.More(); aExp.Next()) {
321         const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current()));
322         //
323         //1
324         if (aMEFP.Contains(aE)) {
325           const BOPCol_ListOfShape& aLFP=aMEFP.FindFromKey(aE);
326           aNbFP=aLFP.Extent();
327           if (aNbFP>1) { 
328             continue;
329           }
330         }
331         //2
332         anOr=aE.Orientation();
333         if (anOr==TopAbs_INTERNAL) {
334           continue;
335         }
336         //3
337         if (BRep_Tool::Degenerated(aE)) {
338           continue;
339         }
340         //
341         // candidate faces list
342         const BOPCol_ListOfShape& aLF=aEFMap.FindFromKey(aE);
343         aNbLF=aLF.Extent();
344         if (!aNbLF) {
345           continue;
346         }
347         //
348         // try to select one of neighbors
349         // check if a face already added to Shell shares E
350         Standard_Boolean bFound;
351         BOPCol_ListIteratorOfListOfShape aItLF;
352         BOPTools_ListOfCoupleOfShape aLCSOff;
353         //
354         aItLF.Initialize(aLF);
355         for (; aItLF.More(); aItLF.Next()) { 
356           const TopoDS_Face& aFL=(*(TopoDS_Face*)(&aItLF.Value()));
357           if (aF.IsSame(aFL)) {
358             continue;
359           } 
360           if (AddedFacesMap.Contains(aFL)){
361             continue;
362           }
363           //
364           bFound=BOPTools_AlgoTools::GetEdgeOff(aE, aFL, aEL);
365           if (!bFound) {
366             continue;
367           }
368           //
369           aCSOff.SetShape1(aEL);
370           aCSOff.SetShape2(aFL);
371           aLCSOff.Append(aCSOff);
372         }//for (; aItLF.More(); aItLF.Next()) { 
373         //
374         aNbOff=aLCSOff.Extent();
375         if (!aNbOff){
376           continue;
377         }
378         //
379         TopoDS_Face aSelF;
380         if (aNbOff==1) {
381           aSelF=(*(TopoDS_Face*)(&aLCSOff.First().Shape2()));
382         }
383         else if (aNbOff>1){
384           BOPTools_AlgoTools::GetFaceOff(aE, aF, 
385                                          aLCSOff, aSelF, aContext);
386         }
387         //
388         if (!aSelF.IsNull() && AddedFacesMap.Add(aSelF)) { 
389           aBB.Add(aShell, aSelF);
390           BOPTools::MapShapesAndAncestors(aSelF, 
391                                           TopAbs_EDGE, TopAbs_FACE, 
392                                           aMEFP);
393         }
394       } // for (; aEdgeExp.More(); aEdgeExp.Next()) { 
395     } //for (; aItAddedF.More(); aItAddedF.Next()) {
396     //
397     if (IsClosedShell(aShell)) {
398       myLoops.Append(aShell);
399     }
400   } // for (; aItF.More(); aItF.Next()) {
401 }
402 //=======================================================================
403 //class    : ShellSplitterFunctor
404 //purpose  : Auxiliary class
405 //=======================================================================
406 class BOPAlgo_ShellSplitterFunctor {
407  protected:
408   TopoDS_Face myFace;
409   BOPAlgo_ShellSplitter_VectorOfConnexityBlock* myPVCB;
410   //
411  public:
412   BOPAlgo_ShellSplitterFunctor
413     (BOPAlgo_ShellSplitter_VectorOfConnexityBlock& aVCB) 
414       : myPVCB(&aVCB) {
415   }
416   //
417   void operator()( const flexible_range<Standard_Size>& aBR ) const{
418     Standard_Size i, iBeg, iEnd;
419     //
420     BOPAlgo_ShellSplitter_VectorOfConnexityBlock& aVCB=*myPVCB;
421     //
422     iBeg=aBR.begin();
423     iEnd=aBR.end();
424     for(i=iBeg; i!=iEnd; ++i) {
425       BOPTools_ConnexityBlock& aCB=aVCB((Standard_Integer)i);
426       //
427       BOPAlgo_ShellSplitter::SplitBlock(aCB);
428     }
429   }
430 };
431 //=======================================================================
432 //class    : BOPAlgo_ShellSplitterCnt
433 //purpose  : Auxiliary class
434 //=======================================================================
435 class BOPAlgo_ShellSplitterCnt {
436  public:
437   //-------------------------------
438   // Perform
439   Standard_EXPORT 
440     static void Perform
441       (const Standard_Boolean bRunParallel,
442        BOPAlgo_ShellSplitter_VectorOfConnexityBlock& aVCB) {
443     //
444     BOPAlgo_ShellSplitterFunctor aSSF(aVCB);
445     Standard_Size aNbVCB=aVCB.Extent();
446     //
447     if (bRunParallel) {
448       flexible_for(flexible_range<Standard_Size>(0,aNbVCB), aSSF);
449     }
450     else {
451       aSSF.operator()(flexible_range<Standard_Size>(0,aNbVCB));
452     }
453   }
454 };
455 //=======================================================================
456 //function : MMakeShells
457 //purpose  : 
458 //=======================================================================
459 void BOPAlgo_ShellSplitter::MakeShells()
460 {
461   Standard_Boolean bIsRegular;
462   Standard_Integer aNbVCB, k;
463   BOPTools_ListIteratorOfListOfConnexityBlock aItCB;
464   BOPCol_ListIteratorOfListOfShape aIt;
465   BOPAlgo_ShellSplitter_VectorOfConnexityBlock aVCB;
466   //
467   myErrorStatus=0;
468   myShells.Clear();
469   //
470   aItCB.Initialize(myLCB);
471   for (; aItCB.More(); aItCB.Next()) {
472     BOPTools_ConnexityBlock& aCB=aItCB.ChangeValue();
473     bIsRegular=aCB.IsRegular();
474     if (bIsRegular) {
475       TopoDS_Shell aShell;
476       //
477       const BOPCol_ListOfShape& aLF=aCB.Shapes();
478       MakeShell(aLF, aShell);
479       myShells.Append(aShell);
480     }
481     else {
482       aVCB.Append(aCB);
483     }
484   }
485   //
486   aNbVCB=aVCB.Extent();
487   //===================================================
488   BOPAlgo_ShellSplitterCnt::Perform(myRunParallel, aVCB);
489   //===================================================
490   for (k=0; k<aNbVCB; ++k) {
491     const BOPTools_ConnexityBlock& aCB=aVCB(k);
492     const BOPCol_ListOfShape& aLS=aCB.Loops();
493     aIt.Initialize(aLS);
494     for (; aIt.More(); aIt.Next()) {
495       const TopoDS_Shape& aShell=aIt.Value();
496       myShells.Append(aShell);
497     }
498   }
499 }
500 //=======================================================================
501 //function : IsClosedShell
502 //purpose  : 
503 //=======================================================================
504 Standard_Boolean IsClosedShell(const TopoDS_Shell& theShell)
505 {
506   Standard_Integer aNbE;
507   Standard_Boolean bRet;
508   TopoDS_Iterator aIt;
509   TopExp_Explorer aExp;
510   BOPCol_MapOfShape aM;
511   // 
512   bRet=Standard_False;
513   aIt.Initialize(theShell);
514   for(; aIt.More(); aIt.Next()) {
515     const TopoDS_Face& aF=(*(TopoDS_Face*)(&aIt.Value()));
516     aExp.Init(aF, TopAbs_EDGE);
517     for (; aExp.More(); aExp.Next()) {
518       const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current()));
519       if (BRep_Tool::Degenerated(aE)) {
520         continue;
521       }
522       //
523       if (aE.Orientation()==TopAbs_INTERNAL) {
524         continue;
525       }
526       if (!aM.Add(aE)) {
527         aM.Remove(aE);
528       }
529     }
530   }
531   //
532   aNbE=aM.Extent();
533   if (!aNbE) {
534     bRet=!bRet;
535   }
536   return bRet;
537 }
538 //=======================================================================
539 //function : MakeShell
540 //purpose  : 
541 //=======================================================================
542 void MakeShell(const BOPCol_ListOfShape& aLS, 
543                TopoDS_Shell& aShell)
544 {
545   BRep_Builder aBB;
546   BOPCol_ListIteratorOfListOfShape aIt;
547   //
548   aBB.MakeShell(aShell);
549   //
550   aIt.Initialize(aLS);
551   for (; aIt.More(); aIt.Next()) {
552     const TopoDS_Shape& aF=aIt.Value();
553     aBB.Add(aShell, aF);
554   }
555 }