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