Salome HOME
Optimization of the RemoveSubshapes feature to make it work faster in some big models...
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_RemoveSubShapes.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_RemoveSubShapes.h"
21
22 #include <ModelAPI_AttributeSelectionList.h>
23 #include <ModelAPI_AttributeString.h>
24 #include <ModelAPI_ResultBody.h>
25 #include <ModelAPI_ResultConstruction.h>
26 #include <ModelAPI_Session.h>
27 #include <ModelAPI_Tools.h>
28 #include <ModelAPI_Validator.h>
29
30 #include <GeomAPI_ShapeIterator.h>
31 #include <GeomAPI_ShapeExplorer.h>
32
33 #include <GeomAlgoAPI_Copy.h>
34 #include <GeomAlgoAPI_ShapeBuilder.h>
35 #include <GeomAlgoAPI_ShapeTools.h>
36 #include <GeomAlgoAPI_MakeShapeCustom.h>
37
38
39 //==================================================================================================
40 FeaturesPlugin_RemoveSubShapes::FeaturesPlugin_RemoveSubShapes()
41 : myChangedInCode(false)
42 {
43 }
44
45 //==================================================================================================
46 void FeaturesPlugin_RemoveSubShapes::initAttributes()
47 {
48   data()->addAttribute(BASE_SHAPE_ID(), ModelAPI_AttributeSelection::typeId());
49
50   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
51
52   data()->addAttribute(SUBSHAPES_TO_KEEP_ID(), ModelAPI_AttributeSelectionList::typeId());
53
54   data()->addAttribute(SUBSHAPES_TO_REMOVE_ID(), ModelAPI_AttributeSelectionList::typeId());
55 }
56
57 void FeaturesPlugin_RemoveSubShapes::attributeChanged(const std::string& theID)
58 {
59   ModelAPI_Feature::attributeChanged(theID);
60
61   if (myChangedInCode) return;
62
63   AttributeSelectionPtr aShapeAttrSelection = selection(BASE_SHAPE_ID());
64   AttributeSelectionListPtr aSubShapesToKeepAttrList = selectionList(SUBSHAPES_TO_KEEP_ID());
65   AttributeSelectionListPtr aSubShapesToRemoveAttrList = selectionList(SUBSHAPES_TO_REMOVE_ID());
66   if (!aShapeAttrSelection.get()
67       || !aSubShapesToKeepAttrList.get()
68       || !aSubShapesToRemoveAttrList.get())
69   {
70     return;
71   }
72
73   ResultPtr aContext = aShapeAttrSelection->context();
74   ResultBodyPtr aResultBody =
75     std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
76   if (!aResultBody.get()) {
77     aSubShapesToKeepAttrList->clear();
78     aSubShapesToRemoveAttrList->clear();
79     return;
80   }
81   const bool isHasSubs = ModelAPI_Tools::hasSubResults(aResultBody);
82
83   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
84   if(!aBaseShape.get()) {
85     aBaseShape = aContext->shape();
86   }
87
88   myChangedInCode = true;
89   if (theID == BASE_SHAPE_ID() || theID == SUBSHAPES_TO_KEEP_ID() ||
90     theID == SUBSHAPES_TO_REMOVE_ID()) {
91     std::list<ResultPtr> anAllSubs;
92     ModelAPI_Tools::allSubs(aResultBody, anAllSubs);
93
94     if(theID == BASE_SHAPE_ID()) {
95       aSubShapesToKeepAttrList->clear();
96       aSubShapesToRemoveAttrList->clear();
97
98       if (!aBaseShape.get()) {
99         return;
100       }
101
102       std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
103       for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt)
104       {
105         GeomShapePtr aSubShape = *anIt;
106         if(!isHasSubs) {
107           aSubShapesToKeepAttrList->append(aContext, aSubShape);
108         } else {
109           std::list<ResultPtr>::iterator aSubsIt = anAllSubs.begin();
110           for(; aSubsIt != anAllSubs.end(); aSubsIt++) {
111             ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aSubsIt);
112             if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aSubShape)) {
113               aSubShapesToKeepAttrList->append(aSub, aSubShape);
114               break;
115             }
116           }
117         }
118       }
119     }
120     else if (theID == SUBSHAPES_TO_KEEP_ID())
121     {
122       aSubShapesToRemoveAttrList->clear();
123
124       if (!aBaseShape.get()) {
125         return;
126       }
127
128       int anIndex;
129       // optimization: collect selection attribute values into a map
130       const int aSubsToKeepNb = aSubShapesToKeepAttrList->size();
131       GeomAPI_DataMapOfShapeShape aSubShapesToKeep;
132       for(anIndex = 0; anIndex < aSubsToKeepNb; ++anIndex) {
133         AttributeSelectionPtr anAttrSelectionInList = aSubShapesToKeepAttrList->value(anIndex);
134         GeomShapePtr aSubShapeToKeep = anAttrSelectionInList->value();
135         if (aSubShapeToKeep.get())
136           aSubShapesToKeep.bind(aSubShapeToKeep, aSubShapeToKeep);
137       }
138
139       std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
140       for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt)
141       {
142         GeomShapePtr aSubShape = *anIt;
143         if (aSubShapesToKeep.isBound(aSubShape))
144           continue;
145
146         if(!isHasSubs) {
147           aSubShapesToRemoveAttrList->append(aContext, aSubShape);
148         }
149         else {
150           std::list<ResultPtr>::iterator aSubsIt = anAllSubs.begin();
151           for (; aSubsIt != anAllSubs.end(); aSubsIt++) {
152             ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aSubsIt);
153             if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aSubShape)) {
154               aSubShapesToRemoveAttrList->append(aSub, aSubShape);
155               break;
156             }
157           }
158         }
159       }
160     }
161     else if (theID == SUBSHAPES_TO_REMOVE_ID())
162     {
163       aSubShapesToKeepAttrList->clear();
164
165       if (!aBaseShape.get()) {
166         return;
167       }
168
169       int anIndex;
170       const int aSubsToRemoveNb = aSubShapesToRemoveAttrList->size();
171       GeomAPI_DataMapOfShapeShape aSubShapesToRemove;
172       for(anIndex = 0; anIndex < aSubsToRemoveNb; ++anIndex) {
173         AttributeSelectionPtr anAttrSelectionInList = aSubShapesToRemoveAttrList->value(anIndex);
174         GeomShapePtr aSubShapeToRemove = anAttrSelectionInList->value();
175         if (aSubShapeToRemove.get())
176           aSubShapesToRemove.bind(aSubShapeToRemove, aSubShapeToRemove);
177       }
178
179
180       std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
181       for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt)
182       {
183         GeomShapePtr aSubShape = *anIt;
184         if (aSubShapesToRemove.isBound(aSubShape))
185           continue;
186
187         if (!isHasSubs) {
188           aSubShapesToKeepAttrList->append(aContext, aSubShape);
189         }
190         else {
191           std::list<ResultPtr>::iterator aSubsIt = anAllSubs.begin();
192           for (; aSubsIt != anAllSubs.end(); aSubsIt++) {
193             ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aSubsIt);
194             if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aSubShape)) {
195               aSubShapesToKeepAttrList->append(aSub, aSubShape);
196               break;
197             }
198           }
199         }
200       }
201     }
202   }
203
204   myChangedInCode = false;
205 }
206
207 //==================================================================================================
208 void FeaturesPlugin_RemoveSubShapes::execute()
209 {
210   // Get base shape and sub-shapes list.
211   AttributeSelectionPtr aShapeAttrSelection = selection(BASE_SHAPE_ID());
212   AttributeSelectionListPtr aSubShapesAttrList = selectionList(SUBSHAPES_TO_KEEP_ID());
213   if(!aShapeAttrSelection.get() || !aSubShapesAttrList.get()) {
214     return;
215   }
216
217   // Get base shape.
218   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
219
220   GeomShapePtr aResultShape;
221   int aSubsNb = aSubShapesAttrList->size();
222   if(aSubsNb > 1) {
223     if(!aBaseShape.get()) {
224       return;
225     }
226     aResultShape = aBaseShape->emptyCopied();
227
228     // Copy sub-shapes from list to new shape.
229     for(int anIndex = 0; anIndex < aSubsNb; ++anIndex) {
230       AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
231       GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
232       GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
233     }
234   } else if(aSubsNb == 1) {
235     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(0);
236     aResultShape = anAttrSelectionInList->value();
237   }
238   // deleted and copied must be jointed to one list which keeps all the history
239   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
240
241   // find all removed shapes
242   std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aDeletedSubs(new GeomAlgoAPI_MakeShapeCustom);
243   std::set<GeomAPI_Shape::ShapeType> aTypes; // types that where removed
244   aTypes.insert(GeomAPI_Shape::FACE);
245
246   std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
247   for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt) {
248     GeomShapePtr aSubShape = *anIt;
249     if (!aSubShape.get() || aSubShape->isNull())
250       continue;
251
252     int anIndex;
253     for(anIndex = 0; anIndex < aSubsNb; ++anIndex) {
254       AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
255       GeomShapePtr aLeftShape = anAttrSelectionInList->value();
256       if (aSubShape->isEqual(aLeftShape)) {
257         break; // found in a left-list
258       }
259     }
260     if (anIndex == aSubsNb) { // not found in left
261       aDeletedSubs->addDeleted(aSubShape);
262       aTypes.insert(aSubShape->shapeType());
263       if (aSubShape->shapeType() != GeomAPI_Shape::FACE) {
264         GeomAPI_ShapeExplorer aFaces(aSubShape, GeomAPI_Shape::FACE);
265         for(; aFaces.more(); aFaces.next())
266           aDeletedSubs->addDeleted(aFaces.current());
267       }
268     }
269   }
270   aMakeShapeList->appendAlgo(aDeletedSubs);
271
272   std::shared_ptr<GeomAlgoAPI_Copy> aCopy(new GeomAlgoAPI_Copy(aResultShape));
273   aResultShape = aCopy->shape();
274   aMakeShapeList->appendAlgo(aCopy);
275
276   if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
277     aResultShape = GeomAlgoAPI_ShapeTools::groupSharedTopology(aResultShape);
278     if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
279       // if the result has only one sub-shape, discard the compound
280       GeomAPI_ShapeIterator aSubIt(aResultShape);
281       GeomShapePtr aSub = aSubIt.current();
282       aSubIt.next();
283       if (!aSubIt.more())
284         aResultShape = aSub;
285     }
286   }
287
288   // Store result.
289   ResultBodyPtr aResultBody = document()->createBody(data());
290   aResultBody->storeModified(aBaseShape, aResultShape);
291   for (std::set<GeomAPI_Shape::ShapeType>::iterator aTypeIter = aTypes.begin();
292        aTypeIter != aTypes.end();
293        ++aTypeIter)
294   {
295     aResultBody->loadDeletedShapes(aMakeShapeList, aBaseShape, *aTypeIter);
296   }
297
298   aResultBody->loadModifiedShapes(aMakeShapeList,
299                                   aBaseShape,
300                                   GeomAPI_Shape::FACE);
301   aResultBody->loadModifiedShapes(aMakeShapeList,
302                                   aBaseShape,
303                                   GeomAPI_Shape::EDGE);
304   aResultBody->loadModifiedShapes(aMakeShapeList,
305                                   aBaseShape,
306                                   GeomAPI_Shape::VERTEX);
307   setResult(aResultBody);
308 }