Salome HOME
Issue #1664: improve mechanism of removing coincidence
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Union.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        FeaturesPlugin_Union.cpp
4 // Created:     17 June 2016
5 // Author:      Dmitry Bobylev
6
7 #include "FeaturesPlugin_Union.h"
8
9 #include <GeomAlgoAPI_Boolean.h>
10 #include <GeomAlgoAPI_MakeShapeList.h>
11 #include <GeomAlgoAPI_PaveFiller.h>
12
13 #include <GeomAPI_ShapeExplorer.h>
14
15 #include <ModelAPI_AttributeSelectionList.h>
16 #include <ModelAPI_ResultCompSolid.h>
17 #include <ModelAPI_Tools.h>
18
19 //=================================================================================================
20 FeaturesPlugin_Union::FeaturesPlugin_Union()
21 {
22 }
23
24 //=================================================================================================
25 void FeaturesPlugin_Union::initAttributes()
26 {
27   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
28 }
29
30 //=================================================================================================
31 void FeaturesPlugin_Union::execute()
32 {
33   ListOfShape anObjects;
34   std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
35
36   // Getting objects.
37   AttributeSelectionListPtr anObjectsSelList = selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
38   for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
39     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
40     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
41     if(!anObject.get()) {
42       return;
43     }
44     ResultPtr aContext = anObjectAttr->context();
45     ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
46     if(aResCompSolidPtr.get()) {
47       std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
48       std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
49       for(; anIt != aCompSolidsObjects.end(); anIt++) {
50         if(anIt->first->isEqual(aContextShape)) {
51           aCompSolidsObjects[anIt->first].push_back(anObject);
52           break;
53         }
54       }
55       if(anIt == aCompSolidsObjects.end()) {
56         aCompSolidsObjects[aContextShape].push_back(anObject);
57       }
58     } else {
59       anObjects.push_back(anObject);
60     }
61   }
62
63   // Collecting solids from compsolids which will not be modified in boolean operation and will be added to result.
64   ListOfShape aShapesToAdd;
65   for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
66     anIt != aCompSolidsObjects.end(); anIt++) {
67     std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
68     ListOfShape& aUsedInOperationSolids = anIt->second;
69     anObjects.insert(anObjects.end(), aUsedInOperationSolids.begin(), aUsedInOperationSolids.end());
70
71     // Collect solids from compsolid which will not be modified in boolean operation.
72     for(GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
73       std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
74       ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
75       for(; anIt != aUsedInOperationSolids.end(); anIt++) {
76         if(aSolidInCompSolid->isEqual(*anIt)) {
77           break;
78         }
79       }
80       if(anIt == aUsedInOperationSolids.end()) {
81         aShapesToAdd.push_back(aSolidInCompSolid);
82       }
83     }
84   }
85
86   if(anObjects.size() < 2) {
87     setError("Error: Not enough objects for operation. Should be at least 2.");
88     return;
89   }
90
91   // Fuse objects.
92   ListOfShape aTools;
93   aTools.splice(aTools.begin(), anObjects, anObjects.begin());
94   std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
95                                                                          aTools,
96                                                                          GeomAlgoAPI_Boolean::BOOL_FUSE));
97
98   // Checking that the algorithm worked properly.
99   GeomAlgoAPI_MakeShapeList aMakeShapeList;
100   GeomAPI_DataMapOfShapeShape aMapOfShapes;
101   if(!aFuseAlgo->isDone()) {
102     setError("Error: Boolean algorithm failed.");
103     return;
104   }
105   if(aFuseAlgo->shape()->isNull()) {
106     setError("Error: Resulting shape is Null.");
107     return;
108   }
109   if(!aFuseAlgo->isValid()) {
110     setError("Error: Resulting shape is not valid.");
111     return;
112   }
113
114   GeomShapePtr aShape = aFuseAlgo->shape();
115   aMakeShapeList.appendAlgo(aFuseAlgo);
116   aMapOfShapes.merge(aFuseAlgo->mapOfSubShapes());
117
118   // Store original shapes for naming.
119   anObjects.splice(anObjects.begin(), aTools);
120   anObjects.insert(anObjects.end(), aShapesToAdd.begin(), aShapesToAdd.end());
121
122   // Combine result with not used solids from compsolid.
123   if(aShapesToAdd.size() > 0) {
124     aShapesToAdd.push_back(aShape);
125     std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
126     if(!aFillerAlgo->isDone()) {
127       setError("Error: PaveFiller algorithm failed.");
128       return;
129     }
130     if(aFillerAlgo->shape()->isNull()) {
131       setError("Error: Resulting shape is Null.");
132       return;
133     }
134     if(!aFillerAlgo->isValid()) {
135       setError("Error: Resulting shape is not valid.");
136       return;
137     }
138
139     aShape = aFillerAlgo->shape();
140     aMakeShapeList.appendAlgo(aFillerAlgo);
141     aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes());
142   }
143
144   // Store result and naming.
145   const int aModifyTag = 1;
146   const int aDeletedTag = 2;
147   const int aSubsolidsTag = 3; /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
148   const std::string aModName = "Modified";
149
150   std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data());
151   aResultBody->storeModified(anObjects.front(), aShape, aSubsolidsTag);
152
153   for(ListOfShape::const_iterator anIter = anObjects.begin(); anIter != anObjects.end(); ++anIter) {
154     aResultBody->loadAndOrientModifiedShapes(&aMakeShapeList, *anIter, GeomAPI_Shape::FACE,
155                                              aModifyTag, aModName, aMapOfShapes);
156     aResultBody->loadDeletedShapes(&aMakeShapeList, *anIter, GeomAPI_Shape::FACE, aDeletedTag);
157   }
158
159   setResult(aResultBody);
160 }