Salome HOME
69fd8deaae1795298ca9de48a4875c0e0e372ed0
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Partition.cpp
1 // Copyright (C) 2014-2021  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_ShapeBuilder.h>
40 #include <GeomAlgoAPI_ShapeTools.h>
41 #include <GeomAlgoAPI_Tools.h>
42
43 #include <GeomAPI_Face.h>
44 #include <GeomAPI_ShapeExplorer.h>
45 #include <GeomAPI_ShapeIterator.h>
46
47 #include <iostream>
48 #include <list>
49 #include <sstream>
50
51
52 //=================================================================================================
53 FeaturesPlugin_Partition::FeaturesPlugin_Partition()
54 {
55 }
56
57 //=================================================================================================
58 void FeaturesPlugin_Partition::initAttributes()
59 {
60   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
61   initVersion(BOP_VERSION_9_4(), selectionList(BASE_OBJECTS_ID()));
62 }
63
64 //=================================================================================================
65 void FeaturesPlugin_Partition::execute()
66 {
67   GeomAPI_ShapeHierarchy anObjects;
68   ListOfShape aPlanes;
69
70   // Getting objects.
71   processAttribute(BASE_OBJECTS_ID(), anObjects, aPlanes);
72   if(anObjects.empty()) {
73     static const std::string aFeatureError = "Error: No objects for partition.";
74     setError(aFeatureError);
75     return;
76   }
77
78   ListOfShape aBaseObjects = anObjects.objects();
79   aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end());
80
81   // resize planes to the bounding box of operated shapes
82   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
83   resizePlanes(anObjects.objects(), aPlanes, aMakeShapeList);
84
85   // cut unused solids of composolids from the objects of partition
86   ListOfShape aTargetObjects, anUnusedSubs;
87   std::string aError;
88   if (!cutSubs(anObjects, aTargetObjects, anUnusedSubs, aMakeShapeList, aError)) {
89     setError(aError);
90     return;
91   }
92   aBaseObjects.insert(aBaseObjects.end(), anUnusedSubs.begin(), anUnusedSubs.end());
93
94   // perform partition first time to split target solids by planes
95   std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
96       new GeomAlgoAPI_Partition(aTargetObjects, aPlanes));
97
98   // Checking that the algorithm worked properly.
99   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
100     setError(aError);
101     return;
102   }
103
104   aMakeShapeList->appendAlgo(aPartitionAlgo);
105   GeomShapePtr aResultShape = aPartitionAlgo->shape();
106
107   if (!anUnusedSubs.empty()) {
108     // second pass of a partition to split shared faces of compsolids
109     aTargetObjects.clear();
110     aTargetObjects.push_back(aResultShape);
111     aTargetObjects.insert(aTargetObjects.end(), anUnusedSubs.begin(), anUnusedSubs.end());
112
113     aPartitionAlgo.reset(new GeomAlgoAPI_Partition(aTargetObjects, ListOfShape()));
114
115     // Checking that the algorithm worked properly.
116     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
117       setError(aError);
118       return;
119     }
120
121     aMakeShapeList->appendAlgo(aPartitionAlgo);
122     aResultShape = aPartitionAlgo->shape();
123   }
124
125   int aResultIndex = 0;
126
127   if (data()->version().empty()) {
128     // default behaviors of Partition
129     if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
130       for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
131         storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
132         ++aResultIndex;
133       }
134     } else {
135       storeResult(aBaseObjects, aPlanes, aResultShape, aMakeShapeList, aResultIndex);
136       ++aResultIndex;
137     }
138   }
139   else {
140     // merge hierarchies of compounds containing objects and tools
141     GeomShapePtr aFirstShape = aResultShape;
142     GeomAPI_ShapeIterator anIt;
143     if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
144       anIt = GeomAPI_ShapeIterator(aResultShape);
145       aFirstShape = anIt.current();
146       anIt.next();
147     }
148
149     GeomShapePtr aResultCompound =
150       keepUnusedSubsOfCompound(aFirstShape, anObjects, GeomAPI_ShapeHierarchy(), aMakeShapeList);
151
152     if (anIt.more()) {
153       if (aResultCompound->shapeType() != GeomAPI_Shape::COMPOUND) {
154         // put the shape into compound
155         ListOfShape aShapes;
156         aShapes.push_back(aResultCompound);
157         aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
158       }
159       std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
160       for (; anIt.more(); anIt.next())
161         aBuilder->add(aResultCompound, anIt.current());
162       aMakeShapeList->appendAlgo(aBuilder);
163     }
164
165     storeResult(aBaseObjects, aPlanes, aResultCompound, aMakeShapeList, aResultIndex);
166     ++aResultIndex;
167   }
168
169   // Remove the rest results if there were produced in the previous pass.
170   removeResults(aResultIndex);
171 }
172
173 //=================================================================================================
174 void FeaturesPlugin_Partition::storeResult(
175   ListOfShape& theObjects, ListOfShape& thePlanes,
176   const GeomShapePtr theResultShape,
177   const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
178   const int theIndex)
179 {
180   // Create result body.
181   ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
182
183   // if result is same as one of the base object, no modification was performed
184   for(ListOfShape::const_iterator anObj = theObjects.cbegin(); anObj != theObjects.cend(); ++anObj)
185   {
186     if (anObj->get() && (*anObj)->isSame(theResultShape)) {
187       aResultBody->store(theResultShape, false);
188       setResult(aResultBody, theIndex);
189       return;
190     }
191   }
192
193   aResultBody->storeModified(theObjects, theResultShape, theMakeShape);
194
195   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
196   theObjects.insert(theObjects.end(), thePlanes.begin(), thePlanes.end());
197   for (ListOfShape::const_iterator anIt = theObjects.cbegin();
198        anIt != theObjects.cend();
199        ++anIt)
200   {
201     GeomShapePtr aShape = *anIt;
202     aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::EDGE);
203     aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
204     aResultBody->loadDeletedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
205   }
206
207   setResult(aResultBody, theIndex);
208 }
209
210
211 //=================================================================================================
212
213 static bool cutSubs(ListOfShape& theSubsToCut,
214                     const ListOfShape& theTools,
215                     std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
216                     std::string& theError)
217 {
218   if (theSubsToCut.empty() || theTools.empty())
219     return true;
220
221   // cut from current list of solids
222   std::shared_ptr<GeomAlgoAPI_MakeShape> aCutAlgo(
223       new GeomAlgoAPI_Boolean(theSubsToCut, theTools, GeomAlgoAPI_Tools::BOOL_CUT));
224   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, "", theError))
225     return false;
226   theMakeShapeList->appendAlgo(aCutAlgo);
227
228   // update list of un-selected objects of the partition
229   GeomAPI_Shape::ShapeType aType = theSubsToCut.front()->shapeType();
230   theSubsToCut.clear();
231   for (GeomAPI_ShapeExplorer anExp(aCutAlgo->shape(), aType); anExp.more(); anExp.next())
232     theSubsToCut.push_back(anExp.current());
233   return true;
234 }
235
236 bool FeaturesPlugin_Partition::cutSubs(
237     GeomAPI_ShapeHierarchy& theHierarchy,
238     ListOfShape& theUsed,
239     ListOfShape& theNotUsed,
240     std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
241     std::string& theError)
242 {
243   theUsed.clear();
244   theNotUsed.clear();
245
246   GeomAPI_ShapeHierarchy::iterator anIt = theHierarchy.begin();
247
248   // compose a set of tools for the CUT operation:
249   // find the list of unused subs of the first argument or use itself
250   ListOfShape aToolsForUsed, aToolsForUnused;
251   GeomShapePtr aFirstArgument = theHierarchy.parent(*anIt, false);
252   if (aFirstArgument && aFirstArgument->shapeType() == GeomAPI_Shape::COMPSOLID) {
253     theHierarchy.splitCompound(aFirstArgument, theUsed, aToolsForUsed);
254     theNotUsed = aToolsForUsed;
255   }
256   else {
257     aFirstArgument = *anIt;
258     theUsed.push_back(aFirstArgument);
259   }
260   aToolsForUnused.push_back(aFirstArgument);
261
262   // cut subs
263   bool isOk = true;
264   for (++anIt; anIt != theHierarchy.end() && isOk; ++anIt) {
265     ListOfShape aUsed, aNotUsed;
266
267     GeomShapePtr aParent = theHierarchy.parent(*anIt, false);
268     if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) {
269       aParent = theHierarchy.parent(*anIt); // get parent once again to mark its subs as processed
270       theHierarchy.splitCompound(aParent, aUsed, aNotUsed);
271     }
272     else
273       aUsed.push_back(*anIt);
274
275     isOk = ::cutSubs(aUsed, aToolsForUsed, theMakeShapeList, theError)
276         && ::cutSubs(aNotUsed, aToolsForUnused, theMakeShapeList, theError);
277     if (isOk) {
278       theUsed.insert(theUsed.end(), aUsed.begin(), aUsed.end());
279       theNotUsed.insert(theNotUsed.end(), aNotUsed.begin(), aNotUsed.end());
280     }
281   }
282
283   return isOk;
284 }