]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Partition.cpp
Salome HOME
Make "Macro" menu be the last, not just after the Sketch.
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Partition.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_Partition.h"
21
22 #include <ModelAPI_AttributeBoolean.h>
23 #include <ModelAPI_AttributeInteger.h>
24 #include <ModelAPI_AttributeReference.h>
25 #include <ModelAPI_AttributeSelectionList.h>
26 #include <ModelAPI_BodyBuilder.h>
27 #include <ModelAPI_Data.h>
28 #include <ModelAPI_Document.h>
29 #include <ModelAPI_ResultBody.h>
30 #include <ModelAPI_Session.h>
31 #include <ModelAPI_Tools.h>
32 #include <ModelAPI_Validator.h>
33
34 #include <GeomAlgoAPI_Boolean.h>
35 #include <GeomAlgoAPI_CompoundBuilder.h>
36 #include <GeomAlgoAPI_MakeShapeCustom.h>
37 #include <GeomAlgoAPI_MakeShapeList.h>
38 #include <GeomAlgoAPI_Partition.h>
39 #include <GeomAlgoAPI_ShapeTools.h>
40 #include <GeomAlgoAPI_Tools.h>
41
42 #include <GeomAPI_Face.h>
43 #include <GeomAPI_ShapeExplorer.h>
44 #include <GeomAPI_ShapeIterator.h>
45
46 #include <iostream>
47 #include <list>
48 #include <sstream>
49
50 typedef std::list<std::pair<GeomShapePtr, ListOfShape> > CompsolidSubs;
51
52 static GeomShapePtr findBase(const GeomShapePtr theObjectShape,
53                              const GeomShapePtr theResultShape,
54                              const GeomAPI_Shape::ShapeType theShapeType,
55                              const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape);
56
57 static void pullObjectsAndPlanes(const AttributeSelectionListPtr& theSelectedList,
58                                  CompsolidSubs& theObjects, ListOfShape& thePlanes);
59
60 static void resizePlanes(const CompsolidSubs& theObjects, ListOfShape& thePlanes,
61                          std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList);
62
63 static void unusedSubsOfComposolid(const CompsolidSubs& theObjects, CompsolidSubs& theNotUsed);
64
65 static bool cutUnusedSubs(CompsolidSubs& theObjects, CompsolidSubs& theNotUsed,
66                           std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
67                           std::string& theError);
68
69
70 //=================================================================================================
71 FeaturesPlugin_Partition::FeaturesPlugin_Partition()
72 {
73 }
74
75 //=================================================================================================
76 void FeaturesPlugin_Partition::initAttributes()
77 {
78   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
79 }
80
81 //=================================================================================================
82 void FeaturesPlugin_Partition::execute()
83 {
84   CompsolidSubs anObjects;
85   ListOfShape aPlanes;
86
87   // Getting objects.
88   pullObjectsAndPlanes(selectionList(BASE_OBJECTS_ID()), anObjects, aPlanes);
89   if(anObjects.empty()) {
90     static const std::string aFeatureError = "Error: No objects for partition.";
91     setError(aFeatureError);
92     return;
93   }
94
95   ListOfShape aBaseObjects;
96   for (CompsolidSubs::iterator anIt = anObjects.begin(); anIt != anObjects.end(); ++anIt)
97     aBaseObjects.insert(aBaseObjects.end(), anIt->second.begin(), anIt->second.end());
98   aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end());
99
100   // resize planes to the bounding box of operated shapes
101   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
102   resizePlanes(anObjects, aPlanes, aMakeShapeList);
103
104   // cut unused solids of composolids from the objects of partition
105   CompsolidSubs anUnusedSubs;
106   unusedSubsOfComposolid(anObjects, anUnusedSubs);
107   for (CompsolidSubs::iterator anIt = anUnusedSubs.begin(); anIt != anUnusedSubs.end(); ++anIt)
108     aBaseObjects.insert(aBaseObjects.end(), anIt->second.begin(), anIt->second.end());
109
110   std::string aError;
111   if (!cutUnusedSubs(anObjects, anUnusedSubs, aMakeShapeList, aError)) {
112     setError(aError);
113     return;
114   }
115
116   // perform partition first time to split target solids
117   ListOfShape aTargetObjects;
118   for (CompsolidSubs::iterator anIt = anObjects.begin(); anIt != anObjects.end(); ++anIt)
119     aTargetObjects.insert(aTargetObjects.end(), anIt->second.begin(), anIt->second.end());
120
121   std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
122     new GeomAlgoAPI_Partition(aTargetObjects, aPlanes));
123
124   // Checking that the algorithm worked properly.
125   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
126     setError(aError);
127     return;
128   }
129
130   aMakeShapeList->appendAlgo(aPartitionAlgo);
131   GeomShapePtr aResultShape = aPartitionAlgo->shape();
132
133   if (!anUnusedSubs.empty()) {
134     // second pass of a partition to split shared faces of compsolids
135     aTargetObjects.clear();
136     aTargetObjects.push_back(aResultShape);
137     for (CompsolidSubs::iterator anIt = anUnusedSubs.begin(); anIt != anUnusedSubs.end(); ++anIt)
138       aTargetObjects.insert(aTargetObjects.end(), anIt->second.begin(), anIt->second.end());
139
140     aPartitionAlgo.reset(new GeomAlgoAPI_Partition(aTargetObjects, ListOfShape()));
141
142     // Checking that the algorithm worked properly.
143     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
144       setError(aError);
145       return;
146     }
147
148     aMakeShapeList->appendAlgo(aPartitionAlgo);
149     aResultShape = aPartitionAlgo->shape();
150   }
151
152   int aResultIndex = 0;
153   if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
154     for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
155       storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
156       ++aResultIndex;
157     }
158   } else {
159     storeResult(aBaseObjects, aPlanes, aResultShape, aMakeShapeList, aResultIndex);
160     ++aResultIndex;
161   }
162
163   // Remove the rest results if there were produced in the previous pass.
164   removeResults(aResultIndex);
165 }
166
167 //=================================================================================================
168 void FeaturesPlugin_Partition::storeResult(
169   ListOfShape& theObjects, ListOfShape& thePlanes,
170   const GeomShapePtr theResultShape,
171   const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
172   const int theIndex)
173 {
174   // Find base. The most complicated is the real modified object (#1799 if box is partitioned by
175   // two planes the box is the base, not planes, independently on the order in the list).
176   GeomShapePtr aBaseShape;
177   for(ListOfShape::const_iterator anIt = theObjects.cbegin(); anIt != theObjects.cend(); ++anIt) {
178     GeomShapePtr anObjectShape = *anIt;
179     GeomShapePtr aCandidate =
180       findBase(anObjectShape, theResultShape, GeomAPI_Shape::VERTEX, theMakeShape);
181     if(!aCandidate.get()) {
182       aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::EDGE, theMakeShape);
183     }
184     if (!aCandidate.get())
185       aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::FACE, theMakeShape);
186
187     if(aCandidate.get()) {
188       if (!aBaseShape.get() || aBaseShape->shapeType() > aCandidate->shapeType()) {
189         aBaseShape = aCandidate;
190       }
191     }
192   }
193
194   // Create result body.
195   ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
196
197   // Store modified shape.
198   if(!aBaseShape.get() || aBaseShape->isEqual(theResultShape)) {
199     aResultBody->store(theResultShape, false);
200     setResult(aResultBody, theIndex);
201     return;
202   }
203
204   aResultBody->storeModified(aBaseShape, theResultShape);
205
206   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
207   theObjects.insert(theObjects.end(), thePlanes.begin(), thePlanes.end());
208   for (ListOfShape::const_iterator anIt = theObjects.cbegin();
209        anIt != theObjects.cend();
210        ++anIt)
211   {
212     GeomShapePtr aShape = *anIt;
213     aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::EDGE);
214     aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
215     aResultBody->loadDeletedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
216   }
217
218   setResult(aResultBody, theIndex);
219 }
220
221
222 //=================     Auxiliary functions     ===================================================
223
224 GeomShapePtr findBase(const GeomShapePtr theObjectShape,
225                       const GeomShapePtr theResultShape,
226                       const GeomAPI_Shape::ShapeType theShapeType,
227                       const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
228 {
229   GeomShapePtr aBaseShape;
230   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
231   for(GeomAPI_ShapeExplorer anObjectSubShapesExp(theObjectShape, theShapeType);
232       anObjectSubShapesExp.more();
233       anObjectSubShapesExp.next()) {
234     GeomShapePtr anObjectSubShape = anObjectSubShapesExp.current();
235     ListOfShape aModifiedShapes;
236     theMakeShape->modified(anObjectSubShape, aModifiedShapes);
237     for(ListOfShape::const_iterator
238         aModIt = aModifiedShapes.cbegin(); aModIt != aModifiedShapes.cend(); ++aModIt) {
239       GeomShapePtr aModShape = *aModIt;
240       if(aMapOfSubShapes->isBound(aModShape)) {
241         aModShape = aMapOfSubShapes->find(aModShape);
242       }
243       if(theResultShape->isSubShape(aModShape)) {
244         aBaseShape = theObjectShape;
245         break;
246       }
247     }
248     if(aBaseShape.get()) {
249       break;
250     }
251   }
252
253   return aBaseShape;
254 }
255
256 static CompsolidSubs::iterator findOrAdd(CompsolidSubs& theList, const GeomShapePtr& theCompsolid)
257 {
258   CompsolidSubs::iterator aFound = theList.begin();
259   for (; aFound != theList.end(); ++aFound)
260     if (aFound->first == theCompsolid)
261       break;
262   if (aFound == theList.end()) {
263     theList.push_back(std::pair<GeomShapePtr, ListOfShape>(theCompsolid, ListOfShape()));
264     aFound = --theList.end();
265   }
266   return aFound;
267 }
268
269 void pullObjectsAndPlanes(const AttributeSelectionListPtr& theSelectedList,
270                           CompsolidSubs& theObjects, ListOfShape& thePlanes)
271 {
272   std::map<ResultBodyPtr, GeomShapePtr> aMapCompsolidShape;
273
274   int aSize = theSelectedList->size();
275   for (int anIndex = 0; anIndex < aSize; ++anIndex) {
276     AttributeSelectionPtr anObjectAttr = theSelectedList->value(anIndex);
277     ResultPtr aContext = anObjectAttr->context();
278     GeomShapePtr anObject = anObjectAttr->value();
279     if (anObject) {
280       GeomShapePtr anOwnerShape = anObject;
281       // check the result is a compsolid and store all used subs in a single list
282       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
283       if (aResCompSolidPtr && aResCompSolidPtr->shape()->shapeType() == GeomAPI_Shape::COMPSOLID) {
284         std::map<ResultBodyPtr, GeomShapePtr>::const_iterator
285             aFound = aMapCompsolidShape.find(aResCompSolidPtr);
286         if (aFound != aMapCompsolidShape.end())
287           anOwnerShape = aFound->second;
288         else {
289           anOwnerShape = aResCompSolidPtr->shape();
290           aMapCompsolidShape[aResCompSolidPtr] = anOwnerShape;
291         }
292       }
293
294       CompsolidSubs::iterator aFound = findOrAdd(theObjects, anOwnerShape);
295       aFound->second.push_back(anObject);
296     }
297     else {
298       // It could be a construction plane.
299       thePlanes.push_back(anObjectAttr->context()->shape());
300     }
301   }
302 }
303
304 void resizePlanes(const CompsolidSubs& theObjects, ListOfShape& thePlanes,
305                   std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList)
306 {
307   ListOfShape aSolidsInOperation;
308   for (CompsolidSubs::const_iterator anIt = theObjects.begin(); anIt != theObjects.end(); ++anIt)
309     aSolidsInOperation.insert(aSolidsInOperation.end(), anIt->second.begin(), anIt->second.end());
310
311   std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
312       GeomAlgoAPI_ShapeTools::getBoundingBox(aSolidsInOperation, 1.0);
313
314   ListOfShape aPlanesCopy = thePlanes;
315   thePlanes.clear();
316
317   // Resize planes to fit in bounding box
318   for (ListOfShape::const_iterator anIt = aPlanesCopy.begin(); anIt != aPlanesCopy.end(); ++anIt) {
319     GeomShapePtr aPlane = *anIt;
320     GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
321     std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(new GeomAlgoAPI_MakeShapeCustom);
322     aMkShCustom->addModified(aPlane, aTool);
323     theMakeShapeList->appendAlgo(aMkShCustom);
324     thePlanes.push_back(aTool);
325   }
326 }
327
328 void unusedSubsOfComposolid(const CompsolidSubs& theObjects, CompsolidSubs& theNotUsed)
329 {
330   for (CompsolidSubs::const_iterator aCSIt = theObjects.begin();
331        aCSIt != theObjects.end(); ++aCSIt) {
332     if (aCSIt->first->shapeType() != GeomAPI_Shape::COMPSOLID)
333       continue;
334
335     // check the compsolid is selected
336     if (aCSIt->second.size() == 1 && aCSIt->first->isEqual(aCSIt->second.front()))
337       continue;
338
339     // process all sub-solids of compsolid
340     ListOfShape aNotUsedSolids;
341     for (GeomAPI_ShapeExplorer anExp(aCSIt->first, GeomAPI_Shape::SOLID);
342          anExp.more(); anExp.next()) {
343       GeomShapePtr aSolidInCompSolid = anExp.current();
344       ListOfShape::const_iterator anIt = aCSIt->second.begin();
345       for (; anIt != aCSIt->second.end(); ++anIt)
346         if (aSolidInCompSolid->isEqual(*anIt))
347           break;
348
349       if (anIt == aCSIt->second.end())
350         aNotUsedSolids.push_back(aSolidInCompSolid);
351     }
352
353     if (!aNotUsedSolids.empty())
354       theNotUsed.push_back(std::pair<GeomShapePtr, ListOfShape>(aCSIt->first, aNotUsedSolids));
355   }
356 }
357
358 static bool cutSubs(const GeomShapePtr& theFirstArgument,
359                     CompsolidSubs& theSubsToCut,
360                     const ListOfShape& theTools,
361                     std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
362                     std::string& theError)
363 {
364   if (theTools.empty())
365     return true;
366
367   std::shared_ptr<GeomAlgoAPI_MakeShape> aCutAlgo;
368
369   for (CompsolidSubs::iterator aUIt= theSubsToCut.begin(); aUIt != theSubsToCut.end(); ++aUIt) {
370     if (aUIt->first == theFirstArgument)
371       continue; // no need to split unused subs of the first compsolid
372
373     // cut from current list of solids
374     aCutAlgo.reset(
375         new GeomAlgoAPI_Boolean(aUIt->second, theTools, GeomAlgoAPI_Boolean::BOOL_CUT));
376     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, "", theError))
377       return false;
378     theMakeShapeList->appendAlgo(aCutAlgo);
379
380     // update list of un-selected objects of the partition
381     GeomAPI_Shape::ShapeType aType = aUIt->second.front()->shapeType();
382     aUIt->second.clear();
383     for (GeomAPI_ShapeExplorer anExp(aCutAlgo->shape(), aType); anExp.more(); anExp.next())
384       aUIt->second.push_back(anExp.current());
385   }
386   return true;
387 }
388
389 bool cutUnusedSubs(CompsolidSubs& theObjects, CompsolidSubs& theNotUsed,
390                    std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
391                    std::string& theError)
392 {
393   GeomShapePtr aFirstArgument = theObjects.front().first;
394
395   // compose a set of tools for the CUT operation:
396   // find the list of unused subs of the first argument or use itself
397   ListOfShape aToolsForUsed;
398   CompsolidSubs::iterator aUIt = theNotUsed.begin();
399   for (; aUIt != theNotUsed.end(); ++aUIt)
400     if (aUIt->first == aFirstArgument) {
401       aToolsForUsed.insert(aToolsForUsed.end(), aUIt->second.begin(), aUIt->second.end());
402       break;
403     }
404   ListOfShape aToolsForUnused;
405   aToolsForUnused.push_back(aFirstArgument);
406
407   // cut subs
408   return cutSubs(aFirstArgument, theObjects, aToolsForUsed, theMakeShapeList, theError)
409       && cutSubs(aFirstArgument, theNotUsed, aToolsForUnused, theMakeShapeList, theError);
410 }