Salome HOME
updated copyright message
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_RemoveSubShapes.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
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       ListOfShape::const_iterator anIt = aSubShapes.cbegin();
104       for (; anIt != aSubShapes.cend(); ++anIt)
105       {
106         GeomShapePtr aSubShape = *anIt;
107         if(!isHasSubs) {
108           aSubShapesToKeepAttrList->append(aContext, aSubShape);
109         } else {
110           std::list<ResultPtr>::iterator aSubsIt = anAllSubs.begin();
111           for(; aSubsIt != anAllSubs.end(); aSubsIt++) {
112             ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aSubsIt);
113             if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aSubShape)) {
114               aSubShapesToKeepAttrList->append(aSub, aSubShape);
115               break;
116             }
117           }
118         }
119       }
120     }
121     else if (theID == SUBSHAPES_TO_KEEP_ID())
122     {
123       aSubShapesToRemoveAttrList->clear();
124
125       if (!aBaseShape.get()) {
126         return;
127       }
128
129       int anIndex;
130       // optimization: collect selection attribute values into a map
131       const int aSubsToKeepNb = aSubShapesToKeepAttrList->size();
132       GeomAPI_DataMapOfShapeShape aSubShapesToKeep;
133       for(anIndex = 0; anIndex < aSubsToKeepNb; ++anIndex) {
134         AttributeSelectionPtr anAttrSelectionInList = aSubShapesToKeepAttrList->value(anIndex);
135         GeomShapePtr aSubShapeToKeep = anAttrSelectionInList->value();
136         if (aSubShapeToKeep.get())
137           aSubShapesToKeep.bind(aSubShapeToKeep, aSubShapeToKeep);
138       }
139
140       std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
141       ListOfShape::const_iterator anIt = aSubShapes.cbegin();
142       for (; anIt != aSubShapes.cend(); ++anIt)
143       {
144         GeomShapePtr aSubShape = *anIt;
145         if (aSubShapesToKeep.isBound(aSubShape))
146           continue;
147
148         if(!isHasSubs) {
149           aSubShapesToRemoveAttrList->append(aContext, aSubShape);
150         }
151         else {
152           std::list<ResultPtr>::iterator aSubsIt = anAllSubs.begin();
153           for (; aSubsIt != anAllSubs.end(); aSubsIt++) {
154             ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aSubsIt);
155             if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aSubShape)) {
156               aSubShapesToRemoveAttrList->append(aSub, aSubShape);
157               break;
158             }
159           }
160         }
161       }
162     }
163     else if (theID == SUBSHAPES_TO_REMOVE_ID())
164     {
165       aSubShapesToKeepAttrList->clear();
166
167       if (!aBaseShape.get()) {
168         return;
169       }
170
171       int anIndex;
172       const int aSubsToRemoveNb = aSubShapesToRemoveAttrList->size();
173       GeomAPI_DataMapOfShapeShape aSubShapesToRemove;
174       for(anIndex = 0; anIndex < aSubsToRemoveNb; ++anIndex) {
175         AttributeSelectionPtr anAttrSelectionInList = aSubShapesToRemoveAttrList->value(anIndex);
176         GeomShapePtr aSubShapeToRemove = anAttrSelectionInList->value();
177         if (aSubShapeToRemove.get())
178           aSubShapesToRemove.bind(aSubShapeToRemove, aSubShapeToRemove);
179       }
180
181
182       std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
183       ListOfShape::const_iterator anIt = aSubShapes.cbegin();
184       for (; anIt != aSubShapes.cend(); ++anIt)
185       {
186         GeomShapePtr aSubShape = *anIt;
187         if (aSubShapesToRemove.isBound(aSubShape))
188           continue;
189
190         if (!isHasSubs) {
191           aSubShapesToKeepAttrList->append(aContext, aSubShape);
192         }
193         else {
194           std::list<ResultPtr>::iterator aSubsIt = anAllSubs.begin();
195           for (; aSubsIt != anAllSubs.end(); aSubsIt++) {
196             ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aSubsIt);
197             if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aSubShape)) {
198               aSubShapesToKeepAttrList->append(aSub, aSubShape);
199               break;
200             }
201           }
202         }
203       }
204     }
205   }
206
207   myChangedInCode = false;
208 }
209
210 //==================================================================================================
211 void FeaturesPlugin_RemoveSubShapes::execute()
212 {
213   // Get base shape and sub-shapes list.
214   AttributeSelectionPtr aShapeAttrSelection = selection(BASE_SHAPE_ID());
215   AttributeSelectionListPtr aSubShapesAttrList = selectionList(SUBSHAPES_TO_KEEP_ID());
216   if(!aShapeAttrSelection.get() || !aSubShapesAttrList.get()) {
217     return;
218   }
219
220   // Get base shape.
221   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
222
223   GeomShapePtr aResultShape;
224   int aSubsNb = aSubShapesAttrList->size();
225   if(aSubsNb > 1) {
226     if(!aBaseShape.get()) {
227       return;
228     }
229     aResultShape = aBaseShape->emptyCopied();
230
231     // Copy sub-shapes from list to new shape.
232     for(int anIndex = 0; anIndex < aSubsNb; ++anIndex) {
233       AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
234       GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
235       GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
236     }
237   } else if(aSubsNb == 1) {
238     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(0);
239     aResultShape = anAttrSelectionInList->value();
240   }
241   // deleted and copied must be jointed to one list which keeps all the history
242   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
243
244   // find all removed shapes
245   std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aDeletedSubs(new GeomAlgoAPI_MakeShapeCustom);
246   std::set<GeomAPI_Shape::ShapeType> aTypes; // types that where removed
247   aTypes.insert(GeomAPI_Shape::FACE);
248
249   std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
250   for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt) {
251     GeomShapePtr aSubShape = *anIt;
252     if (!aSubShape.get() || aSubShape->isNull())
253       continue;
254
255     int anIndex;
256     for(anIndex = 0; anIndex < aSubsNb; ++anIndex) {
257       AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
258       GeomShapePtr aLeftShape = anAttrSelectionInList->value();
259       if (aSubShape->isEqual(aLeftShape)) {
260         break; // found in a left-list
261       }
262     }
263     if (anIndex == aSubsNb) { // not found in left
264       aDeletedSubs->addDeleted(aSubShape);
265       aTypes.insert(aSubShape->shapeType());
266       if (aSubShape->shapeType() != GeomAPI_Shape::FACE) {
267         GeomAPI_ShapeExplorer aFaces(aSubShape, GeomAPI_Shape::FACE);
268         for(; aFaces.more(); aFaces.next())
269           aDeletedSubs->addDeleted(aFaces.current());
270       }
271     }
272   }
273   aMakeShapeList->appendAlgo(aDeletedSubs);
274
275   std::shared_ptr<GeomAlgoAPI_Copy> aCopy(new GeomAlgoAPI_Copy(aResultShape));
276   aResultShape = aCopy->shape();
277   aMakeShapeList->appendAlgo(aCopy);
278
279   if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
280     aResultShape = GeomAlgoAPI_ShapeTools::groupSharedTopology(aResultShape);
281     if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
282       // if the result has only one sub-shape, discard the compound
283       GeomAPI_ShapeIterator aSubIt(aResultShape);
284       GeomShapePtr aSub = aSubIt.current();
285       aSubIt.next();
286       if (!aSubIt.more())
287         aResultShape = aSub;
288     }
289   }
290
291   // Store result.
292   ResultBodyPtr aResultBody = document()->createBody(data());
293   std::list<GeomShapePtr> anOldShapes;
294   anOldShapes.push_back(aBaseShape);
295   aResultBody->storeModified(anOldShapes, aResultShape, aMakeShapeList);
296   for (std::set<GeomAPI_Shape::ShapeType>::iterator aTypeIter = aTypes.begin();
297        aTypeIter != aTypes.end();
298        ++aTypeIter)
299   {
300     aResultBody->loadDeletedShapes(aMakeShapeList, aBaseShape, *aTypeIter);
301   }
302
303   aResultBody->loadModifiedShapes(aMakeShapeList,
304                                   aBaseShape,
305                                   GeomAPI_Shape::FACE);
306   aResultBody->loadModifiedShapes(aMakeShapeList,
307                                   aBaseShape,
308                                   GeomAPI_Shape::EDGE);
309   aResultBody->loadModifiedShapes(aMakeShapeList,
310                                   aBaseShape,
311                                   GeomAPI_Shape::VERTEX);
312   setResult(aResultBody);
313 }