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