0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / BOPAlgo / BOPAlgo_Builder.cxx
1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2014 OPEN CASCADE SAS
3 // Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
4 // Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
5 //                         EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 //
7 // This file is part of Open CASCADE Technology software library.
8 //
9 // This library is free software; you can redistribute it and/or modify it under
10 // the terms of the GNU Lesser General Public License version 2.1 as published
11 // by the Free Software Foundation, with special exception defined in the file
12 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
13 // distribution for complete text of the license and disclaimer of any warranty.
14 //
15 // Alternatively, this file may be used under the terms of Open CASCADE
16 // commercial license or contractual agreement.
17
18
19 #include <BOPAlgo_Builder.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPAlgo_BuilderSolid.hxx>
22 #include <BOPAlgo_PaveFiller.hxx>
23 #include <BOPAlgo_Tools.hxx>
24 #include <BOPDS_DS.hxx>
25 #include <BOPDS_ShapeInfo.hxx>
26 #include <BOPTools_AlgoTools.hxx>
27 #include <BRep_Builder.hxx>
28 #include <IntTools_Context.hxx>
29 #include <Standard_ErrorHandler.hxx>
30 #include <Standard_Failure.hxx>
31 #include <TopExp.hxx>
32 #include <TopExp_Explorer.hxx>
33 #include <TopoDS.hxx>
34 #include <TopoDS_Compound.hxx>
35 #include <TopoDS_Solid.hxx>
36 #include <TopTools_IndexedMapOfShape.hxx>
37 #include <TopTools_MapOfOrientedShape.hxx>
38
39 //=======================================================================
40 //function : 
41 //purpose  : 
42 //=======================================================================
43 BOPAlgo_Builder::BOPAlgo_Builder()
44 :
45   BOPAlgo_BuilderShape(),
46   myArguments(myAllocator),
47   myMapFence(100, myAllocator),
48   myPaveFiller(NULL),
49   myDS(NULL),
50   myEntryPoint(0),
51   myImages(100, myAllocator),
52   myShapesSD(100, myAllocator),
53   myOrigins(100, myAllocator),
54   myInParts(100, myAllocator),
55   myNonDestructive(Standard_False),
56   myGlue(BOPAlgo_GlueOff),
57   myCheckInverted(Standard_True)
58 {
59 }
60 //=======================================================================
61 //function : 
62 //purpose  : 
63 //=======================================================================
64 BOPAlgo_Builder::BOPAlgo_Builder
65   (const Handle(NCollection_BaseAllocator)& theAllocator)
66 :
67   BOPAlgo_BuilderShape(theAllocator),
68   myArguments(myAllocator),
69   myMapFence(100, myAllocator),
70   myPaveFiller(NULL),
71   myDS(NULL),
72   myEntryPoint(0),
73   myImages(100, myAllocator), 
74   myShapesSD(100, myAllocator),
75   myOrigins(100, myAllocator),
76   myInParts(100, myAllocator),
77   myNonDestructive(Standard_False),
78   myGlue(BOPAlgo_GlueOff),
79   myCheckInverted(Standard_True)
80 {
81 }
82 //=======================================================================
83 //function : ~
84 //purpose  : 
85 //=======================================================================
86 BOPAlgo_Builder::~BOPAlgo_Builder()
87 {
88   if (myEntryPoint==1) {
89     if (myPaveFiller) {
90       delete myPaveFiller;
91       myPaveFiller=NULL;
92     }
93   }
94 }
95 //=======================================================================
96 //function : Clear
97 //purpose  : 
98 //=======================================================================
99 void BOPAlgo_Builder::Clear()
100 {
101   BOPAlgo_BuilderShape::Clear();
102   myArguments.Clear();
103   myMapFence.Clear();
104   myImages.Clear();
105   myShapesSD.Clear();
106   myOrigins.Clear();
107   myInParts.Clear();
108 }
109 //=======================================================================
110 //function : AddArgument
111 //purpose  : 
112 //=======================================================================
113 void BOPAlgo_Builder::AddArgument(const TopoDS_Shape& theShape)
114 {
115   if (myMapFence.Add(theShape)) {
116     myArguments.Append(theShape);
117   }
118 }
119 //=======================================================================
120 //function : SetArguments
121 //purpose  : 
122 //=======================================================================
123 void BOPAlgo_Builder::SetArguments(const TopTools_ListOfShape& theShapes)
124 {
125   TopTools_ListIteratorOfListOfShape aIt;
126   //
127   myArguments.Clear();
128   //
129   aIt.Initialize(theShapes);
130   for (; aIt.More(); aIt.Next()) {
131     const TopoDS_Shape& aS = aIt.Value();
132     AddArgument(aS);
133   }
134 }
135 //=======================================================================
136 // function: CheckData
137 // purpose: 
138 //=======================================================================
139 void BOPAlgo_Builder::CheckData()
140 {
141   Standard_Integer aNb = myArguments.Extent();
142   if (aNb<2) {
143     AddError (new BOPAlgo_AlertTooFewArguments); // too few arguments to process
144     return;
145   }
146   //
147   CheckFiller();
148 }
149 //=======================================================================
150 // function: CheckFiller
151 // purpose: 
152 //=======================================================================
153 void BOPAlgo_Builder::CheckFiller()
154 {
155   if (!myPaveFiller) {
156     AddError (new BOPAlgo_AlertNoFiller);
157     return;
158   }
159   GetReport()->Merge (myPaveFiller->GetReport());
160 }
161
162 //=======================================================================
163 //function : Prepare
164 //purpose  : 
165 //=======================================================================
166 void BOPAlgo_Builder::Prepare()
167 {
168   BRep_Builder aBB;
169   TopoDS_Compound aC;
170   //
171   // 1. myShape is empty compound
172   aBB.MakeCompound(aC);
173   myShape=aC;
174 }
175 //=======================================================================
176 //function : Perform
177 //purpose  : 
178 //=======================================================================
179 void BOPAlgo_Builder::Perform(const Message_ProgressRange& theRange)
180 {
181   GetReport()->Clear();
182   //
183   if (myEntryPoint==1) {
184     if (myPaveFiller) {
185       delete myPaveFiller;
186       myPaveFiller=NULL;
187     }
188   }
189   //
190   Handle(NCollection_BaseAllocator) aAllocator=
191     NCollection_BaseAllocator::CommonBaseAllocator();
192   //
193   BOPAlgo_PaveFiller* pPF=new BOPAlgo_PaveFiller(aAllocator);
194   //
195   pPF->SetArguments(myArguments);
196   pPF->SetRunParallel(myRunParallel);
197   Message_ProgressScope aPS(theRange, "Performing General Fuse operation", 10);
198   pPF->SetFuzzyValue(myFuzzyValue);
199   pPF->SetNonDestructive(myNonDestructive);
200   pPF->SetGlue(myGlue);
201   pPF->SetUseOBB(myUseOBB);
202   //
203   pPF->Perform(aPS.Next(9));
204   //
205   myEntryPoint=1;
206   PerformInternal(*pPF, aPS.Next(1));
207 }
208 //=======================================================================
209 //function : PerformWithFiller
210 //purpose  : 
211 //=======================================================================
212 void BOPAlgo_Builder::PerformWithFiller(const BOPAlgo_PaveFiller& theFiller, const Message_ProgressRange& theRange)
213 {
214   GetReport()->Clear();
215   myEntryPoint=0;
216   myNonDestructive = theFiller.NonDestructive();
217   myFuzzyValue = theFiller.FuzzyValue();
218   myGlue = theFiller.Glue();
219   myUseOBB = theFiller.UseOBB();
220   PerformInternal(theFiller, theRange);
221 }
222 //=======================================================================
223 //function : PerformInternal
224 //purpose  : 
225 //=======================================================================
226 void BOPAlgo_Builder::PerformInternal(const BOPAlgo_PaveFiller& theFiller, const Message_ProgressRange& theRange)
227 {
228   GetReport()->Clear();
229   //
230   try {
231     OCC_CATCH_SIGNALS
232     PerformInternal1(theFiller, theRange);
233   }
234   //
235   catch (Standard_Failure const&) {
236     AddError (new BOPAlgo_AlertBuilderFailed);
237   }
238 }
239
240 //=======================================================================
241 //function : getNbShapes
242 //purpose  : 
243 //=======================================================================
244 BOPAlgo_Builder::NbShapes BOPAlgo_Builder::getNbShapes() const
245 {
246   NbShapes aCounter;
247   aCounter.NbVertices() = myDS->ShapesSD().Size();
248   for (Standard_Integer i = 0; i < myDS->NbSourceShapes(); ++i)
249   {
250     const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i); 
251     switch (aSI.ShapeType())
252     {
253       case TopAbs_EDGE:
254       {
255         if (myDS->HasPaveBlocks(i))
256         {
257           aCounter.NbEdges()++;
258         }
259         break;
260       }
261       case TopAbs_WIRE:
262         aCounter.NbWires()++;
263         break;
264       case TopAbs_FACE:
265       {
266         if (myDS->HasFaceInfo(i))
267         {
268           aCounter.NbFaces()++;
269         }
270         break;
271       }
272       case TopAbs_SHELL:
273         aCounter.NbShells()++;
274         break;
275       case TopAbs_SOLID:
276         aCounter.NbSolids()++;
277         break;
278       case TopAbs_COMPSOLID:
279         aCounter.NbCompsolids()++;
280         break;
281       case TopAbs_COMPOUND:
282         aCounter.NbCompounds()++;
283         break;
284       default: break;
285     }
286   }
287   return aCounter;
288 }
289
290 //=======================================================================
291 // function: fillPIConstants
292 // purpose: 
293 //=======================================================================
294 void BOPAlgo_Builder::fillPIConstants (const Standard_Real theWhole,
295                                        BOPAlgo_PISteps& theSteps) const
296 {
297   // Fill in the constants:
298   if (myFillHistory)
299   {
300     // for FillHistroty, which takes about 5% of the whole operation
301     theSteps.SetStep(PIOperation_FillHistory, 0.05 * theWhole);
302   }
303
304   // and for PostTreat, which takes about 3% of the whole operation 
305   theSteps.SetStep(PIOperation_PostTreat, 0.03 * theWhole);
306 }
307
308 //=======================================================================
309 // function: fillPISteps
310 // purpose: 
311 //=======================================================================
312 void BOPAlgo_Builder::fillPISteps (BOPAlgo_PISteps& theSteps) const
313 {
314   // Compute the rest of the operations - all depend on the number of sub-shapes of certain type
315   NbShapes aNbShapes = getNbShapes();
316
317   theSteps.SetStep(PIOperation_TreatVertices, aNbShapes.NbVertices());
318   theSteps.SetStep(PIOperation_TreatEdges, aNbShapes.NbEdges());
319   theSteps.SetStep(PIOperation_TreatWires, aNbShapes.NbWires());
320   theSteps.SetStep(PIOperation_TreatFaces, 20 * aNbShapes.NbFaces());
321   theSteps.SetStep(PIOperation_TreatShells, aNbShapes.NbShells());
322   theSteps.SetStep(PIOperation_TreatSolids, 50 * aNbShapes.NbSolids());
323   theSteps.SetStep(PIOperation_TreatCompsolids, aNbShapes.NbCompsolids());
324   theSteps.SetStep(PIOperation_TreatCompounds, aNbShapes.NbCompounds());
325 }
326
327 //=======================================================================
328 //function : PerformInternal1
329 //purpose  : 
330 //=======================================================================
331 void BOPAlgo_Builder::PerformInternal1(const BOPAlgo_PaveFiller& theFiller, const Message_ProgressRange& theRange)
332 {
333   myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
334   myDS=myPaveFiller->PDS();
335   myContext=myPaveFiller->Context();
336   myFuzzyValue = myPaveFiller->FuzzyValue();
337   myNonDestructive = myPaveFiller->NonDestructive();
338   //
339   Message_ProgressScope aPS(theRange, "Building the result of General Fuse operation", 100);
340   // 1. CheckData
341   CheckData();
342   if (HasErrors()) {
343     return;
344   }
345   //
346   // 2. Prepare
347   Prepare();
348   if (HasErrors()) {
349     return;
350   }
351   //
352   BOPAlgo_PISteps aSteps(PIOperation_Last);
353   analyzeProgress(100., aSteps);
354   // 3. Fill Images
355   // 3.1 Vertice
356   FillImagesVertices(aPS.Next(aSteps.GetStep(PIOperation_TreatVertices)));
357   if (HasErrors()) {
358     return;
359   }
360   //
361   BuildResult(TopAbs_VERTEX);
362   if (HasErrors()) {
363     return;
364   }
365   // 3.2 Edges
366   FillImagesEdges(aPS.Next(aSteps.GetStep(PIOperation_TreatEdges)));
367   if (HasErrors()) {
368     return;
369   }
370   //
371   BuildResult(TopAbs_EDGE);
372   if (HasErrors()) {
373     return;
374   }
375   //
376   // 3.3 Wires
377   FillImagesContainers(TopAbs_WIRE, aPS.Next(aSteps.GetStep(PIOperation_TreatWires)));
378   if (HasErrors()) {
379     return;
380   }
381   //
382   BuildResult(TopAbs_WIRE);
383   if (HasErrors()) {
384     return;
385   }
386   
387   // 3.4 Faces
388   FillImagesFaces(aPS.Next(aSteps.GetStep(PIOperation_TreatFaces)));
389   if (HasErrors()) {
390     return;
391   }
392   //
393   BuildResult(TopAbs_FACE);
394   if (HasErrors()) {
395     return;
396   }
397   // 3.5 Shells
398   FillImagesContainers(TopAbs_SHELL, aPS.Next(aSteps.GetStep(PIOperation_TreatShells)));
399   if (HasErrors()) {
400     return;
401   }
402   
403   BuildResult(TopAbs_SHELL);
404   if (HasErrors()) {
405     return;
406   }
407   // 3.6 Solids
408   FillImagesSolids(aPS.Next(aSteps.GetStep(PIOperation_TreatSolids)));
409   if (HasErrors()) {
410     return;
411   }
412   
413   BuildResult(TopAbs_SOLID);
414   if (HasErrors()) {
415     return;
416   }
417   // 3.7 CompSolids
418   FillImagesContainers(TopAbs_COMPSOLID, aPS.Next(aSteps.GetStep(PIOperation_TreatCompsolids)));
419   if (HasErrors()) {
420     return;
421   }
422   
423   BuildResult(TopAbs_COMPSOLID);
424   if (HasErrors()) {
425     return;
426   }
427   
428   // 3.8 Compounds
429   FillImagesCompounds(aPS.Next(aSteps.GetStep(PIOperation_TreatCompounds)));
430   if (HasErrors()) {
431     return;
432   }
433   
434   BuildResult(TopAbs_COMPOUND);
435   if (HasErrors()) {
436     return;
437   }
438   //
439   // 4 History
440   PrepareHistory(aPS.Next(aSteps.GetStep(PIOperation_FillHistory)));
441   if (HasErrors()) {
442     return;
443   }
444   //
445   // 5 Post-treatment 
446   PostTreat(aPS.Next(aSteps.GetStep(PIOperation_PostTreat)));
447 }
448
449 //=======================================================================
450 //function : PostTreat
451 //purpose  : 
452 //=======================================================================
453 void BOPAlgo_Builder::PostTreat(const Message_ProgressRange& theRange)
454 {
455   Standard_Integer i, aNbS;
456   TopAbs_ShapeEnum aType;
457   TopTools_IndexedMapOfShape aMA;
458   if (myPaveFiller->NonDestructive()) {
459     // MapToAvoid
460     aNbS=myDS->NbSourceShapes();
461     for (i=0; i<aNbS; ++i) {
462       const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
463       aType=aSI.ShapeType();
464       if (aType==TopAbs_VERTEX ||
465           aType==TopAbs_EDGE||
466           aType==TopAbs_FACE) {
467         const TopoDS_Shape& aS=aSI.Shape();
468         aMA.Add(aS);
469       }
470     }
471   }
472   //
473   Message_ProgressScope aPS(theRange, "Post treatment of result shape", 2);
474   BOPTools_AlgoTools::CorrectTolerances(myShape, aMA, 0.05, myRunParallel);
475   aPS.Next();
476   BOPTools_AlgoTools::CorrectShapeTolerances(myShape, aMA, myRunParallel);
477 }
478
479 //=======================================================================
480 //function : BuildBOP
481 //purpose  : 
482 //=======================================================================
483 void BOPAlgo_Builder::BuildBOP(const TopTools_ListOfShape&  theObjects,
484                                const TopAbs_State           theObjState,
485                                const TopTools_ListOfShape&  theTools,
486                                const TopAbs_State           theToolsState,
487                                const Message_ProgressRange& theRange,
488                                Handle(Message_Report)       theReport)
489 {
490   if (HasErrors())
491     return;
492
493   // Report for the method
494   Handle(Message_Report) aReport = theReport.IsNull() ? myReport : theReport;
495
496   if (myArguments.IsEmpty() || myShape.IsNull())
497   {
498     aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBuilderFailed());
499     return;
500   }
501   // Check the input data
502   if ((theObjState   != TopAbs_IN && theObjState   != TopAbs_OUT) ||
503       (theToolsState != TopAbs_IN && theToolsState != TopAbs_OUT))
504   {
505     aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBOPNotSet());
506     return;
507   }
508
509   // Check input shapes
510   Standard_Boolean hasObjects = !theObjects.IsEmpty();
511   Standard_Boolean hasTools   = !theTools  .IsEmpty();
512   if (!hasObjects && !hasTools)
513   {
514     aReport->AddAlert(Message_Fail, new BOPAlgo_AlertTooFewArguments());
515     return;
516   }
517
518   // Check that all input solids are from the arguments
519   for (Standard_Integer i = 0; i < 2; ++i)
520   {
521     const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
522     TopTools_ListOfShape::Iterator itLS(aList);
523     for (; itLS.More(); itLS.Next())
524     {
525       const TopoDS_Shape& aS = itLS.Value();
526       // Check if the shape belongs to the arguments of operation
527       if (myDS->Index(aS) < 0)
528       {
529         aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnknownShape(aS));
530         return;
531       }
532
533       // Check if the shape is a solid or collection of them
534       if (aS.ShapeType() != TopAbs_SOLID)
535       {
536         TopTools_ListOfShape aLS;
537         TopTools_MapOfShape aMFence;
538         BOPTools_AlgoTools::TreatCompound(aS, aLS, &aMFence);
539
540         TopTools_ListOfShape::Iterator it(aLS);
541         for (; it.More(); it.Next())
542         {
543           const TopoDS_Shape& aSx = it.Value();
544           if (aSx.ShapeType() != TopAbs_SOLID &&
545               aSx.ShapeType() != TopAbs_COMPSOLID)
546           {
547             aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnsupportedType(aS));
548             return;
549           }
550         }
551       }
552     }
553   }
554
555   // Classification of the faces relatively solids has been made
556   // on the stage of Solids splitting. All results are saved into
557   // myInParts map, which connects the solids with its IN faces from
558   // other arguments. All faces not contained in the list of IN faces
559   // will be considered as OUT.
560
561   // Prepare the maps of splits of solids faces with orientations
562   TopTools_IndexedMapOfOrientedShape aMObjFacesOri, aMToolFacesOri;
563   // Prepare the maps of splits of solids faces
564   TopTools_IndexedMapOfShape aMObjFaces, aMToolFaces;
565   // Copy the list of IN faces of the solids into map
566   TopTools_MapOfShape anINObjects, anINTools;
567
568   for (Standard_Integer i = 0; i < 2; ++i)
569   {
570     const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
571     TopTools_IndexedMapOfOrientedShape& aMapOri  = !i ? aMObjFacesOri : aMToolFacesOri;
572     TopTools_IndexedMapOfShape& aMap = !i ? aMObjFaces : aMToolFaces;
573     TopTools_ListOfShape::Iterator itLS(aList);
574     for (; itLS.More(); itLS.Next())
575     {
576       const TopoDS_Shape& aShape = itLS.Value();
577       TopExp_Explorer expS(aShape, TopAbs_SOLID);
578       for (; expS.More(); expS.Next())
579       {
580         const TopoDS_Shape& aS = expS.Current();
581         TopExp_Explorer expF(aS, TopAbs_FACE);
582         for (; expF.More(); expF.Next())
583         {
584           const TopoDS_Shape& aF = expF.Current();
585           if (aF.Orientation() != TopAbs_FORWARD &&
586               aF.Orientation() != TopAbs_REVERSED)
587             continue;
588           const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
589           if (pLFIm)
590           {
591             TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
592             for (; itLFIm.More(); itLFIm.Next())
593             {
594               TopoDS_Face aFIm = TopoDS::Face(itLFIm.Value());
595               if (BOPTools_AlgoTools::IsSplitToReverse(aFIm, aF, myContext))
596                 aFIm.Reverse();
597               aMapOri.Add(aFIm);
598               aMap.Add(aFIm);
599             }
600           }
601           else
602           {
603             aMapOri.Add(aF);
604             aMap.Add(aF);
605           }
606         }
607
608         // Copy the list of IN faces into a map
609         const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
610         if (pLFIN)
611         {
612           TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
613           TopTools_ListOfShape::Iterator itLFIn(*pLFIN);
614           for (; itLFIn.More(); itLFIn.Next())
615             anINMap.Add(itLFIn.Value());
616         }
617       }
618     }
619   }
620
621   // Now we need to select all faces which will participate in
622   // building of the resulting solids. The final set of faces
623   // depends on the given states for the groups.
624   Standard_Boolean isObjectsIN = (theObjState   == TopAbs_IN),
625                    isToolsIN   = (theToolsState == TopAbs_IN);
626
627   // Shortcuts
628   Standard_Boolean bAvoidIN = (!isObjectsIN && !isToolsIN), // avoid all in faces
629                    bAvoidINforBoth = (isObjectsIN != isToolsIN); // avoid faces IN for both groups
630
631   // Choose which SD faces are needed to be taken - equally or differently oriented faces
632   Standard_Boolean isSameOriNeeded = (theObjState == theToolsState);
633   // Resulting faces
634   TopTools_IndexedMapOfOrientedShape aMResFacesOri;
635   TopTools_MapOfShape aMResFacesFence;
636   // Fence map
637   TopTools_MapOfShape aMFence, aMFToAvoid;
638   // Oriented fence map
639   TopTools_MapOfOrientedShape aMFenceOri;
640
641   for (Standard_Integer i = 0; i < 2; ++i)
642   {
643     const TopTools_IndexedMapOfOrientedShape& aMap  = !i ? aMObjFacesOri : aMToolFacesOri;
644     const TopTools_IndexedMapOfShape& anOppositeMap  = !i ? aMToolFaces : aMObjFaces;
645     const TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
646     const TopTools_MapOfShape& anOppositeINMap = !i ? anINTools : anINObjects;
647     const Standard_Boolean bTakeIN = !i ? isObjectsIN : isToolsIN;
648
649     const Standard_Integer aNbF = aMap.Extent();
650     for (Standard_Integer j = 1; j <= aNbF; ++j)
651     {
652       TopoDS_Shape aFIm = aMap(j);
653
654       Standard_Boolean isIN = anINMap.Contains(aFIm);
655       Standard_Boolean isINOpposite = anOppositeINMap.Contains(aFIm);
656
657       // Filtering for FUSE - avoid any IN faces
658       if (bAvoidIN && (isIN || isINOpposite))
659         continue;
660
661       // Filtering for CUT - avoid faces IN for both groups
662       if (bAvoidINforBoth && isIN && isINOpposite)
663         continue;
664
665       // Treatment of SD faces
666       if (!aMFence.Add(aFIm))
667       {
668         if (!anOppositeMap.Contains(aFIm))
669         {
670           // The face belongs to only one group
671           if (bTakeIN != isSameOriNeeded)
672             aMFToAvoid.Add(aFIm);
673         }
674         else
675         {
676           // The face belongs to both groups.
677           // Using its orientation decide if it is needed in the result or not.
678           Standard_Boolean isSameOri = !aMFenceOri.Add(aFIm);
679           if (isSameOriNeeded == isSameOri)
680           {
681             // Take the shape without classification
682             if (aMResFacesFence.Add(aFIm))
683               aMResFacesOri.Add(aFIm);
684           }
685           else
686             // Remove the face
687             aMFToAvoid.Add(aFIm);
688
689           continue;
690         }
691       }
692       if (!aMFenceOri.Add(aFIm))
693         continue;
694
695       if (bTakeIN == isINOpposite)
696       {
697         if (isIN)
698         {
699           aMResFacesOri.Add(aFIm);
700           aMResFacesOri.Add(aFIm.Reversed());
701         }
702         else if (bTakeIN && !isSameOriNeeded)
703           aMResFacesOri.Add(aFIm.Reversed());
704         else
705           aMResFacesOri.Add(aFIm);
706         aMResFacesFence.Add(aFIm);
707       }
708     }
709   }
710
711   // Remove the faces which has to be avoided
712   TopTools_ListOfShape aResFaces;
713   const Standard_Integer aNbRF = aMResFacesOri.Extent();
714   for (Standard_Integer i = 1; i <= aNbRF; ++i)
715   {
716     const TopoDS_Shape& aRF = aMResFacesOri(i);
717     if (!aMFToAvoid.Contains(aRF))
718       aResFaces.Append(aRF);
719   }
720   Message_ProgressScope aPS(theRange, NULL, 2);
721   BRep_Builder aBB;
722
723   // Try to build closed solids from the faces
724   BOPAlgo_BuilderSolid aBS;
725   aBS.SetShapes(aResFaces);
726   aBS.SetRunParallel(myRunParallel);
727   aBS.SetContext(myContext);
728   aBS.SetFuzzyValue(myFuzzyValue);
729   aBS.Perform(aPS.Next());
730
731   // Resulting solids
732   TopTools_ListOfShape aResSolids;
733
734   aMFence.Clear();
735   if (!aBS.HasErrors())
736   {
737     // If any, add solids into resulting compound
738     TopTools_ListIteratorOfListOfShape itA(aBS.Areas());
739     for (; itA.More(); itA.Next())
740     {
741       const TopoDS_Shape& aSolid = itA.Value();
742       // The solid must contain at least one face
743       // from either of objects or tools
744       TopExp_Explorer expF(aSolid, TopAbs_FACE);
745       for (; expF.More(); expF.Next())
746       {
747         const TopoDS_Shape& aF = expF.Current();
748         if (aMObjFacesOri.Contains(aF) || aMToolFacesOri.Contains(aF))
749           break;
750       }
751       if (expF.More())
752       {
753         aResSolids.Append(aSolid);
754         TopExp::MapShapes(aSolid, aMFence);
755       }
756     }
757   }
758   else
759   {
760     return;
761   }
762
763   // Collect unused faces
764   TopoDS_Compound anUnUsedFaces;
765   aBB.MakeCompound(anUnUsedFaces);
766
767   TopTools_ListOfShape::Iterator itLF(aResFaces);
768   for (; itLF.More(); itLF.Next())
769   {
770     if (aMFence.Add(itLF.Value()))
771       aBB.Add(anUnUsedFaces, itLF.Value());
772   }
773
774   // Build blocks from the unused faces
775   TopTools_ListOfShape aLCB;
776   BOPTools_AlgoTools::MakeConnexityBlocks(anUnUsedFaces, TopAbs_EDGE, TopAbs_FACE, aLCB);
777
778   // Build solid from each block
779   TopTools_ListIteratorOfListOfShape itCB(aLCB);
780   for (; itCB.More(); itCB.Next())
781   {
782     const TopoDS_Shape& aCB = itCB.Value();
783     TopoDS_Shell aShell;
784     aBB.MakeShell(aShell);
785     // Add faces of the block to the shell
786     TopExp_Explorer anExpF(aCB, TopAbs_FACE);
787     for (; anExpF.More(); anExpF.Next())
788       aBB.Add(aShell, TopoDS::Face(anExpF.Current()));
789
790     BOPTools_AlgoTools::OrientFacesOnShell(aShell);
791     // Make solid out of the shell
792     TopoDS_Solid aSolid;
793     aBB.MakeSolid(aSolid);
794     aBB.Add(aSolid, aShell);
795     // Add new solid to result
796     aResSolids.Append(aSolid);
797   }
798
799   if (!bAvoidIN)
800   {
801     // Fill solids with internal parts coming with the solids
802     TopTools_ListOfShape anInParts;
803     for (Standard_Integer i = 0; i < 2; ++i)
804     {
805       const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
806       TopTools_ListOfShape::Iterator itLS(aList);
807       for (; itLS.More(); itLS.Next())
808       {
809         TopExp_Explorer expS(itLS.Value(), TopAbs_SOLID);
810         for (; expS.More(); expS.Next())
811         {
812           const TopoDS_Shape& aS = expS.Current(); // Solid
813           for (TopoDS_Iterator it(aS); it.More(); it.Next())
814           {
815             const TopoDS_Shape& aSInt = it.Value();
816             if (aSInt.Orientation() == TopAbs_INTERNAL)
817               anInParts.Append(aSInt); // vertex or edge
818             else
819             {
820               // shell treatment
821               TopoDS_Iterator itInt(aSInt);
822               if (itInt.More() && itInt.Value().Orientation() == TopAbs_INTERNAL)
823                 anInParts.Append(aSInt);
824             }
825           }
826         }
827       }
828     }
829
830     BOPAlgo_Tools::FillInternals(aResSolids, anInParts, myImages, myContext);
831   }
832
833   // Combine solids into compound
834   TopoDS_Shape aResult;
835   aBB.MakeCompound(TopoDS::Compound(aResult));
836
837   TopTools_ListOfShape::Iterator itLS(aResSolids);
838   for (; itLS.More(); itLS.Next())
839     aBB.Add(aResult, itLS.Value());
840
841   myShape = aResult;
842   PrepareHistory(aPS.Next());
843 }