0029186: Move AddTool(), SetTools(), Tools() and other common methods of BOP tools...
[occt.git] / src / BOPAlgo / BOPAlgo_BOP.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
16 #include <BOPAlgo_BOP.hxx>
17 #include <BOPAlgo_BuilderSolid.hxx>
18 #include <BOPAlgo_PaveFiller.hxx>
19 #include <BOPAlgo_Alerts.hxx>
20 #include <BOPCol_DataMapOfShapeShape.hxx>
21 #include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
22 #include <BOPCol_IndexedMapOfShape.hxx>
23 #include <BOPCol_ListOfShape.hxx>
24 #include <BOPCol_MapOfShape.hxx>
25 #include <BOPDS_DS.hxx>
26 #include <BOPTools.hxx>
27 #include <BOPTools_AlgoTools.hxx>
28 #include <BOPTools_AlgoTools3D.hxx>
29 #include <BOPTools_Set.hxx>
30 #include <BOPTools_SetMapHasher.hxx>
31 #include <BRep_Builder.hxx>
32 #include <BRep_Tool.hxx>
33 #include <NCollection_DataMap.hxx>
34 #include <TopAbs_ShapeEnum.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TopoDS_Compound.hxx>
37 #include <TopoDS_Edge.hxx>
38 #include <TopoDS_Iterator.hxx>
39 #include <TopoDS_Shape.hxx>
40
41 typedef NCollection_IndexedDataMap
42   <BOPTools_Set,
43   TopoDS_Shape,
44   BOPTools_SetMapHasher> BOPTools_IndexedDataMapOfSetShape;
45 //
46 static
47   TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim);
48 //
49 static
50   void CollectContainers(const TopoDS_Shape& theS,
51                          BOPCol_ListOfShape& theLSC);
52 //
53 static
54   void RemoveDuplicates(BOPCol_ListOfShape& theContainers);
55 //
56 static
57   void RemoveDuplicates(BOPCol_ListOfShape& theContainers,
58                         const TopAbs_ShapeEnum theType);
59 //
60 static
61   Standard_Integer NbCommonItemsInMap(const BOPCol_MapOfShape& theM1,
62                                       const BOPCol_MapOfShape& theM2);
63 //
64 static
65   void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
66                              BOPCol_IndexedDataMapOfShapeListOfShape& theMFS,
67                              BOPCol_IndexedMapOfShape& theMFI);
68
69 //=======================================================================
70 //function : 
71 //purpose  : 
72 //=======================================================================
73 BOPAlgo_BOP::BOPAlgo_BOP()
74 : BOPAlgo_ToolsProvider()
75 {
76   Clear();
77 }
78 //=======================================================================
79 //function : 
80 //purpose  : 
81 //=======================================================================
82 BOPAlgo_BOP::BOPAlgo_BOP(const Handle(NCollection_BaseAllocator)& theAllocator)
83 : BOPAlgo_ToolsProvider(theAllocator)
84 {
85   Clear();
86 }
87 //=======================================================================
88 //function : ~
89 //purpose  : 
90 //=======================================================================
91 BOPAlgo_BOP::~BOPAlgo_BOP()
92 {
93 }
94 //=======================================================================
95 //function : Clear
96 //purpose  : 
97 //=======================================================================
98 void BOPAlgo_BOP::Clear()
99 {
100   myOperation=BOPAlgo_UNKNOWN;
101   myDims[0]=-1;
102   myDims[1]=-1;
103
104   BOPAlgo_ToolsProvider::Clear();
105 }
106 //=======================================================================
107 //function : SetOperation
108 //purpose  : 
109 //=======================================================================
110 void BOPAlgo_BOP::SetOperation(const BOPAlgo_Operation theOperation)
111 {
112   myOperation=theOperation;
113 }
114 //=======================================================================
115 //function : Operation
116 //purpose  : 
117 //=======================================================================
118 BOPAlgo_Operation BOPAlgo_BOP::Operation()const
119 {
120   return myOperation;
121 }
122 //=======================================================================
123 //function : CheckData
124 //purpose  : 
125 //=======================================================================
126 void BOPAlgo_BOP::CheckData()
127 {
128   Standard_Integer i, j, iDim, aNbArgs, aNbTools;
129   Standard_Boolean bFuse;
130   BOPCol_ListIteratorOfListOfShape aItLS;
131   //
132   if (!(myOperation==BOPAlgo_COMMON ||
133         myOperation==BOPAlgo_FUSE || 
134         myOperation==BOPAlgo_CUT|| 
135         myOperation==BOPAlgo_CUT21)) {
136     // non-licit operation
137     AddError (new BOPAlgo_AlertBOPNotSet);
138     return;
139   }
140   //
141   aNbArgs=myArguments.Extent();
142   if (!aNbArgs) {
143     // invalid number of Arguments
144     AddError (new BOPAlgo_AlertTooFewArguments);
145     return;
146   }
147   //
148   aNbTools=myTools.Extent();
149   if (!aNbTools) { 
150     // invalid number of Tools
151     AddError (new BOPAlgo_AlertTooFewArguments);
152     return;
153   }
154   //
155   CheckFiller();
156   if (HasErrors()) {
157     return;
158   }
159   //
160   bFuse = (myOperation == BOPAlgo_FUSE);
161   //
162   // The rules for different types of operations are the following:
163   // 1. FUSE:   All arguments and tools should have the same dimension;
164   // 2. CUT:    The MAXIMAL dimension of the ARGUMENTS should be less
165   //            or equal to the MINIMAL dimension of the TOOLS;
166   // 3. CUT21:  The MINIMAL dimension of ARGUMENTS should be grater
167   //            or equal to the MAXIMAL dimension of the TOOLS;
168   // 4. COMMON: The arguments and tools could have any dimensions.
169   //
170   Standard_Integer iDimMin[2], iDimMax[2];
171   Standard_Boolean bHasValid[2] = {Standard_False, Standard_False};
172   //
173   for (i=0; i<2; ++i) {
174     const BOPCol_ListOfShape& aLS=(!i)? myArguments : myTools;
175     aItLS.Initialize(aLS);
176     for (j=0; aItLS.More(); aItLS.Next(), ++j) {
177       const TopoDS_Shape& aS=aItLS.Value();
178       Standard_Boolean bIsEmpty = BOPTools_AlgoTools3D::IsEmptyShape(aS);
179       if (bIsEmpty) {
180         AddWarning(new BOPAlgo_AlertEmptyShape (aS));
181         continue;
182       }
183       //
184       iDim = BOPTools_AlgoTools::Dimension(aS);
185       if (iDim < 0) {
186         // non-homogeneous argument
187         AddError (new BOPAlgo_AlertBOPNotAllowed);
188         return;
189       }
190       //
191       bHasValid[i] = Standard_True;
192       //
193       if (!j) {
194         iDimMin[i] = iDim;
195         iDimMax[i] = iDim;
196         continue;
197       }
198       //
199       if (iDim < iDimMin[i]) {
200         iDimMin[i] = iDim;
201       }
202       else if (iDim > iDimMax[i]) {
203         iDimMax[i] = iDim;
204       }
205       //
206       if (bFuse && (iDimMin[i] != iDimMax[i])) {
207         // non-homogeneous argument
208         AddError (new BOPAlgo_AlertBOPNotAllowed);
209         return;
210       }
211     }
212   }
213   //
214   if (bHasValid[0] && bHasValid[1]) {
215     if (((myOperation == BOPAlgo_FUSE)  && (iDimMax[0] != iDimMax[1])) ||
216         ((myOperation == BOPAlgo_CUT)   && (iDimMax[0] >  iDimMin[1])) ||
217         ((myOperation == BOPAlgo_CUT21) && (iDimMin[0] <  iDimMax[1])) )
218     {
219       // non-licit operation for the arguments
220       AddError (new BOPAlgo_AlertBOPNotAllowed);
221       return;
222     }
223     myDims[0] = iDimMin[0];
224     myDims[1] = iDimMin[1];
225   }
226 }
227 //=======================================================================
228 //function : TreatEmtpyShape
229 //purpose  : 
230 //=======================================================================
231 Standard_Boolean BOPAlgo_BOP::TreatEmptyShape()
232 {
233   if (! GetReport()->HasAlert (STANDARD_TYPE(BOPAlgo_AlertEmptyShape)))
234   {
235     return Standard_False;
236   }
237   //
238   // Find non-empty objects
239   BOPCol_ListOfShape aLValidObjs;
240   BOPCol_ListIteratorOfListOfShape aItLS(myArguments);
241   for (; aItLS.More(); aItLS.Next()) {
242     if (!BOPTools_AlgoTools3D::IsEmptyShape(aItLS.Value())) {
243       aLValidObjs.Append(aItLS.Value());
244     }
245   }
246   //
247   // Find non-empty tools
248   BOPCol_ListOfShape aLValidTools;
249   aItLS.Initialize(myTools);
250   for (; aItLS.More() ; aItLS.Next()) {
251     if (!BOPTools_AlgoTools3D::IsEmptyShape(aItLS.Value())) {
252       aLValidTools.Append(aItLS.Value());
253     }
254   }
255   //
256   Standard_Boolean bHasValidObj  = (aLValidObjs .Extent() > 0);
257   Standard_Boolean bHasValidTool = (aLValidTools.Extent() > 0);
258   //
259   if (bHasValidObj && bHasValidTool) {
260     // We need to continue the operation to obtain the result
261     return Standard_False;
262   }
263   //
264   if (!bHasValidObj && !bHasValidTool) {
265     // All shapes are empty shapes, the result will always be empty shape
266     return Standard_True;
267   }
268   //
269   // One of the groups of arguments consists of empty shapes only,
270   // so we can build the result of operation right away just by
271   // choosing the list of shapes to add to result, depending on
272   // the type of the operation
273   BOPCol_ListOfShape *pLResult = NULL;
274   //
275   switch (myOperation) {
276     case BOPAlgo_FUSE:
277       // Add not empty shapes into result
278       pLResult = bHasValidObj ? &aLValidObjs : &aLValidTools;
279       break;
280     case BOPAlgo_CUT:
281       // Add objects into result
282       pLResult = &aLValidObjs;
283       break;
284     case BOPAlgo_CUT21:
285       // Add tools into result
286       pLResult = &aLValidTools;
287       break;
288     case BOPAlgo_COMMON:
289       // Common will be empty
290       break;
291     default:
292       break;
293   }
294   //
295   if (pLResult) {
296     aItLS.Initialize(*pLResult);
297     for (; aItLS.More(); aItLS.Next()) {
298       BRep_Builder().Add(myShape, aItLS.Value());
299     }
300   }
301   return Standard_True;
302 }
303 //=======================================================================
304 //function : BuildResult
305 //purpose  : 
306 //=======================================================================
307 void BOPAlgo_BOP::BuildResult(const TopAbs_ShapeEnum theType)
308 {
309   TopAbs_ShapeEnum aType;
310   BRep_Builder aBB;
311   BOPCol_MapOfShape aM;
312   BOPCol_ListIteratorOfListOfShape aIt, aItIm;
313   //
314   const BOPCol_ListOfShape& aLA=myDS->Arguments();
315   aIt.Initialize(aLA);
316   for (; aIt.More(); aIt.Next()) {
317     const TopoDS_Shape& aS=aIt.Value();
318     aType=aS.ShapeType();
319     if (aType==theType) {
320       if (myImages.IsBound(aS)){
321         const BOPCol_ListOfShape& aLSIm=myImages.Find(aS);
322         aItIm.Initialize(aLSIm);
323         for (; aItIm.More(); aItIm.Next()) {
324           const TopoDS_Shape& aSIm=aItIm.Value();
325           if (aM.Add(aSIm)) {
326             aBB.Add(myShape, aSIm);
327           }
328         }
329       }
330       else {
331         if (aM.Add(aS)) {
332           aBB.Add(myShape, aS);
333         }
334       }
335     }
336   }
337 }
338 //=======================================================================
339 //function : Perform
340 //purpose  : 
341 //=======================================================================
342 void BOPAlgo_BOP::Perform()
343 {
344   Handle(NCollection_BaseAllocator) aAllocator;
345   BOPAlgo_PaveFiller* pPF;
346   BOPCol_ListIteratorOfListOfShape aItLS;
347   //
348   GetReport()->Clear();
349   //
350   if (myEntryPoint==1) {
351     if (myPaveFiller) {
352       delete myPaveFiller;
353       myPaveFiller=NULL;
354     }
355   }
356   //
357   aAllocator=
358     NCollection_BaseAllocator::CommonBaseAllocator();
359   BOPCol_ListOfShape aLS(aAllocator);
360   //
361   aItLS.Initialize(myArguments);
362   for (; aItLS.More(); aItLS.Next()) {
363     const TopoDS_Shape& aS=aItLS.Value();
364     aLS.Append(aS);
365   }
366   //
367   aItLS.Initialize(myTools);
368   for (; aItLS.More(); aItLS.Next()) {
369     const TopoDS_Shape& aS=aItLS.Value();
370     aLS.Append(aS);
371   }
372   //
373   pPF=new BOPAlgo_PaveFiller(aAllocator);
374   pPF->SetArguments(aLS);
375   pPF->SetRunParallel(myRunParallel);
376   pPF->SetProgressIndicator(myProgressIndicator);
377   pPF->SetFuzzyValue(myFuzzyValue);
378   pPF->SetNonDestructive(myNonDestructive);
379   pPF->SetGlue(myGlue);
380   //
381   pPF->Perform();
382   //
383   myEntryPoint=1;
384   PerformInternal(*pPF);
385 }
386 //=======================================================================
387 //function : PerformInternal1
388 //purpose  : 
389 //=======================================================================
390 void BOPAlgo_BOP::PerformInternal1(const BOPAlgo_PaveFiller& theFiller)
391 {
392   myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
393   myDS=myPaveFiller->PDS();
394   myContext=myPaveFiller->Context();
395   myFuzzyValue = myPaveFiller->FuzzyValue();
396   myNonDestructive = myPaveFiller->NonDestructive();
397   //
398   // 1. CheckData
399   CheckData();
400   if (HasErrors()) {
401     return;
402   }
403   //
404   // 2. Prepare
405   Prepare();
406   if (HasErrors()) {
407     return;
408   }
409   //
410   if (GetReport()->HasAlert (STANDARD_TYPE(BOPAlgo_AlertEmptyShape)))
411   {
412     Standard_Boolean bDone = TreatEmptyShape();
413     if (bDone) {
414       return;
415     }
416   }
417   //
418   // 3. Fill Images
419   // 3.1 Vertices
420   FillImagesVertices();
421   if (HasErrors()) {
422     return;
423   }
424   //
425   BuildResult(TopAbs_VERTEX);
426   if (HasErrors()) {
427     return;
428   }
429   // 3.2 Edges
430   FillImagesEdges();
431   if (HasErrors()) {
432     return;
433   }
434   //
435   BuildResult(TopAbs_EDGE);
436   if (HasErrors()) {
437     return;
438   }
439   //
440   // 3.3 Wires
441   FillImagesContainers(TopAbs_WIRE);
442   if (HasErrors()) {
443     return;
444   }
445   //
446   BuildResult(TopAbs_WIRE);
447   if (HasErrors()) {
448     return;
449   }
450   //
451   // 3.4 Faces
452   FillImagesFaces();
453   if (HasErrors()) {
454     return;
455   }
456   
457   BuildResult(TopAbs_FACE);
458   if (HasErrors()) {
459     return;
460   }
461   //
462   // 3.5 Shells
463   FillImagesContainers(TopAbs_SHELL);
464   if (HasErrors()) {
465     return;
466   }
467   //
468   BuildResult(TopAbs_SHELL);
469   if (HasErrors()) {
470     return;
471   }
472   //
473   // 3.6 Solids
474   FillImagesSolids();
475   if (HasErrors()) {
476     return;
477   }
478   //
479   BuildResult(TopAbs_SOLID);
480   if (HasErrors()) {
481     return;
482   }
483   //
484   // 3.7 CompSolids
485   FillImagesContainers(TopAbs_COMPSOLID);
486   if (HasErrors()) {
487     return;
488   }
489   //
490   BuildResult(TopAbs_COMPSOLID);
491   if (HasErrors()) {
492     return;
493   }
494   //
495   // 3.8 Compounds
496   FillImagesCompounds();
497   if (HasErrors()) {
498     return;
499   }
500   //
501   BuildResult(TopAbs_COMPOUND);
502   if (HasErrors()) {
503     return;
504   }
505   //
506   // 4.BuildShape;
507   BuildShape();
508   if (HasErrors()) {
509     return;
510   }
511   // 
512   // 5.History
513   PrepareHistory();
514   //
515   // 6 Post-treatment 
516   PostTreat();
517 }
518 //=======================================================================
519 //function : BuildRC
520 //purpose  : 
521 //=======================================================================
522 void BOPAlgo_BOP::BuildRC()
523 {
524   TopAbs_ShapeEnum aType;
525   TopoDS_Compound aC;
526   BRep_Builder aBB;
527   //
528   aBB.MakeCompound(aC);
529   //
530   // A. Fuse
531   if (myOperation == BOPAlgo_FUSE) {
532     BOPCol_MapOfShape aMFence;
533     aType = TypeToExplore(myDims[0]);
534     TopExp_Explorer aExp(myShape, aType);
535     for (; aExp.More(); aExp.Next()) {
536       const TopoDS_Shape& aS = aExp.Current();
537       if (aMFence.Add(aS)) {
538         aBB.Add(aC, aS);
539       }
540     }
541     myRC = aC;
542     return;
543   }
544   //
545   // B. Common, Cut, Cut21
546   //
547   Standard_Integer i, j, aNb, iDim;
548   Standard_Boolean bCheckEdges, bContains, bCut21, bCommon;
549   BOPCol_ListIteratorOfListOfShape aItLS;
550   //
551   // prepare the building elements of arguments to get its splits
552   BOPCol_IndexedMapOfShape aMArgs, aMTools;
553   for (i = 0; i < 2; ++i) {
554     const BOPCol_ListOfShape& aLS = !i ? myArguments : myTools;
555     BOPCol_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
556     aItLS.Initialize(aLS);
557     for (; aItLS.More(); aItLS.Next()) {
558       const TopoDS_Shape& aS = aItLS.Value();
559       iDim = BOPTools_AlgoTools::Dimension(aS);
560       if (iDim < 0) {
561         continue;
562       }
563       aType = TypeToExplore(iDim);
564       BOPTools::MapShapes(aS, aType, aMS);
565     }
566   }
567   //
568   bCheckEdges = Standard_False;
569   //
570   // get splits of building elements
571   BOPCol_IndexedMapOfShape aMArgsIm, aMToolsIm;
572   BOPTools_IndexedDataMapOfSetShape aMSetArgs, aMSetTools;
573
574   for (i = 0; i < 2; ++i) {
575     const BOPCol_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
576     BOPCol_IndexedMapOfShape& aMSIm = !i ? aMArgsIm : aMToolsIm;
577     BOPTools_IndexedDataMapOfSetShape& aMSet = !i ? aMSetArgs : aMSetTools;
578     //
579     aNb = aMS.Extent();
580     for (j = 1; j <= aNb; ++j) {
581       const TopoDS_Shape& aS = aMS(j);
582       aType = aS.ShapeType();
583       if (aType == TopAbs_EDGE) {
584         const TopoDS_Edge& aE = *(TopoDS_Edge*)&aS;
585         bCheckEdges = Standard_True;
586         if (BRep_Tool::Degenerated(aE)) {
587           continue;
588         }
589       }
590       //
591       if (myImages.IsBound(aS)) {
592         const BOPCol_ListOfShape& aLSIm = myImages.Find(aS);
593         aItLS.Initialize(aLSIm);
594         for (; aItLS.More(); aItLS.Next()) {
595           const TopoDS_Shape& aSIm = aItLS.Value();
596           aMSIm.Add(aSIm);
597         }
598       }
599       else {
600         aMSIm.Add(aS);
601         if (aS.ShapeType() == TopAbs_SOLID) {
602           BOPTools_Set aST;
603           aST.Add(aS, TopAbs_FACE);
604           if (!aMSet.Contains(aST)) {
605             aMSet.Add(aST, aS);
606           }
607         }
608       }
609     }
610   }
611   //
612   // compare the maps and make the result
613   //
614   Standard_Integer iDimMin, iDimMax;
615   //
616   iDimMin = Min(myDims[0], myDims[1]);
617   bCommon = (myOperation == BOPAlgo_COMMON);
618   bCut21  = (myOperation == BOPAlgo_CUT21);
619   //
620   const BOPCol_IndexedMapOfShape& aMIt = bCut21 ? aMToolsIm : aMArgsIm;
621   const BOPCol_IndexedMapOfShape& aMCheck = bCut21 ? aMArgsIm : aMToolsIm;
622   const BOPTools_IndexedDataMapOfSetShape& aMSetCheck = bCut21 ? aMSetArgs : aMSetTools;
623   //
624   BOPCol_IndexedMapOfShape aMCheckExp, aMItExp;
625   //
626   if (bCommon) {
627     aNb = aMIt.Extent();
628     for (i = 1; i <= aNb; ++i) {
629       const TopoDS_Shape& aS = aMIt(i);
630       iDimMax = BOPTools_AlgoTools::Dimension(aS);
631       for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
632         aType = TypeToExplore(iDim);
633         BOPTools::MapShapes(aS, aType, aMItExp);
634       }
635       aMItExp.Add(aS);
636     }
637   }
638   else {
639     aMItExp = aMIt;
640   }
641   //
642   aNb = aMCheck.Extent();
643   for (i = 1; i <= aNb; ++i) {
644     const TopoDS_Shape& aS = aMCheck(i);
645     iDimMax = BOPTools_AlgoTools::Dimension(aS);
646     for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
647       aType = TypeToExplore(iDim);
648       BOPTools::MapShapes(aS, aType, aMCheckExp);
649     }
650     aMCheckExp.Add(aS);
651   }
652   //
653   aNb = aMItExp.Extent();
654   for (i = 1; i <= aNb; ++i) {
655     const TopoDS_Shape& aS = aMItExp(i);
656     //
657     bContains = aMCheckExp.Contains(aS);
658     if (!bContains && aS.ShapeType() == TopAbs_SOLID) {
659       BOPTools_Set aST;
660       aST.Add(aS, TopAbs_FACE);
661       bContains = aMSetCheck.Contains(aST);
662     }
663     //
664     if (bCommon) {
665       if (bContains) {
666         aBB.Add(aC, aS);
667       }
668     }
669     else {
670       if (!bContains) {
671         aBB.Add(aC, aS);
672       }
673     }
674   }
675   //
676   // filter result for COMMON operation
677   if (bCommon) {
678     BOPCol_MapOfShape aMFence;
679     TopExp_Explorer aExp;
680     TopoDS_Compound aCx;
681     aBB.MakeCompound(aCx);
682     //
683     for (iDim = 3; iDim >= iDimMin; --iDim) {
684       aType = TypeToExplore(iDim);
685       aExp.Init(aC, aType);
686       for (; aExp.More(); aExp.Next()) {
687         const TopoDS_Shape& aS = aExp.Current();
688         if (aMFence.Add(aS)) {
689           aBB.Add(aCx, aS);
690           BOPTools::MapShapes(aS, aMFence);
691         }
692       }
693     }
694     aC = aCx;
695   }
696   //
697   if (!bCheckEdges) {
698     myRC = aC;
699     return;
700   }
701   //
702   // The squats around degenerated edges
703   Standard_Integer nVD;
704   BOPCol_IndexedMapOfShape aMVC;
705   //
706   // 1. Vertices of aC
707   BOPTools::MapShapes(aC, TopAbs_VERTEX, aMVC);
708   //
709   // 2. DE candidates
710   aNb = myDS->NbSourceShapes();
711   for (i = 0; i < aNb; ++i) {
712     const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
713     aType = aSI.ShapeType();
714     if (aType != TopAbs_EDGE) {
715       continue;
716     }
717     //
718     const TopoDS_Edge& aE = *((TopoDS_Edge*)&aSI.Shape());
719     if (!BRep_Tool::Degenerated(aE)) {
720       continue;
721     }
722     //
723     nVD = aSI.SubShapes().First();
724     const TopoDS_Shape& aVD = myDS->Shape(nVD);
725     //
726     if (!aMVC.Contains(aVD)) {
727       continue;
728     }
729     //
730     if (myDS->IsNewShape(nVD)) {
731       continue;
732     }
733     //
734     if (myDS->HasInterf(nVD)) {
735       continue;
736     }
737     //
738     aBB.Add(aC, aE);
739   }
740   //
741   myRC=aC;
742 }
743 //=======================================================================
744 //function : BuildShape
745 //purpose  : 
746 //=======================================================================
747 void BOPAlgo_BOP::BuildShape()
748 {
749   BuildRC();
750   //
751   if ((myOperation == BOPAlgo_FUSE) && (myDims[0] == 3)) {
752     BuildSolid();
753     return;
754   }
755   //
756   Standard_Integer i;
757   TopAbs_ShapeEnum aType, aT1, aT2;
758   BOPCol_ListOfShape aLSC, aLCB;
759   BOPCol_ListIteratorOfListOfShape aItLS, aItLSIm, aItLCB;
760   TopoDS_Iterator aIt;
761   BRep_Builder aBB;
762   TopoDS_Shape aRC, aRCB;
763   //
764   BOPCol_MapOfShape aMSRC;
765   BOPTools::MapShapes(myRC, aMSRC);
766   //
767   // collect images of containers
768   for (i = 0; i < 2; ++i) {
769     const BOPCol_ListOfShape& aLS = !i ? myArguments : myTools;
770     //
771     aItLS.Initialize(aLS);
772     for (; aItLS.More(); aItLS.Next()) {
773       const TopoDS_Shape& aS = aItLS.Value();
774       //
775       CollectContainers(aS, aLSC);
776     }
777   }
778   // make containers
779   BOPCol_ListOfShape aLCRes;
780   aItLS.Initialize(aLSC);
781   for (; aItLS.More(); aItLS.Next()) {
782     const TopoDS_Shape& aSC = aItLS.Value();
783     //
784     BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
785     //
786     aIt.Initialize(aSC);
787     for (; aIt.More(); aIt.Next()) {
788       const TopoDS_Shape& aS = aIt.Value();
789       if (myImages.IsBound(aS)) {
790         const BOPCol_ListOfShape& aLSIm = myImages.Find(aS);
791         //
792         aItLSIm.Initialize(aLSIm);
793         for (; aItLSIm.More(); aItLSIm.Next()) {
794           const TopoDS_Shape& aSIm = aItLSIm.Value();
795           if (aMSRC.Contains(aSIm)) {
796             aBB.Add(aRC, aSIm);
797           }
798         }
799       }
800       else if (aMSRC.Contains(aS)) {
801         aBB.Add(aRC, aS);
802       }
803     }
804     //
805     aType = aSC.ShapeType();
806     switch (aType) {
807       case TopAbs_WIRE: {
808         aT1 = TopAbs_VERTEX;
809         aT2 = TopAbs_EDGE;
810         break;
811       }
812       case TopAbs_SHELL: {
813         aT1 = TopAbs_EDGE;
814         aT2 = TopAbs_FACE;
815         break;
816       }
817       default: {
818         aT1 = TopAbs_FACE;
819         aT2 = TopAbs_SOLID;
820       }
821     }
822     //
823     aLCB.Clear();
824     BOPTools_AlgoTools::MakeConnexityBlocks(aRC, aT1, aT2, aLCB);
825     if (aLCB.IsEmpty()) {
826       continue;
827     }
828     //
829     aItLCB.Initialize(aLCB);
830     for (; aItLCB.More(); aItLCB.Next()) {
831       BOPTools_AlgoTools::MakeContainer(aType, aRCB);
832       //
833       const TopoDS_Shape& aCB = aItLCB.Value();
834       aIt.Initialize(aCB);
835       for (; aIt.More(); aIt.Next()) {
836         const TopoDS_Shape& aCBS = aIt.Value();
837         aBB.Add(aRCB, aCBS);
838       }
839       //
840       if (aType == TopAbs_WIRE) {
841         // reorient wire
842         BOPTools_AlgoTools::OrientEdgesOnWire(aRCB);
843       }
844       else if (aType == TopAbs_SHELL) {
845         BOPTools_AlgoTools::OrientFacesOnShell(aRCB);
846       }
847       //
848       aRCB.Orientation(aSC.Orientation());
849       //
850       aLCRes.Append(aRCB);
851     }
852   }
853   //
854   RemoveDuplicates(aLCRes);
855   //
856   // add containers to result
857   TopoDS_Compound aResult;
858   aBB.MakeCompound(aResult);
859   //
860   aItLS.Initialize(aLCRes);
861   for (; aItLS.More(); aItLS.Next()) {
862     aBB.Add(aResult, aItLS.Value());
863   }
864   //
865   // add the rest of the shapes into result
866   BOPCol_MapOfShape aMSResult;
867   BOPTools::MapShapes(aResult, aMSResult);
868   //
869   aIt.Initialize(myRC);
870   for (; aIt.More(); aIt.Next()) {
871     const TopoDS_Shape& aS = aIt.Value();
872     if (aMSResult.Add(aS)) {
873       aBB.Add(aResult, aS);
874     }
875   }
876   //
877   myShape = aResult;
878 }
879 //=======================================================================
880 //function : BuildSolid
881 //purpose  : 
882 //=======================================================================
883 void BOPAlgo_BOP::BuildSolid()
884 {
885   // Containers
886   BOPCol_ListOfShape aLSC;
887   //
888   BOPCol_ListIteratorOfListOfShape aItLS;
889   TopExp_Explorer aExp;
890   BRep_Builder aBB;
891   //
892   // Get solids from input arguments
893   BOPCol_MapOfShape aMSA;
894   // Map the arguments to find shared faces
895   BOPCol_IndexedDataMapOfShapeListOfShape aMFS;
896   for (Standard_Integer i = 0; i < 2; ++i) {
897     const BOPCol_ListOfShape& aLSA = (i) ? myArguments : myTools;
898     aItLS.Initialize(aLSA);
899     for (; aItLS.More(); aItLS.Next()) {
900       const TopoDS_Shape& aSA = aItLS.Value();
901       aExp.Init(aSA, TopAbs_SOLID);
902       for (; aExp.More(); aExp.Next()) {
903         const TopoDS_Shape& aSol = aExp.Current();
904         aMSA.Add(aSol);
905         BOPTools::MapShapesAndAncestors(aSol, TopAbs_FACE, TopAbs_SOLID, aMFS);
906       }
907       //
908       // get Compsolids from input arguments
909       CollectContainers(aSA, aLSC);
910     }
911   }
912   //
913   // Find solids in input arguments sharing faces with other solids
914   BOPCol_MapOfShape aMTSols;
915   Standard_Integer i, aNb = aMFS.Extent();
916   for (i = 1; i < aNb; ++i) {
917     const BOPCol_ListOfShape& aLSols = aMFS(i);
918     if (aLSols.Extent() > 1) {
919       aItLS.Initialize(aLSols);
920       for(; aItLS.More(); aItLS.Next()) {
921         aMTSols.Add(aItLS.Value());
922       }
923     }
924   }
925   //
926   // Possibly untouched solids - to be added to results as is
927   BOPCol_IndexedMapOfShape aMUSols;
928   // Use map to chose the most outer faces to build result solids
929   aMFS.Clear();
930   // Internal faces
931   BOPCol_IndexedMapOfShape aMFI;
932   //
933   TopoDS_Iterator aIt(myRC);
934   for (; aIt.More(); aIt.Next()) {
935     const TopoDS_Shape& aSx = aIt.Value();
936     if (aMSA.Contains(aSx)) {
937       if (!aMTSols.Contains(aSx)) {
938         aMUSols.Add(aSx);
939         continue;
940       }
941     }
942     //
943     MapFacesToBuildSolids(aSx, aMFS, aMFI);
944   } // for (; aIt.More(); aIt.Next()) {
945   //
946   // Process possibly untouched solids.
947   // Really untouched solids will be added into result as is.
948   // Others will be processed by BuilderSolid.
949   BOPTools_IndexedDataMapOfSetShape aDMSTS;
950   //
951   aNb = aMUSols.Extent();
952   for (i = 1; i <= aNb; ++i) {
953     const TopoDS_Shape& aSx = aMUSols(i);
954     //
955     aExp.Init(aSx, TopAbs_FACE);
956     for (; aExp.More(); aExp.Next()) {
957       if (aMFS.Contains(aExp.Current())) {
958         break;
959       }
960     }
961     //
962     if (aExp.More()) {
963       MapFacesToBuildSolids(aSx, aMFS, aMFI);
964     }
965     else {
966       BOPTools_Set aST;
967       aST.Add(aSx, TopAbs_FACE);
968       if (!aDMSTS.Contains(aST)) {
969         aDMSTS.Add(aST, aSx);
970       }
971     }
972   }
973   //
974   BOPCol_IndexedDataMapOfShapeListOfShape aMEF;
975   // Split faces will be added in the end
976   // to avoid errors in BuilderSolid algorithm
977   BOPCol_ListOfShape aLF, aLFx;
978   aNb = aMFS.Extent();
979   for (i = 1; i <= aNb; ++i) {
980     const BOPCol_ListOfShape& aLSx = aMFS(i);
981     if (aLSx.Extent() == 1) {
982       const TopoDS_Shape& aFx = aMFS.FindKey(i);
983       BOPTools::MapShapesAndAncestors(aFx, TopAbs_EDGE, TopAbs_FACE, aMEF);
984       if (IsBoundSplits(aFx, aMEF)){
985         aLFx.Append(aFx);
986         continue;
987       }
988       aLF.Append(aFx);
989     }
990   }
991   //
992   // Faces to build result solids
993   BOPCol_ListOfShape aSFS;
994   aItLS.Initialize(aLF);
995   for(; aItLS.More(); aItLS.Next()) {
996     const TopoDS_Shape& aFx = aItLS.Value();
997     aSFS.Append(aFx);
998   }
999   //
1000   // Split faces
1001   aItLS.Initialize(aLFx);
1002   for (; aItLS.More(); aItLS.Next()) {
1003     const TopoDS_Shape& aFx = aItLS.Value();
1004     aSFS.Append(aFx);
1005   }
1006   //
1007   // Internal faces
1008   aNb = aMFI.Extent();
1009   for (i = 1; i <= aNb; ++i) {
1010     TopoDS_Shape aFx = aMFI.FindKey(i);
1011     aSFS.Append(aFx.Oriented(TopAbs_FORWARD));
1012     aSFS.Append(aFx.Oriented(TopAbs_REVERSED));
1013   }
1014   //
1015   TopoDS_Shape aRC;
1016   BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
1017   if (aSFS.Extent()) {
1018     // Build solids from set of faces
1019     BOPAlgo_BuilderSolid aSB;
1020     aSB.SetContext(myContext);
1021     aSB.SetShapes(aSFS);
1022     aSB.Perform();
1023     if (aSB.HasErrors()) {
1024       AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
1025       return;
1026     }
1027     // new solids
1028     const BOPCol_ListOfShape& aLSR = aSB.Areas();
1029     //
1030     // add new solids to result
1031     aItLS.Initialize(aLSR);
1032     for (; aItLS.More(); aItLS.Next()) {
1033       const TopoDS_Shape& aSR = aItLS.Value();
1034       aBB.Add(aRC, aSR);
1035     }
1036   }
1037   //
1038   // add untouched solids to result
1039   aNb = aDMSTS.Extent();
1040   for (i = 1; i <= aNb; ++i) {
1041     const TopoDS_Shape& aSx = aDMSTS(i);
1042     aBB.Add(aRC, aSx);
1043   }
1044   //
1045   if (aLSC.IsEmpty()) {
1046     // no Compsolids in arguments
1047     myShape = aRC;
1048     return;
1049   }
1050   //
1051   // build new Compsolids from new solids containing splits
1052   // of faces from arguments of type Compsolid
1053   //
1054   TopoDS_Shape aResult;
1055   BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aResult);
1056   //
1057   aIt.Initialize(aRC);
1058   if (!aIt.More()) {
1059     // no solids in the result
1060     myShape = aRC;
1061     return;
1062   }
1063   //
1064   const TopoDS_Shape& aSol1 = aIt.Value();
1065   aIt.Next();
1066   //
1067   // optimization for one solid in the result
1068   if (!aIt.More()) {
1069     TopoDS_Shape aCS;
1070     BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
1071     aBB.Add(aCS, aSol1);
1072     //
1073     aBB.Add(aResult, aCS);
1074     myShape = aResult;
1075     return;
1076   }
1077   //
1078   // get splits of faces of the Compsolid arguments
1079   BOPCol_MapOfShape aMFCs;
1080   aItLS.Initialize(aLSC);
1081   for (; aItLS.More(); aItLS.Next()) {
1082     const TopoDS_Shape& aCs = aItLS.Value();
1083     aExp.Init(aCs, TopAbs_FACE);
1084     for (; aExp.More(); aExp.Next()) {
1085       const TopoDS_Shape& aF = aExp.Current();
1086       const BOPCol_ListOfShape* pLFIm = myImages.Seek(aF);
1087       if (!pLFIm) {
1088         aMFCs.Add(aF);
1089       }
1090       else {
1091         BOPCol_ListIteratorOfListOfShape aItLFIm(*pLFIm);
1092         for (; aItLFIm.More(); aItLFIm.Next()) {
1093           aMFCs.Add(aItLFIm.Value());
1094         }
1095       }
1096     }
1097   }
1098   //
1099   // build connexity blocks from new solids
1100   BOPCol_ListOfShape aLCBS;
1101   BOPTools_AlgoTools::MakeConnexityBlocks(aRC, TopAbs_FACE, TopAbs_SOLID, aLCBS);
1102   //
1103   aItLS.Initialize(aLCBS);
1104   for (; aItLS.More(); aItLS.Next()) {
1105     const TopoDS_Shape& aCB = aItLS.Value();
1106     //
1107     // check if the Compsolid should be created
1108     aExp.Init(aCB, TopAbs_FACE);
1109     for (; aExp.More(); aExp.Next()) {
1110       if (aMFCs.Contains(aExp.Current())) {
1111         break;
1112       }
1113     }
1114     //
1115     if (!aExp.More()) {
1116       // add solids directly into result as their origins are not Compsolids
1117       for (aIt.Initialize(aCB); aIt.More(); aIt.Next()) {
1118         aBB.Add(aResult, aIt.Value());
1119       }
1120       continue;
1121     }
1122     //
1123     // make Compsolid
1124     TopoDS_Shape aCS;
1125     BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
1126     //
1127     aIt.Initialize(aCB);
1128     for (; aIt.More(); aIt.Next()) {
1129       aBB.Add(aCS, aIt.Value());
1130     }
1131     //
1132     aBB.Add(aResult, aCS);
1133   }
1134   //
1135   myShape = aResult;
1136 }
1137 //=======================================================================
1138 //function : IsBoundSplits
1139 //purpose  : 
1140 //=======================================================================
1141 Standard_Boolean BOPAlgo_BOP::IsBoundSplits
1142   (const TopoDS_Shape& aS,
1143    BOPCol_IndexedDataMapOfShapeListOfShape& aMEF)
1144 {
1145   Standard_Boolean bRet = Standard_False;
1146   if (mySplits.IsBound(aS) || myOrigins.IsBound(aS)) {
1147     return !bRet;
1148   }
1149
1150   BOPCol_ListIteratorOfListOfShape aIt;
1151   Standard_Integer aNbLS;
1152   TopAbs_Orientation anOr;
1153   //
1154   //check face aF may be connected to face from mySplits
1155   TopExp_Explorer aExp(aS, TopAbs_EDGE);
1156   for (; aExp.More(); aExp.Next()) {
1157     const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current()));
1158     //
1159     anOr = aE.Orientation();
1160     if (anOr==TopAbs_INTERNAL) {
1161       continue;
1162     }
1163     //
1164     if (BRep_Tool::Degenerated(aE)) {
1165       continue;
1166     }
1167     //
1168     const BOPCol_ListOfShape& aLS=aMEF.FindFromKey(aE);
1169     aNbLS = aLS.Extent();
1170     if (!aNbLS) {
1171       continue;
1172     }
1173     //
1174     aIt.Initialize(aLS);
1175     for (; aIt.More(); aIt.Next()) {
1176       const TopoDS_Shape& aSx = aIt.Value();
1177       if (mySplits.IsBound(aSx) || myOrigins.IsBound(aS)) {
1178         return !bRet;
1179       }
1180     }
1181   }
1182   //
1183   return bRet;
1184 }
1185 //=======================================================================
1186 //function : TypeToExplore
1187 //purpose  : 
1188 //=======================================================================
1189 TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim)
1190 {
1191   TopAbs_ShapeEnum aRet;
1192   //
1193   switch(theDim) {
1194   case 0:
1195     aRet=TopAbs_VERTEX;
1196     break;
1197   case 1:
1198     aRet=TopAbs_EDGE;
1199     break;
1200   case 2:
1201     aRet=TopAbs_FACE;
1202     break;
1203   case 3:
1204     aRet=TopAbs_SOLID;
1205     break;
1206   default:
1207     aRet=TopAbs_SHAPE;
1208     break;
1209   }
1210   return aRet;
1211 }
1212 //=======================================================================
1213 //function : CollectContainers
1214 //purpose  : 
1215 //=======================================================================
1216 void CollectContainers(const TopoDS_Shape& theS,
1217                        BOPCol_ListOfShape& theLSC)
1218 {
1219   TopAbs_ShapeEnum aType = theS.ShapeType();
1220   if (aType == TopAbs_WIRE ||
1221       aType == TopAbs_SHELL ||
1222       aType == TopAbs_COMPSOLID) {
1223     theLSC.Append(theS);
1224     return;
1225   }
1226   //
1227   if (aType != TopAbs_COMPOUND) {
1228     return;
1229   }
1230   //
1231   TopoDS_Iterator aIt(theS);
1232   for (; aIt.More(); aIt.Next()) {
1233     const TopoDS_Shape& aS = aIt.Value();
1234     CollectContainers(aS, theLSC);
1235   }
1236 }
1237
1238 //=======================================================================
1239 //function : RemoveDuplicates
1240 //purpose  : Filters the containers with identical contents
1241 //=======================================================================
1242 void RemoveDuplicates(BOPCol_ListOfShape& theContainers)
1243 {
1244   RemoveDuplicates(theContainers, TopAbs_WIRE);
1245   RemoveDuplicates(theContainers, TopAbs_SHELL);
1246   RemoveDuplicates(theContainers, TopAbs_COMPSOLID);
1247 }
1248
1249 //=======================================================================
1250 //function : RemoveDuplicates
1251 //purpose  : Filters the containers of given type with identical contents
1252 //=======================================================================
1253 void RemoveDuplicates(BOPCol_ListOfShape& theContainers,
1254                       const TopAbs_ShapeEnum theType)
1255 {
1256   // get containers of given type
1257   BOPCol_ListOfShape aLC;
1258   BOPCol_ListIteratorOfListOfShape aItLC(theContainers);
1259   for (; aItLC.More(); aItLC.Next()) {
1260     const TopoDS_Shape& aC = aItLC.Value();
1261     if (aC.ShapeType() == theType) {
1262       aLC.Append(aC);
1263     }
1264   }
1265   //
1266   if (aLC.IsEmpty()) {
1267     return;
1268   }
1269   //
1270   // map containers to compare its contents
1271   NCollection_IndexedDataMap<TopoDS_Shape, BOPCol_MapOfShape> aContents;
1272   //
1273   aItLC.Initialize(aLC);
1274   for (; aItLC.More(); aItLC.Next()) {
1275     const TopoDS_Shape& aC = aItLC.Value();
1276     //
1277     BOPCol_MapOfShape& aMC = aContents(aContents.Add(aC, BOPCol_MapOfShape()));
1278     //
1279     TopoDS_Iterator aIt(aC);
1280     for (; aIt.More(); aIt.Next()) {
1281       aMC.Add(aIt.Value());
1282     }
1283   }
1284   //
1285   // compare the contents of the containers and find duplicates
1286   BOPCol_MapOfShape aDuplicates;
1287   //
1288   Standard_Integer i, j, aNb = aContents.Extent();
1289   for (i = 1; i <= aNb; ++i) {
1290     const TopoDS_Shape& aCi = aContents.FindKey(i);
1291     if (aDuplicates.Contains(aCi)) {
1292       continue;
1293     }
1294     const BOPCol_MapOfShape& aMi = aContents(i);
1295     Standard_Integer aNbi = aMi.Extent();
1296     //
1297     for (j = i + 1; j <= aNb; ++j) {
1298       const TopoDS_Shape& aCj = aContents.FindKey(j);
1299       if (aDuplicates.Contains(aCj)) {
1300         continue;
1301       }
1302       const BOPCol_MapOfShape& aMj = aContents(j);
1303       Standard_Integer aNbj = aMj.Extent();
1304       //
1305       Standard_Integer aNbCommon = NbCommonItemsInMap(aMi, aMj);
1306       //
1307       if (aNbj == aNbCommon) {
1308         aDuplicates.Add(aCj);
1309         continue;
1310       }
1311       //
1312       if (aNbi == aNbCommon) {
1313         aDuplicates.Add(aCi);
1314         break;
1315       }
1316     }
1317   }
1318   //
1319   if (aDuplicates.IsEmpty()) {
1320     return;
1321   }
1322   //
1323   // remove duplicating containers
1324   aItLC.Initialize(theContainers);
1325   for (; aItLC.More(); ) {
1326     const TopoDS_Shape& aC = aItLC.Value();
1327     if (aDuplicates.Contains(aC)) {
1328       theContainers.Remove(aItLC);
1329       continue;
1330     }
1331     aItLC.Next();
1332   }
1333 }
1334
1335 //=======================================================================
1336 //function : NbCommonItemsInMap
1337 //purpose  : Counts the items contained in both maps
1338 //=======================================================================
1339 Standard_Integer NbCommonItemsInMap(const BOPCol_MapOfShape& theM1,
1340                                     const BOPCol_MapOfShape& theM2)
1341 {
1342   const BOPCol_MapOfShape* aMap1 = &theM1;
1343   const BOPCol_MapOfShape* aMap2 = &theM2;
1344   //
1345   if (theM2.Extent() < theM1.Extent()) {
1346     aMap1 = &theM2;
1347     aMap2 = &theM1;
1348   }
1349   //
1350   Standard_Integer iCommon = 0;
1351   for (BOPCol_MapIteratorOfMapOfShape aIt(*aMap1); aIt.More(); aIt.Next()) {
1352     if (aMap2->Contains(aIt.Value())) {
1353       ++iCommon;
1354     }
1355   }
1356   return iCommon;
1357 }
1358 //=======================================================================
1359 //function : MapFacesToBuildSolids
1360 //purpose  : Stores the faces of the given solid into outgoing maps:
1361 //           <theMFS> - not internal faces with reference to solid;
1362 //           <theMFI> - internal faces.
1363 //=======================================================================
1364 void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
1365                            BOPCol_IndexedDataMapOfShapeListOfShape& theMFS,
1366                            BOPCol_IndexedMapOfShape& theMFI)
1367 {
1368   TopExp_Explorer aExp(theSol, TopAbs_FACE);
1369   for (; aExp.More(); aExp.Next()) {
1370     const TopoDS_Shape& aF = aExp.Current();
1371     //
1372     if (aF.Orientation() == TopAbs_INTERNAL) {
1373       theMFI.Add(aF);
1374       continue;
1375     }
1376     //
1377     BOPCol_ListOfShape* pLSol = theMFS.ChangeSeek(aF);
1378     if (!pLSol) {
1379       pLSol = &theMFS(theMFS.Add(aF, BOPCol_ListOfShape()));
1380       pLSol->Append(theSol);
1381     }
1382     else {
1383       const TopoDS_Shape& aF1 = theMFS.FindKey(theMFS.FindIndex(aF));
1384       if (aF1.Orientation() != aF.Orientation()) {
1385         pLSol->Append(theSol);
1386       }
1387     }
1388   }
1389 }