Salome HOME
Task #3016: 3.2 To add a mode «through all» for features RevolutionCut and RevolutionFuse
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_VersionedBoolean.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "FeaturesPlugin_VersionedBoolean.h"
21
22 #include <ModelAPI_Data.h>
23 #include <ModelAPI_Document.h>
24 #include <ModelAPI_AttributeReference.h>
25 #include <ModelAPI_AttributeInteger.h>
26 #include <ModelAPI_ResultBody.h>
27 #include <ModelAPI_AttributeSelectionList.h>
28 #include <ModelAPI_Session.h>
29 #include <ModelAPI_Validator.h>
30 #include <ModelAPI_Tools.h>
31
32 #include <GeomAlgoAPI_Boolean.h>
33 #include <GeomAlgoAPI_CompoundBuilder.h>
34 #include <GeomAlgoAPI_MakeShapeCustom.h>
35 #include <GeomAlgoAPI_MakeShapeList.h>
36 #include <GeomAlgoAPI_Partition.h>
37 #include <GeomAlgoAPI_PaveFiller.h>
38 #include <GeomAlgoAPI_ShapeBuilder.h>
39 #include <GeomAlgoAPI_ShapeTools.h>
40 #include <GeomAlgoAPI_Tools.h>
41 #include <GeomAlgoAPI_UnifySameDomain.h>
42 #include <GeomAPI_Face.h>
43 #include <GeomAPI_ShapeExplorer.h>
44 #include <GeomAPI_ShapeIterator.h>
45
46 #include <algorithm>
47 #include <map>
48
49 static void performBoolean(const GeomAlgoAPI_Tools::BOPType theBooleanType,
50                            GeomMakeShapePtr& theBooleanAlgo,
51                            const ListOfShape& theObjects,
52                            const ListOfShape& theTools)
53 {
54   if (theBooleanType == GeomAlgoAPI_Tools::BOOL_PARTITION)
55     theBooleanAlgo.reset(new GeomAlgoAPI_Partition(theObjects, theTools));
56   else {
57     // separate processing of FUSE, if only objects are given
58     if (theBooleanType == GeomAlgoAPI_Tools::BOOL_FUSE && theTools.empty()) {
59       if (theObjects.front()->shapeType() == GeomAPI_Shape::FACE)
60         theBooleanAlgo.reset(new GeomAlgoAPI_UnifySameDomain(theObjects));
61       else {
62         ListOfShape anObjects = theObjects;
63         ListOfShape aTools;
64         aTools.splice(aTools.begin(), anObjects, anObjects.begin());
65         theBooleanAlgo.reset(new GeomAlgoAPI_Boolean(anObjects, aTools, theBooleanType));
66       }
67     }
68     else
69       theBooleanAlgo.reset(new GeomAlgoAPI_Boolean(theObjects, theTools, theBooleanType));
70   }
71 }
72
73 //=================================================================================================
74 void FeaturesPlugin_VersionedBoolean::initVersion(const int theVersion,
75                                                   const AttributePtr theObjectsAttr,
76                                                   const AttributePtr theToolsAttr)
77 {
78   AttributePtr aVerAttr = data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId());
79   aVerAttr->setIsArgument(false);
80   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID());
81   if (!integer(VERSION_ID())->isInitialized() &&
82       (!theObjectsAttr || !theObjectsAttr->isInitialized()) &&
83       (!theToolsAttr || !theToolsAttr->isInitialized())) {
84     // this is a newly created feature (not read from file),
85     // so, initialize the latest version
86     integer(VERSION_ID())->setValue(theVersion);
87   }
88 }
89
90 //=================================================================================================
91 void FeaturesPlugin_VersionedBoolean::parentForShape(const GeomShapePtr& theShape,
92                                             const ResultPtr& theContext,
93                                             ObjectHierarchy& theShapesHierarchy)
94 {
95   ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(theContext);
96   if (aResCompSolidPtr.get()) {
97     std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
98     if (aContextShape->shapeType() <= GeomAPI_Shape::COMPSOLID) {
99       theShapesHierarchy.AddParent(theShape, aContextShape);
100       parentForShape(aContextShape, aResCompSolidPtr, theShapesHierarchy);
101     }
102   }
103 }
104
105 bool FeaturesPlugin_VersionedBoolean::processAttribute(const std::string& theAttributeName,
106                                               ObjectHierarchy& theObjects,
107                                               ListOfShape& thePlanesList)
108 {
109   AttributeSelectionListPtr anObjectsSelList = selectionList(theAttributeName);
110   for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
111     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
112     GeomShapePtr anObject = anObjectAttr->value();
113     if (!anObject.get()) {
114       // It could be a construction plane.
115       ResultPtr aContext = anObjectAttr->context();
116       anObject = anObjectAttr->context()->shape();
117       if (anObject.get()) {
118         thePlanesList.push_back(anObject);
119         continue;
120       } else
121         return false;
122     }
123
124     theObjects.AddObject(anObject);
125
126     ResultPtr aContext = anObjectAttr->context();
127     parentForShape(anObject, aContext, theObjects);
128   }
129   return true;
130 }
131
132 //=================================================================================================
133 bool FeaturesPlugin_VersionedBoolean::processObject(
134     const GeomAlgoAPI_Tools::BOPType theBooleanType,
135     const GeomShapePtr& theObject,
136     const ListOfShape& theTools,
137     const ListOfShape& thePlanes,
138     int& theResultIndex,
139     std::vector<FeaturesPlugin_Tools::ResultBaseAlgo>& theResultBaseAlgoList,
140     ListOfShape& theResultShapesList,
141     GeomShapePtr theResultCompound)
142 {
143   ListOfShape aListWithObject;
144   aListWithObject.push_back(theObject);
145   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
146   std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
147   GeomShapePtr aResShape;
148
149   // Resize planes.
150   ListOfShape aToolsWithPlanes = theTools;
151   ListOfShape aPlanesCopy = thePlanes;
152   resizePlanes(aListWithObject, aPlanesCopy, aMakeShapeList);
153   aToolsWithPlanes.insert(aToolsWithPlanes.end(), aPlanesCopy.begin(), aPlanesCopy.end());
154
155   if (theBooleanType == GeomAlgoAPI_Tools::BOOL_PARTITION)
156     aBoolAlgo.reset(new GeomAlgoAPI_Partition(aListWithObject, aToolsWithPlanes));
157   else
158     aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
159                                             aToolsWithPlanes,
160                                             theBooleanType));
161
162   // Checking that the algorithm worked properly.
163   std::string anError;
164   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) {
165     setError(anError);
166     return false;
167   }
168
169   aResShape = aBoolAlgo->shape();
170   if (aResShape.get() && aResShape->shapeType() == GeomAPI_Shape::COMPOUND) {
171     int aSubResultsNb = 0;
172     GeomAPI_ShapeIterator anIt(aResShape);
173     for (; anIt.more(); anIt.next())
174       ++aSubResultsNb;
175
176     if (aSubResultsNb == 1) {
177       anIt.init(aResShape);
178       if (anIt.more())
179         aResShape = anIt.current();
180     }
181   }
182
183   aMakeShapeList->appendAlgo(aBoolAlgo);
184
185   GeomAPI_ShapeIterator aShapeIt(aResShape);
186   if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) {
187     std::shared_ptr<ModelAPI_ResultBody> aResultBody;
188
189     if (theResultCompound) { // store BOP result to the compound
190       std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
191       aBuilder->add(theResultCompound, aResShape);
192       aMakeShapeList->appendAlgo(aBuilder);
193     }
194     else { // create a separate ResultBody
195       aResultBody = document()->createBody(data(), theResultIndex);
196
197       // tools should be added to the list to fulfill the correct history of modification
198       aListWithObject.insert(aListWithObject.end(), theTools.begin(), theTools.end());
199
200       ListOfShape aUsedTools = theTools;
201       aUsedTools.insert(aUsedTools.end(), thePlanes.begin(), thePlanes.end());
202
203       FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
204                                                aListWithObject,
205                                                aUsedTools,
206                                                aMakeShapeList,
207                                                aResShape);
208       setResult(aResultBody, theResultIndex);
209       ++theResultIndex;
210     }
211
212
213     FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
214     aRBA.resultBody = aResultBody;
215     aRBA.baseShape = theObject;
216     aRBA.makeShape = aMakeShapeList;
217     theResultBaseAlgoList.push_back(aRBA);
218     theResultShapesList.push_back(aResShape);
219   }
220   return true;
221 }
222
223 //=================================================================================================
224 bool FeaturesPlugin_VersionedBoolean::processCompsolid(
225     const GeomAlgoAPI_Tools::BOPType theBooleanType,
226     ObjectHierarchy& theCompsolidHierarchy,
227     const GeomShapePtr& theCompsolid,
228     const ListOfShape& theTools,
229     const ListOfShape& thePlanes,
230     int& theResultIndex,
231     std::vector<FeaturesPlugin_Tools::ResultBaseAlgo>& theResultBaseAlgoList,
232     ListOfShape& theResultShapesList,
233     GeomShapePtr theResultCompound)
234 {
235   ListOfShape aUsedInOperationSolids;
236   ListOfShape aNotUsedSolids;
237   theCompsolidHierarchy.SplitCompound(theCompsolid, aUsedInOperationSolids, aNotUsedSolids);
238
239   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
240
241   // Resize planes.
242   ListOfShape aToolsWithPlanes = theTools;
243   ListOfShape aPlanesCopy = thePlanes;
244   resizePlanes(aUsedInOperationSolids, aPlanesCopy, aMakeShapeList);
245   aToolsWithPlanes.insert(aToolsWithPlanes.end(), aPlanesCopy.begin(), aPlanesCopy.end());
246
247   std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
248   performBoolean(theBooleanType, aBoolAlgo, aUsedInOperationSolids, aToolsWithPlanes);
249
250   // Checking that the algorithm worked properly.
251   std::string anError;
252   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) {
253     setError(anError);
254     return false;
255   }
256
257   aMakeShapeList->appendAlgo(aBoolAlgo);
258   GeomShapePtr aResultShape = aBoolAlgo->shape();
259
260   // Add result to not used solids from compsolid.
261   if (!aNotUsedSolids.empty()) {
262     theCompsolidHierarchy.MarkProcessed(aNotUsedSolids);
263
264     ListOfShape aShapesToAdd = aNotUsedSolids;
265     aShapesToAdd.push_back(aBoolAlgo->shape());
266     std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
267         new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
268     if (!aFillerAlgo->isDone()) {
269       std::string aFeatureError = "Error: PaveFiller algorithm failed.";
270       setError(aFeatureError);
271       return false;
272     }
273
274     aMakeShapeList->appendAlgo(aFillerAlgo);
275     aResultShape = aFillerAlgo->shape();
276   }
277
278   GeomAPI_ShapeIterator aShapeIt(aResultShape);
279   if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX)
280   {
281     std::shared_ptr<ModelAPI_ResultBody> aResultBody;
282
283     if (theResultCompound) { // store BOP result to the compound
284       std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
285       aBuilder->add(theResultCompound, aResultShape);
286       aMakeShapeList->appendAlgo(aBuilder);
287     }
288     else { // create a separate ResultBody
289       aResultBody = document()->createBody(data(), theResultIndex);
290
291       ListOfShape aCompSolidList;
292       aCompSolidList.push_back(theCompsolid);
293       // tools should be added to the list to fulfill the correct history of modification
294       aCompSolidList.insert(aCompSolidList.end(), theTools.begin(), theTools.end());
295
296       ListOfShape aUsedTools = theTools;
297       aUsedTools.insert(aUsedTools.end(), thePlanes.begin(), thePlanes.end());
298
299       FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
300                                                aCompSolidList,
301                                                aUsedTools,
302                                                aMakeShapeList,
303                                                aResultShape);
304       setResult(aResultBody, theResultIndex);
305       ++theResultIndex;
306     }
307
308     FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
309     aRBA.resultBody = aResultBody;
310     aRBA.baseShape = theCompsolid;
311     aRBA.makeShape = aMakeShapeList;
312     theResultBaseAlgoList.push_back(aRBA);
313     theResultShapesList.push_back(aResultShape);
314   }
315   return true;
316 }
317
318 //=================================================================================================
319 bool FeaturesPlugin_VersionedBoolean::processCompound(
320     const GeomAlgoAPI_Tools::BOPType theBooleanType,
321     ObjectHierarchy& theCompoundHierarchy,
322     const GeomShapePtr& theCompound,
323     const ListOfShape& theTools,
324     int& theResultIndex,
325     std::vector<FeaturesPlugin_Tools::ResultBaseAlgo>& theResultBaseAlgoList,
326     ListOfShape& theResultShapesList,
327     GeomShapePtr theResultCompound)
328 {
329   ListOfShape aUsedInOperationShapes;
330   ListOfShape aNotUsedShapes;
331   theCompoundHierarchy.SplitCompound(theCompound, aUsedInOperationShapes, aNotUsedShapes);
332   if (theResultCompound) {
333     // Not necessary to keep all subs of the current compound,
334     // all unused solids are already stored in the result compound.
335     aNotUsedShapes.clear();
336   }
337
338   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
339   std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
340   performBoolean(theBooleanType, aBoolAlgo, aUsedInOperationShapes, theTools);
341
342   // Checking that the algorithm worked properly.
343   std::string anError;
344   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) {
345     setError(anError);
346     return false;
347   }
348
349   aMakeShapeList->appendAlgo(aBoolAlgo);
350   GeomShapePtr aResultShape = aBoolAlgo->shape();
351
352   // Add result to not used shape from compound.
353   if (!aNotUsedShapes.empty()) {
354     theCompoundHierarchy.MarkProcessed(aNotUsedShapes);
355
356     ListOfShape aShapesForResult = aNotUsedShapes;
357     if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
358       for (GeomAPI_ShapeIterator aResultIt(aResultShape); aResultIt.more(); aResultIt.next()) {
359         aShapesForResult.push_back(aResultIt.current());
360       }
361     }
362     else {
363       aShapesForResult.push_back(aResultShape);
364     }
365
366     if (aShapesForResult.size() == 1) {
367       aResultShape = aShapesForResult.front();
368     }
369     else {
370       aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult);
371     }
372   }
373
374   GeomAPI_ShapeIterator aShapeIt(aResultShape);
375   if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) {
376     std::shared_ptr<ModelAPI_ResultBody> aResultBody;
377
378     if (theResultCompound) { // store BOP result to the compound
379       std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
380       aBuilder->add(theResultCompound, aResultShape);
381       aMakeShapeList->appendAlgo(aBuilder);
382     }
383     else { // create a separate ResultBody
384       aResultBody = document()->createBody(data(), theResultIndex);
385
386       ListOfShape aCompoundList;
387       aCompoundList.push_back(theCompound);
388       FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
389                                                aCompoundList,
390                                                theTools,
391                                                aMakeShapeList,
392                                                aResultShape);
393       setResult(aResultBody, theResultIndex);
394       ++theResultIndex;
395     }
396
397     FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
398     aRBA.resultBody = aResultBody;
399     aRBA.baseShape = theCompound;
400     aRBA.makeShape = aMakeShapeList;
401     theResultBaseAlgoList.push_back(aRBA);
402     theResultShapesList.push_back(aResultShape);
403   }
404   return true;
405 }
406
407 //==================================================================================================
408 GeomShapePtr FeaturesPlugin_VersionedBoolean::keepUnusedSubsOfCompound(
409     const GeomShapePtr& theResult,
410     const ObjectHierarchy& theObjectsHierarchy,
411     const ObjectHierarchy& theToolsHierarchy,
412     std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList)
413 {
414   ListOfShape aCompounds;
415   theObjectsHierarchy.CompoundsOfUnusedObjects(aCompounds);
416   theToolsHierarchy.CompoundsOfUnusedObjects(aCompounds);
417
418   GeomShapePtr aResultShape = theResult;
419   if (!aCompounds.empty()) {
420     aResultShape = aCompounds.front();
421     aCompounds.pop_front();
422
423     std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
424     for (ListOfShape::iterator anIt = aCompounds.begin(); anIt != aCompounds.end(); ++anIt) {
425       for (GeomAPI_ShapeIterator aSub(*anIt); aSub.more(); aSub.next())
426         aBuilder->add(aResultShape, aSub.current());
427     }
428
429     if (theResult)
430       aBuilder->add(aResultShape, theResult);
431
432     theMakeShapeList->appendAlgo(aBuilder);
433   }
434   return aResultShape;
435 }
436
437 //=================================================================================================
438 void FeaturesPlugin_VersionedBoolean::resizePlanes(
439     const ListOfShape& theObjects,
440     ListOfShape& thePlanes,
441     std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList)
442 {
443   if (thePlanes.empty())
444     return;
445
446   std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
447       GeomAlgoAPI_ShapeTools::getBoundingBox(theObjects, 1.0);
448
449   // Resize planes to fit in bounding box
450   for (ListOfShape::iterator anIt = thePlanes.begin(); anIt != thePlanes.end(); ++anIt) {
451     GeomShapePtr aPlane = *anIt;
452     GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
453     std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(new GeomAlgoAPI_MakeShapeCustom);
454     aMkShCustom->addModified(aPlane, aTool);
455     theMakeShapeList->appendAlgo(aMkShCustom);
456     *anIt = aTool;
457   }
458 }
459
460 //=================================================================================================
461 int FeaturesPlugin_VersionedBoolean::version()
462 {
463   AttributeIntegerPtr aVersionAttr = integer(VERSION_ID());
464   int aVersion = 0;
465   if (aVersionAttr && aVersionAttr->isInitialized())
466     aVersion = aVersionAttr->value();
467   return aVersion;
468 }
469
470 //=================================================================================================
471
472 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::AddObject(const GeomShapePtr& theObject)
473 {
474   myObjects.push_back(theObject);
475 }
476
477 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::AddParent(const GeomShapePtr& theShape,
478                                                                  const GeomShapePtr& theParent)
479 {
480   myParent[theShape] = theParent;
481
482   MapShapeToIndex::iterator aFound = myParentIndices.find(theParent);
483   size_t anIndex = myParentIndices.size();
484   if (aFound == myParentIndices.end()) {
485     myParentIndices[theParent] = anIndex;
486     mySubshapes.push_back(ShapeAndSubshapes(theParent, ListOfShape()));
487   } else
488     anIndex = aFound->second;
489
490   mySubshapes[anIndex].second.push_back(theShape);
491 }
492
493 GeomShapePtr FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Parent(const GeomShapePtr& theShape,
494                                                                       bool theMarkProcessed)
495 {
496   MapShapeToParent::const_iterator aFound = myParent.find(theShape);
497   GeomShapePtr aParent;
498   if (aFound != myParent.end()) {
499     aParent = aFound->second;
500     if (theMarkProcessed) {
501       // mark the parent and all its subs as processed by Boolean algorithm
502       myProcessedObjects.insert(aParent);
503       const ListOfShape& aSubs = mySubshapes[myParentIndices[aParent]].second;
504       for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt)
505         myProcessedObjects.insert(*anIt);
506     }
507   }
508   return aParent;
509 }
510
511 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::MarkProcessed(const GeomShapePtr& theShape)
512 {
513   myProcessedObjects.insert(theShape);
514 }
515
516 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::MarkProcessed(const ListOfShape& theShapes)
517 {
518   for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt)
519     MarkProcessed(*anIt);
520 }
521
522 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::ObjectsByType(
523     ListOfShape& theShapesByType,
524     ListOfShape& theOtherShapes,
525     const GeomAPI_Shape::ShapeType theMinType,
526     const GeomAPI_Shape::ShapeType theMaxType) const
527 {
528   if (theMinType > theMaxType)
529     return ObjectsByType(theShapesByType, theOtherShapes, theMaxType, theMinType);
530
531   // no need to select objects if whole range is specified
532   if (theMinType == GeomAPI_Shape::COMPOUND && theMaxType == GeomAPI_Shape::SHAPE) {
533     theShapesByType.insert(theShapesByType.end(), myObjects.begin(), myObjects.end());
534     return;
535   }
536
537   for (ListOfShape::const_iterator anIt = myObjects.begin(); anIt != myObjects.end(); ++anIt) {
538     GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType();
539     if (aType >= theMinType && aType <= theMaxType)
540       theShapesByType.push_back(*anIt);
541     else
542       theOtherShapes.push_back(*anIt);
543   }
544 }
545
546
547 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::SplitCompound(
548     const GeomShapePtr& theCompShape,
549     ListOfShape& theUsed,
550     ListOfShape& theNotUsed) const
551 {
552   theUsed.clear();
553   theNotUsed.clear();
554
555   MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theCompShape);
556   if (aFoundIndex == myParentIndices.end())
557     return; // no such shape
558
559   theUsed = mySubshapes[aFoundIndex->second].second;
560   SetOfShape aSubsSet;
561   aSubsSet.insert(theUsed.begin(), theUsed.end());
562
563   for (GeomAPI_ShapeIterator anExp(theCompShape); anExp.more(); anExp.next()) {
564     GeomShapePtr aCurrent = anExp.current();
565     if (aSubsSet.find(aCurrent) == aSubsSet.end())
566       theNotUsed.push_back(aCurrent);
567   }
568 }
569
570 bool FeaturesPlugin_VersionedBoolean::ObjectHierarchy::IsEmpty() const
571 {
572   return myObjects.empty();
573 }
574
575 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::CompoundsOfUnusedObjects(
576     ListOfShape& theDestination) const
577 {
578   SetOfShape aUsedObjects = myProcessedObjects;
579   aUsedObjects.insert(myObjects.begin(), myObjects.end());
580
581   for (std::vector<ShapeAndSubshapes>::const_iterator anIt = mySubshapes.begin();
582        anIt != mySubshapes.end(); ++anIt) {
583     MapShapeToParent::const_iterator aParent = myParent.find(anIt->first);
584     if ((aParent == myParent.end() || !aParent->second) &&
585          anIt->first->shapeType() ==  GeomAPI_Shape::COMPOUND) {
586       // this is a top-level compound
587       GeomShapePtr aCompound = collectUnusedSubs(anIt->first, aUsedObjects);
588       // add to destination non-empty compounds only
589       if (aCompound)
590         theDestination.push_back(aCompound);
591     }
592   }
593 }
594
595 GeomShapePtr FeaturesPlugin_VersionedBoolean::ObjectHierarchy::collectUnusedSubs(
596     GeomShapePtr theTopLevelCompound,
597     const SetOfShape& theUsed) const
598 {
599   GeomShapePtr aResult = theTopLevelCompound->emptyCopied();
600   bool isResultEmpty = true;
601
602   for (GeomAPI_ShapeIterator aSub(theTopLevelCompound); aSub.more(); aSub.next()) {
603     GeomShapePtr aCurrent = aSub.current();
604     if (theUsed.find(aCurrent) != theUsed.end())
605       continue; // already used
606
607     MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(aCurrent);
608     if (aCurrent->shapeType() > GeomAPI_Shape::COMPOUND ||
609         aFoundIndex == myParentIndices.end()) {
610       bool isAddShape = true;
611       // check compsolid is fully unused in the Boolean operation
612       if (aCurrent->shapeType() == GeomAPI_Shape::COMPSOLID) {
613         for (GeomAPI_ShapeIterator anIt(aCurrent); isAddShape && anIt.more(); anIt.next())
614           isAddShape = theUsed.find(anIt.current()) == theUsed.end();
615       }
616
617       if (isAddShape) { // low-level shape, add it
618         GeomAlgoAPI_ShapeBuilder::add(aResult, aCurrent);
619         isResultEmpty = false;
620       }
621     } else {
622       GeomShapePtr aCompound = collectUnusedSubs(aCurrent, theUsed);
623       if (aCompound) {
624         GeomAlgoAPI_ShapeBuilder::add(aResult, aCompound);
625         isResultEmpty = false;
626       }
627     }
628   }
629   return isResultEmpty ? GeomShapePtr() : aResult;
630 }
631
632
633 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator
634 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Begin()
635 {
636   return Iterator(this);
637 }
638
639 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator
640 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::End()
641 {
642   return Iterator(this, false);
643 }
644
645 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::Iterator(
646     FeaturesPlugin_VersionedBoolean::ObjectHierarchy* theHierarchy, bool isBegin)
647   : myHierarchy(theHierarchy)
648 {
649   if (isBegin) {
650     myObject = myHierarchy->myObjects.begin();
651     SkipAlreadyProcessed();
652   } else
653     myObject = myHierarchy->myObjects.end();
654 }
655
656 void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::SkipAlreadyProcessed()
657 {
658   while (myObject != myHierarchy->myObjects.end() &&
659          myHierarchy->myProcessedObjects.find(*myObject) != myHierarchy->myProcessedObjects.end())
660     ++myObject;
661 }
662
663 bool FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator==(
664     const Iterator& theOther) const
665 {
666   return myObject == theOther.myObject;
667 }
668
669 bool FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator!=(
670     const Iterator& theOther) const
671 {
672   return !operator==(theOther);
673 }
674
675 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator&
676 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator++()
677 {
678   ++myObject;
679   SkipAlreadyProcessed();
680   return *this;
681 }
682
683 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator
684 FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator++(int)
685 {
686   Iterator aCurrent;
687   aCurrent.myHierarchy = myHierarchy;
688   aCurrent.myObject = myObject;
689
690   // increase iterator
691   operator++();
692
693   return aCurrent;
694 }
695
696 GeomShapePtr FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator*() const
697 {
698   myHierarchy->myProcessedObjects.insert(*myObject);
699   return *myObject;
700 }