0030386: Modeling Algorithms - Unable to perform Cut operation
[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 //=======================================================================
41 //function : 
42 //purpose  : 
43 //=======================================================================
44 BOPAlgo_Builder::BOPAlgo_Builder()
45 :
46   BOPAlgo_BuilderShape(),
47   myArguments(myAllocator),
48   myMapFence(100, myAllocator),
49   myPaveFiller(NULL),
50   myDS(NULL),
51   myEntryPoint(0),
52   myImages(100, myAllocator),
53   myShapesSD(100, myAllocator),
54   myOrigins(100, myAllocator),
55   myInParts(100, myAllocator),
56   myNonDestructive(Standard_False),
57   myGlue(BOPAlgo_GlueOff),
58   myCheckInverted(Standard_True)
59 {
60 }
61 //=======================================================================
62 //function : 
63 //purpose  : 
64 //=======================================================================
65 BOPAlgo_Builder::BOPAlgo_Builder
66   (const Handle(NCollection_BaseAllocator)& theAllocator)
67 :
68   BOPAlgo_BuilderShape(theAllocator),
69   myArguments(myAllocator),
70   myMapFence(100, myAllocator),
71   myPaveFiller(NULL),
72   myDS(NULL),
73   myEntryPoint(0),
74   myImages(100, myAllocator), 
75   myShapesSD(100, myAllocator),
76   myOrigins(100, myAllocator),
77   myInParts(100, myAllocator),
78   myNonDestructive(Standard_False),
79   myGlue(BOPAlgo_GlueOff),
80   myCheckInverted(Standard_True)
81 {
82 }
83 //=======================================================================
84 //function : ~
85 //purpose  : 
86 //=======================================================================
87 BOPAlgo_Builder::~BOPAlgo_Builder()
88 {
89   if (myEntryPoint==1) {
90     if (myPaveFiller) {
91       delete myPaveFiller;
92       myPaveFiller=NULL;
93     }
94   }
95 }
96 //=======================================================================
97 //function : Clear
98 //purpose  : 
99 //=======================================================================
100 void BOPAlgo_Builder::Clear()
101 {
102   BOPAlgo_BuilderShape::Clear();
103   myArguments.Clear();
104   myMapFence.Clear();
105   myImages.Clear();
106   myShapesSD.Clear();
107   myOrigins.Clear();
108   myInParts.Clear();
109 }
110 //=======================================================================
111 //function : AddArgument
112 //purpose  : 
113 //=======================================================================
114 void BOPAlgo_Builder::AddArgument(const TopoDS_Shape& theShape)
115 {
116   if (myMapFence.Add(theShape)) {
117     myArguments.Append(theShape);
118   }
119 }
120 //=======================================================================
121 //function : SetArguments
122 //purpose  : 
123 //=======================================================================
124 void BOPAlgo_Builder::SetArguments(const TopTools_ListOfShape& theShapes)
125 {
126   TopTools_ListIteratorOfListOfShape aIt;
127   //
128   myArguments.Clear();
129   //
130   aIt.Initialize(theShapes);
131   for (; aIt.More(); aIt.Next()) {
132     const TopoDS_Shape& aS = aIt.Value();
133     AddArgument(aS);
134   }
135 }
136 //=======================================================================
137 // function: CheckData
138 // purpose: 
139 //=======================================================================
140 void BOPAlgo_Builder::CheckData()
141 {
142   Standard_Integer aNb = myArguments.Extent();
143   if (aNb<2) {
144     AddError (new BOPAlgo_AlertTooFewArguments); // too few arguments to process
145     return;
146   }
147   //
148   CheckFiller();
149 }
150 //=======================================================================
151 // function: CheckFiller
152 // purpose: 
153 //=======================================================================
154 void BOPAlgo_Builder::CheckFiller()
155 {
156   if (!myPaveFiller) {
157     AddError (new BOPAlgo_AlertNoFiller);
158     return;
159   }
160   GetReport()->Merge (myPaveFiller->GetReport());
161 }
162
163 //=======================================================================
164 //function : Prepare
165 //purpose  : 
166 //=======================================================================
167 void BOPAlgo_Builder::Prepare()
168 {
169   BRep_Builder aBB;
170   TopoDS_Compound aC;
171   //
172   // 1. myShape is empty compound
173   aBB.MakeCompound(aC);
174   myShape=aC;
175 }
176 //=======================================================================
177 //function : Perform
178 //purpose  : 
179 //=======================================================================
180 void BOPAlgo_Builder::Perform()
181 {
182   GetReport()->Clear();
183   //
184   if (myEntryPoint==1) {
185     if (myPaveFiller) {
186       delete myPaveFiller;
187       myPaveFiller=NULL;
188     }
189   }
190   //
191   Handle(NCollection_BaseAllocator) aAllocator=
192     NCollection_BaseAllocator::CommonBaseAllocator();
193   //
194   BOPAlgo_PaveFiller* pPF=new BOPAlgo_PaveFiller(aAllocator);
195   //
196   pPF->SetArguments(myArguments);
197   pPF->SetRunParallel(myRunParallel);
198   pPF->SetProgressIndicator(myProgressIndicator);
199   pPF->SetFuzzyValue(myFuzzyValue);
200   pPF->SetNonDestructive(myNonDestructive);
201   pPF->SetGlue(myGlue);
202   pPF->SetUseOBB(myUseOBB);
203   //
204   pPF->Perform();
205   //
206   myEntryPoint=1;
207   PerformInternal(*pPF);
208 }
209 //=======================================================================
210 //function : PerformWithFiller
211 //purpose  : 
212 //=======================================================================
213 void BOPAlgo_Builder::PerformWithFiller(const BOPAlgo_PaveFiller& theFiller)
214 {
215   GetReport()->Clear();
216   myEntryPoint=0;
217   myNonDestructive = theFiller.NonDestructive();
218   myFuzzyValue = theFiller.FuzzyValue();
219   myGlue = theFiller.Glue();
220   myUseOBB = theFiller.UseOBB();
221   PerformInternal(theFiller);
222 }
223 //=======================================================================
224 //function : PerformInternal
225 //purpose  : 
226 //=======================================================================
227 void BOPAlgo_Builder::PerformInternal(const BOPAlgo_PaveFiller& theFiller)
228 {
229   GetReport()->Clear();
230   //
231   try {
232     OCC_CATCH_SIGNALS
233     PerformInternal1(theFiller);
234   }
235   //
236   catch (Standard_Failure const&) {
237     AddError (new BOPAlgo_AlertBuilderFailed);
238   }
239 }
240 //=======================================================================
241 //function : PerformInternal1
242 //purpose  : 
243 //=======================================================================
244 void BOPAlgo_Builder::PerformInternal1(const BOPAlgo_PaveFiller& theFiller)
245 {
246   myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
247   myDS=myPaveFiller->PDS();
248   myContext=myPaveFiller->Context();
249   myFuzzyValue = myPaveFiller->FuzzyValue();
250   myNonDestructive = myPaveFiller->NonDestructive();
251   //
252   // 1. CheckData
253   CheckData();
254   if (HasErrors()) {
255     return;
256   }
257   //
258   // 2. Prepare
259   Prepare();
260   if (HasErrors()) {
261     return;
262   }
263   //
264   // 3. Fill Images
265   // 3.1 Vertice
266   FillImagesVertices();
267   if (HasErrors()) {
268     return;
269   }
270   //
271   BuildResult(TopAbs_VERTEX);
272   if (HasErrors()) {
273     return;
274   }
275   // 3.2 Edges
276   FillImagesEdges();
277   if (HasErrors()) {
278     return;
279   }
280   //
281   BuildResult(TopAbs_EDGE);
282   if (HasErrors()) {
283     return;
284   }
285   //
286   // 3.3 Wires
287   FillImagesContainers(TopAbs_WIRE);
288   if (HasErrors()) {
289     return;
290   }
291   //
292   BuildResult(TopAbs_WIRE);
293   if (HasErrors()) {
294     return;
295   }
296   
297   // 3.4 Faces
298   FillImagesFaces();
299   if (HasErrors()) {
300     return;
301   }
302   //
303   BuildResult(TopAbs_FACE);
304   if (HasErrors()) {
305     return;
306   }
307   // 3.5 Shells
308   FillImagesContainers(TopAbs_SHELL);
309   if (HasErrors()) {
310     return;
311   }
312   
313   BuildResult(TopAbs_SHELL);
314   if (HasErrors()) {
315     return;
316   }
317   // 3.6 Solids
318   FillImagesSolids();
319   if (HasErrors()) {
320     return;
321   }
322   
323   BuildResult(TopAbs_SOLID);
324   if (HasErrors()) {
325     return;
326   }
327   // 3.7 CompSolids
328   FillImagesContainers(TopAbs_COMPSOLID);
329   if (HasErrors()) {
330     return;
331   }
332   
333   BuildResult(TopAbs_COMPSOLID);
334   if (HasErrors()) {
335     return;
336   }
337   
338   // 3.8 Compounds
339   FillImagesCompounds();
340   if (HasErrors()) {
341     return;
342   }
343   
344   BuildResult(TopAbs_COMPOUND);
345   if (HasErrors()) {
346     return;
347   }
348   //
349   // 4.History
350   PrepareHistory();
351   //
352   //
353   // 5 Post-treatment 
354   PostTreat();
355   
356 }
357 //=======================================================================
358 //function : PostTreat
359 //purpose  : 
360 //=======================================================================
361 void BOPAlgo_Builder::PostTreat()
362 {
363   Standard_Integer i, aNbS;
364   TopAbs_ShapeEnum aType;
365   TopTools_IndexedMapOfShape aMA;
366   if (myPaveFiller->NonDestructive()) {
367     // MapToAvoid
368     aNbS=myDS->NbSourceShapes();
369     for (i=0; i<aNbS; ++i) {
370       const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
371       aType=aSI.ShapeType();
372       if (aType==TopAbs_VERTEX ||
373           aType==TopAbs_EDGE||
374           aType==TopAbs_FACE) {
375         const TopoDS_Shape& aS=aSI.Shape();
376         aMA.Add(aS);
377       }
378     }
379   }
380   //
381   BOPTools_AlgoTools::CorrectTolerances(myShape, aMA, 0.05, myRunParallel);
382   BOPTools_AlgoTools::CorrectShapeTolerances(myShape, aMA, myRunParallel);
383 }
384
385 //=======================================================================
386 //function : BuildBOP
387 //purpose  : 
388 //=======================================================================
389 void BOPAlgo_Builder::BuildBOP(const TopTools_ListOfShape& theObjects,
390                                const TopAbs_State          theObjState,
391                                const TopTools_ListOfShape& theTools,
392                                const TopAbs_State          theToolsState,
393                                Handle(Message_Report)      theReport)
394 {
395   if (HasErrors())
396     return;
397
398   // Report for the method
399   Handle(Message_Report) aReport = theReport.IsNull() ? myReport : theReport;
400
401   if (myArguments.IsEmpty() || myShape.IsNull())
402   {
403     aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBuilderFailed());
404     return;
405   }
406
407   // Check the input data
408   if ((theObjState   != TopAbs_IN && theObjState   != TopAbs_OUT) ||
409       (theToolsState != TopAbs_IN && theToolsState != TopAbs_OUT))
410   {
411     aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBOPNotSet());
412     return;
413   }
414
415   // Check input shapes
416   Standard_Boolean hasObjects = !theObjects.IsEmpty();
417   Standard_Boolean hasTools   = !theTools  .IsEmpty();
418   if (!hasObjects && !hasTools)
419   {
420     aReport->AddAlert(Message_Fail, new BOPAlgo_AlertTooFewArguments());
421     return;
422   }
423
424   // Check that all input solids are from the arguments
425   for (Standard_Integer i = 0; i < 2; ++i)
426   {
427     const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
428     TopTools_ListOfShape::Iterator itLS(aList);
429     for (; itLS.More(); itLS.Next())
430     {
431       const TopoDS_Shape& aS = itLS.Value();
432       // Check if the shape belongs to the arguments of operation
433       if (myDS->Index(aS) < 0)
434       {
435         aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnknownShape(aS));
436         return;
437       }
438
439       // Check if the shape is a solid or collection of them
440       if (aS.ShapeType() != TopAbs_SOLID)
441       {
442         TopTools_ListOfShape aLS;
443         TopTools_MapOfShape aMFence;
444         BOPTools_AlgoTools::TreatCompound(aS, aLS, &aMFence);
445
446         TopTools_ListOfShape::Iterator it(aLS);
447         for (; it.More(); it.Next())
448         {
449           const TopoDS_Shape& aSx = it.Value();
450           if (aSx.ShapeType() != TopAbs_SOLID &&
451               aSx.ShapeType() != TopAbs_COMPSOLID)
452           {
453             aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnsupportedType(aS));
454             return;
455           }
456         }
457       }
458     }
459   }
460
461   // Classification of the faces relatively solids has been made
462   // on the stage of Solids splitting. All results are saved into
463   // myInParts map, which connects the solids with its IN faces from
464   // other arguments. All faces not contained in the list of IN faces
465   // will be considered as OUT.
466
467   // Prepare the maps of splits of solids faces with orientations
468   TopTools_IndexedMapOfOrientedShape aMObjFacesOri, aMToolFacesOri;
469   // Prepare the maps of splits of solids faces
470   TopTools_IndexedMapOfShape aMObjFaces, aMToolFaces;
471   // Copy the list of IN faces of the solids into map
472   TopTools_MapOfShape anINObjects, anINTools;
473
474   for (Standard_Integer i = 0; i < 2; ++i)
475   {
476     const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
477     TopTools_IndexedMapOfOrientedShape& aMapOri  = !i ? aMObjFacesOri : aMToolFacesOri;
478     TopTools_IndexedMapOfShape& aMap = !i ? aMObjFaces : aMToolFaces;
479     TopTools_ListOfShape::Iterator itLS(aList);
480     for (; itLS.More(); itLS.Next())
481     {
482       const TopoDS_Shape& aShape = itLS.Value();
483       TopExp_Explorer expS(aShape, TopAbs_SOLID);
484       for (; expS.More(); expS.Next())
485       {
486         const TopoDS_Shape& aS = expS.Current();
487         TopExp_Explorer expF(aS, TopAbs_FACE);
488         for (; expF.More(); expF.Next())
489         {
490           const TopoDS_Shape& aF = expF.Current();
491           if (aF.Orientation() != TopAbs_FORWARD &&
492               aF.Orientation() != TopAbs_REVERSED)
493             continue;
494           const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
495           if (pLFIm)
496           {
497             TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
498             for (; itLFIm.More(); itLFIm.Next())
499             {
500               TopoDS_Face aFIm = TopoDS::Face(itLFIm.Value());
501               if (BOPTools_AlgoTools::IsSplitToReverse(aFIm, aF, myContext))
502                 aFIm.Reverse();
503               aMapOri.Add(aFIm);
504               aMap.Add(aFIm);
505             }
506           }
507           else
508           {
509             aMapOri.Add(aF);
510             aMap.Add(aF);
511           }
512         }
513
514         // Copy the list of IN faces into a map
515         const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
516         if (pLFIN)
517         {
518           TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
519           TopTools_ListOfShape::Iterator itLFIn(*pLFIN);
520           for (; itLFIn.More(); itLFIn.Next())
521             anINMap.Add(itLFIn.Value());
522         }
523       }
524     }
525   }
526
527   // Now we need to select all faces which will participate in
528   // building of the resulting solids. The final set of faces
529   // depends on the given states for the groups.
530   Standard_Boolean isObjectsIN = (theObjState   == TopAbs_IN),
531                    isToolsIN   = (theToolsState == TopAbs_IN);
532
533   // Shortcuts
534   Standard_Boolean bAvoidIN = (!isObjectsIN && !isToolsIN), // avoid all in faces
535                    bAvoidINforBoth = (isObjectsIN != isToolsIN); // avoid faces IN for both groups
536
537   // Choose which SD faces are needed to be taken - equally or differently oriented faces
538   Standard_Boolean isSameOriNeeded = (theObjState == theToolsState);
539   // Resulting faces
540   TopTools_IndexedMapOfOrientedShape aMResFacesOri;
541   TopTools_MapOfShape aMResFacesFence;
542   // Fence map
543   TopTools_MapOfShape aMFence, aMFToAvoid;
544   // Oriented fence map
545   TopTools_MapOfOrientedShape aMFenceOri;
546
547   for (Standard_Integer i = 0; i < 2; ++i)
548   {
549     const TopTools_IndexedMapOfOrientedShape& aMap  = !i ? aMObjFacesOri : aMToolFacesOri;
550     const TopTools_IndexedMapOfShape& anOppositeMap  = !i ? aMToolFaces : aMObjFaces;
551     const TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
552     const TopTools_MapOfShape& anOppositeINMap = !i ? anINTools : anINObjects;
553     const Standard_Boolean bTakeIN = !i ? isObjectsIN : isToolsIN;
554
555     const Standard_Integer aNbF = aMap.Extent();
556     for (Standard_Integer j = 1; j <= aNbF; ++j)
557     {
558       TopoDS_Shape aFIm = aMap(j);
559
560       Standard_Boolean isIN = anINMap.Contains(aFIm);
561       Standard_Boolean isINOpposite = anOppositeINMap.Contains(aFIm);
562
563       // Filtering for FUSE - avoid any IN faces
564       if (bAvoidIN && (isIN || isINOpposite))
565         continue;
566
567       // Filtering for CUT - avoid faces IN for both groups
568       if (bAvoidINforBoth && isIN && isINOpposite)
569         continue;
570
571       // Treatment of SD faces
572       if (!aMFence.Add(aFIm))
573       {
574         if (!anOppositeMap.Contains(aFIm))
575         {
576           // The face belongs to only one group
577           if (bTakeIN != isSameOriNeeded)
578             aMFToAvoid.Add(aFIm);
579         }
580         else
581         {
582           // The face belongs to both groups.
583           // Using its orientation decide if it is needed in the result or not.
584           Standard_Boolean isSameOri = !aMFenceOri.Add(aFIm);
585           if (isSameOriNeeded == isSameOri)
586           {
587             // Take the shape without classification
588             if (aMResFacesFence.Add(aFIm))
589               aMResFacesOri.Add(aFIm);
590           }
591           else
592             // Remove the face
593             aMFToAvoid.Add(aFIm);
594
595           continue;
596         }
597       }
598       if (!aMFenceOri.Add(aFIm))
599         continue;
600
601       if (bTakeIN == isINOpposite)
602       {
603         if (isIN)
604         {
605           aMResFacesOri.Add(aFIm);
606           aMResFacesOri.Add(aFIm.Reversed());
607         }
608         else if (bTakeIN && !isSameOriNeeded)
609           aMResFacesOri.Add(aFIm.Reversed());
610         else
611           aMResFacesOri.Add(aFIm);
612         aMResFacesFence.Add(aFIm);
613       }
614     }
615   }
616
617   // Remove the faces which has to be avoided
618   TopTools_ListOfShape aResFaces;
619   const Standard_Integer aNbRF = aMResFacesOri.Extent();
620   for (Standard_Integer i = 1; i <= aNbRF; ++i)
621   {
622     const TopoDS_Shape& aRF = aMResFacesOri(i);
623     if (!aMFToAvoid.Contains(aRF))
624       aResFaces.Append(aRF);
625   }
626
627   BRep_Builder aBB;
628
629   // Try to build closed solids from the faces
630   BOPAlgo_BuilderSolid aBS;
631   aBS.SetShapes(aResFaces);
632   aBS.SetRunParallel(myRunParallel);
633   aBS.SetContext(myContext);
634   aBS.SetFuzzyValue(myFuzzyValue);
635   aBS.SetProgressIndicator(myProgressIndicator);
636   aBS.Perform();
637
638   // Resulting solids
639   TopTools_ListOfShape aResSolids;
640
641   aMFence.Clear();
642   if (!aBS.HasErrors())
643   {
644     // If any, add solids into resulting compound
645     TopTools_ListIteratorOfListOfShape itA(aBS.Areas());
646     for (; itA.More(); itA.Next())
647     {
648       const TopoDS_Shape& aSolid = itA.Value();
649       // The solid must contain at least one face
650       // from either of objects or tools
651       TopExp_Explorer expF(aSolid, TopAbs_FACE);
652       for (; expF.More(); expF.Next())
653       {
654         const TopoDS_Shape& aF = expF.Current();
655         if (aMObjFacesOri.Contains(aF) || aMToolFacesOri.Contains(aF))
656           break;
657       }
658       if (expF.More())
659       {
660         aResSolids.Append(aSolid);
661         TopExp::MapShapes(aSolid, aMFence);
662       }
663     }
664   }
665
666   // Collect unused faces
667   TopoDS_Compound anUnUsedFaces;
668   aBB.MakeCompound(anUnUsedFaces);
669
670   TopTools_ListOfShape::Iterator itLF(aResFaces);
671   for (; itLF.More(); itLF.Next())
672   {
673     if (aMFence.Add(itLF.Value()))
674       aBB.Add(anUnUsedFaces, itLF.Value());
675   }
676
677   // Build blocks from the unused faces
678   TopTools_ListOfShape aLCB;
679   BOPTools_AlgoTools::MakeConnexityBlocks(anUnUsedFaces, TopAbs_EDGE, TopAbs_FACE, aLCB);
680
681   // Build solid from each block
682   TopTools_ListIteratorOfListOfShape itCB(aLCB);
683   for (; itCB.More(); itCB.Next())
684   {
685     const TopoDS_Shape& aCB = itCB.Value();
686     TopoDS_Shell aShell;
687     aBB.MakeShell(aShell);
688     // Add faces of the block to the shell
689     TopExp_Explorer anExpF(aCB, TopAbs_FACE);
690     for (; anExpF.More(); anExpF.Next())
691       aBB.Add(aShell, TopoDS::Face(anExpF.Current()));
692
693     BOPTools_AlgoTools::OrientFacesOnShell(aShell);
694     // Make solid out of the shell
695     TopoDS_Solid aSolid;
696     aBB.MakeSolid(aSolid);
697     aBB.Add(aSolid, aShell);
698     // Add new solid to result
699     aResSolids.Append(aSolid);
700   }
701
702   if (!bAvoidIN)
703   {
704     // Fill solids with internal parts coming with the solids
705     TopTools_ListOfShape anInParts;
706     for (Standard_Integer i = 0; i < 2; ++i)
707     {
708       const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
709       TopTools_ListOfShape::Iterator itLS(aList);
710       for (; itLS.More(); itLS.Next())
711       {
712         TopExp_Explorer expS(itLS.Value(), TopAbs_SOLID);
713         for (; expS.More(); expS.Next())
714         {
715           const TopoDS_Shape& aS = expS.Current(); // Solid
716           for (TopoDS_Iterator it(aS); it.More(); it.Next())
717           {
718             const TopoDS_Shape& aSInt = it.Value();
719             if (aSInt.Orientation() == TopAbs_INTERNAL)
720               anInParts.Append(aSInt); // vertex or edge
721             else
722             {
723               // shell treatment
724               TopoDS_Iterator itInt(aSInt);
725               if (itInt.More() && itInt.Value().Orientation() == TopAbs_INTERNAL)
726                 anInParts.Append(aSInt);
727             }
728           }
729         }
730       }
731     }
732
733     BOPAlgo_Tools::FillInternals(aResSolids, anInParts, myImages, myContext);
734   }
735
736   // Combine solids into compound
737   TopoDS_Shape aResult;
738   aBB.MakeCompound(TopoDS::Compound(aResult));
739
740   TopTools_ListOfShape::Iterator itLS(aResSolids);
741   for (; itLS.More(); itLS.Next())
742     aBB.Add(aResult, itLS.Value());
743
744   myShape = aResult;
745   PrepareHistory();
746 }