1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include "FeaturesPlugin_Partition.h"
23 #include <ModelAPI_AttributeBoolean.h>
24 #include <ModelAPI_AttributeInteger.h>
25 #include <ModelAPI_AttributeReference.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_BodyBuilder.h>
28 #include <ModelAPI_Data.h>
29 #include <ModelAPI_Document.h>
30 #include <ModelAPI_ResultBody.h>
31 #include <ModelAPI_Session.h>
32 #include <ModelAPI_Tools.h>
33 #include <ModelAPI_Validator.h>
35 #include <GeomAlgoAPI_Boolean.h>
36 #include <GeomAlgoAPI_CompoundBuilder.h>
37 #include <GeomAlgoAPI_MakeShapeCustom.h>
38 #include <GeomAlgoAPI_MakeShapeList.h>
39 #include <GeomAlgoAPI_Partition.h>
40 #include <GeomAlgoAPI_ShapeTools.h>
41 #include <GeomAlgoAPI_Tools.h>
43 #include <GeomAPI_Face.h>
44 #include <GeomAPI_ShapeExplorer.h>
45 #include <GeomAPI_ShapeIterator.h>
51 typedef std::list<std::pair<GeomShapePtr, ListOfShape> > CompsolidSubs;
53 static GeomShapePtr findBase(const GeomShapePtr theObjectShape,
54 const GeomShapePtr theResultShape,
55 const GeomAPI_Shape::ShapeType theShapeType,
56 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape);
58 static void pullObjectsAndPlanes(const AttributeSelectionListPtr& theSelectedList,
59 CompsolidSubs& theObjects, ListOfShape& thePlanes);
61 static void resizePlanes(const CompsolidSubs& theObjects, ListOfShape& thePlanes,
62 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList);
64 static void unusedSubsOfComposolid(const CompsolidSubs& theObjects, CompsolidSubs& theNotUsed);
66 static bool cutUnusedSubs(CompsolidSubs& theObjects, CompsolidSubs& theNotUsed,
67 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
68 std::string& theError);
71 //=================================================================================================
72 FeaturesPlugin_Partition::FeaturesPlugin_Partition()
76 //=================================================================================================
77 void FeaturesPlugin_Partition::initAttributes()
79 data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
82 //=================================================================================================
83 void FeaturesPlugin_Partition::execute()
85 CompsolidSubs anObjects;
89 pullObjectsAndPlanes(selectionList(BASE_OBJECTS_ID()), anObjects, aPlanes);
90 if(anObjects.empty()) {
91 static const std::string aFeatureError = "Error: No objects for partition.";
92 setError(aFeatureError);
96 ListOfShape aBaseObjects;
97 for (CompsolidSubs::iterator anIt = anObjects.begin(); anIt != anObjects.end(); ++anIt)
98 aBaseObjects.insert(aBaseObjects.end(), anIt->second.begin(), anIt->second.end());
99 aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end());
101 // resize planes to the bounding box of operated shapes
102 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
103 resizePlanes(anObjects, aPlanes, aMakeShapeList);
105 // cut unused solids of composolids from the objects of partition
106 CompsolidSubs anUnusedSubs;
107 unusedSubsOfComposolid(anObjects, anUnusedSubs);
108 for (CompsolidSubs::iterator anIt = anUnusedSubs.begin(); anIt != anUnusedSubs.end(); ++anIt)
109 aBaseObjects.insert(aBaseObjects.end(), anIt->second.begin(), anIt->second.end());
112 if (!cutUnusedSubs(anObjects, anUnusedSubs, aMakeShapeList, aError)) {
117 // perform partition first time to split target solids
118 ListOfShape aTargetObjects;
119 for (CompsolidSubs::iterator anIt = anObjects.begin(); anIt != anObjects.end(); ++anIt)
120 aTargetObjects.insert(aTargetObjects.end(), anIt->second.begin(), anIt->second.end());
122 std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
123 new GeomAlgoAPI_Partition(aTargetObjects, aPlanes));
125 // Checking that the algorithm worked properly.
126 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
131 aMakeShapeList->appendAlgo(aPartitionAlgo);
132 GeomShapePtr aResultShape = aPartitionAlgo->shape();
134 if (!anUnusedSubs.empty()) {
135 // second pass of a partition to split shared faces of compsolids
136 aTargetObjects.clear();
137 aTargetObjects.push_back(aResultShape);
138 for (CompsolidSubs::iterator anIt = anUnusedSubs.begin(); anIt != anUnusedSubs.end(); ++anIt)
139 aTargetObjects.insert(aTargetObjects.end(), anIt->second.begin(), anIt->second.end());
141 aPartitionAlgo.reset(new GeomAlgoAPI_Partition(aTargetObjects, ListOfShape()));
143 // Checking that the algorithm worked properly.
144 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
149 aMakeShapeList->appendAlgo(aPartitionAlgo);
150 aResultShape = aPartitionAlgo->shape();
153 int aResultIndex = 0;
154 if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
155 for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
156 storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
160 storeResult(aBaseObjects, aPlanes, aResultShape, aMakeShapeList, aResultIndex);
164 // Remove the rest results if there were produced in the previous pass.
165 removeResults(aResultIndex);
168 //=================================================================================================
169 void FeaturesPlugin_Partition::storeResult(
170 ListOfShape& theObjects, ListOfShape& thePlanes,
171 const GeomShapePtr theResultShape,
172 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
175 // Find base. The most complicated is the real modified object (#1799 if box is partitioned by
176 // two planes the box is the base, not planes, independently on the order in the list).
177 GeomShapePtr aBaseShape;
178 for(ListOfShape::const_iterator anIt = theObjects.cbegin(); anIt != theObjects.cend(); ++anIt) {
179 GeomShapePtr anObjectShape = *anIt;
180 GeomShapePtr aCandidate =
181 findBase(anObjectShape, theResultShape, GeomAPI_Shape::VERTEX, theMakeShape);
182 if(!aCandidate.get()) {
183 aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::EDGE, theMakeShape);
185 if (!aCandidate.get())
186 aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::FACE, theMakeShape);
188 if(aCandidate.get()) {
189 if (!aBaseShape.get() || aBaseShape->shapeType() > aCandidate->shapeType()) {
190 aBaseShape = aCandidate;
195 // Create result body.
196 ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
198 // Store modified shape.
199 if(!aBaseShape.get() || aBaseShape->isEqual(theResultShape)) {
200 aResultBody->store(theResultShape, false);
201 setResult(aResultBody, theIndex);
205 aResultBody->storeModified(aBaseShape, theResultShape);
207 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
208 theObjects.insert(theObjects.end(), thePlanes.begin(), thePlanes.end());
209 for (ListOfShape::const_iterator anIt = theObjects.cbegin();
210 anIt != theObjects.cend();
213 GeomShapePtr aShape = *anIt;
214 aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::EDGE);
215 aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
216 aResultBody->loadDeletedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
219 setResult(aResultBody, theIndex);
223 //================= Auxiliary functions ===================================================
225 GeomShapePtr findBase(const GeomShapePtr theObjectShape,
226 const GeomShapePtr theResultShape,
227 const GeomAPI_Shape::ShapeType theShapeType,
228 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
230 GeomShapePtr aBaseShape;
231 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
232 for(GeomAPI_ShapeExplorer anObjectSubShapesExp(theObjectShape, theShapeType);
233 anObjectSubShapesExp.more();
234 anObjectSubShapesExp.next()) {
235 GeomShapePtr anObjectSubShape = anObjectSubShapesExp.current();
236 ListOfShape aModifiedShapes;
237 theMakeShape->modified(anObjectSubShape, aModifiedShapes);
238 for(ListOfShape::const_iterator
239 aModIt = aModifiedShapes.cbegin(); aModIt != aModifiedShapes.cend(); ++aModIt) {
240 GeomShapePtr aModShape = *aModIt;
241 if(aMapOfSubShapes->isBound(aModShape)) {
242 aModShape = aMapOfSubShapes->find(aModShape);
244 if(theResultShape->isSubShape(aModShape)) {
245 aBaseShape = theObjectShape;
249 if(aBaseShape.get()) {
257 static CompsolidSubs::iterator findOrAdd(CompsolidSubs& theList, const GeomShapePtr& theCompsolid)
259 CompsolidSubs::iterator aFound = theList.begin();
260 for (; aFound != theList.end(); ++aFound)
261 if (aFound->first == theCompsolid)
263 if (aFound == theList.end()) {
264 theList.push_back(std::pair<GeomShapePtr, ListOfShape>(theCompsolid, ListOfShape()));
265 aFound = --theList.end();
270 void pullObjectsAndPlanes(const AttributeSelectionListPtr& theSelectedList,
271 CompsolidSubs& theObjects, ListOfShape& thePlanes)
273 std::map<ResultBodyPtr, GeomShapePtr> aMapCompsolidShape;
275 int aSize = theSelectedList->size();
276 for (int anIndex = 0; anIndex < aSize; ++anIndex) {
277 AttributeSelectionPtr anObjectAttr = theSelectedList->value(anIndex);
278 ResultPtr aContext = anObjectAttr->context();
279 GeomShapePtr anObject = anObjectAttr->value();
281 GeomShapePtr anOwnerShape = anObject;
282 // check the result is a compsolid and store all used subs in a single list
283 ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
284 if (aResCompSolidPtr && aResCompSolidPtr->shape()->shapeType() == GeomAPI_Shape::COMPSOLID) {
285 std::map<ResultBodyPtr, GeomShapePtr>::const_iterator
286 aFound = aMapCompsolidShape.find(aResCompSolidPtr);
287 if (aFound != aMapCompsolidShape.end())
288 anOwnerShape = aFound->second;
290 anOwnerShape = aResCompSolidPtr->shape();
291 aMapCompsolidShape[aResCompSolidPtr] = anOwnerShape;
295 CompsolidSubs::iterator aFound = findOrAdd(theObjects, anOwnerShape);
296 aFound->second.push_back(anObject);
299 // It could be a construction plane.
300 thePlanes.push_back(anObjectAttr->context()->shape());
305 void resizePlanes(const CompsolidSubs& theObjects, ListOfShape& thePlanes,
306 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList)
308 ListOfShape aSolidsInOperation;
309 for (CompsolidSubs::const_iterator anIt = theObjects.begin(); anIt != theObjects.end(); ++anIt)
310 aSolidsInOperation.insert(aSolidsInOperation.end(), anIt->second.begin(), anIt->second.end());
312 std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
313 GeomAlgoAPI_ShapeTools::getBoundingBox(aSolidsInOperation, 1.0);
315 ListOfShape aPlanesCopy = thePlanes;
318 // Resize planes to fit in bounding box
319 for (ListOfShape::const_iterator anIt = aPlanesCopy.begin(); anIt != aPlanesCopy.end(); ++anIt) {
320 GeomShapePtr aPlane = *anIt;
321 GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
322 std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(new GeomAlgoAPI_MakeShapeCustom);
323 aMkShCustom->addModified(aPlane, aTool);
324 theMakeShapeList->appendAlgo(aMkShCustom);
325 thePlanes.push_back(aTool);
329 void unusedSubsOfComposolid(const CompsolidSubs& theObjects, CompsolidSubs& theNotUsed)
331 for (CompsolidSubs::const_iterator aCSIt = theObjects.begin();
332 aCSIt != theObjects.end(); ++aCSIt) {
333 if (aCSIt->first->shapeType() != GeomAPI_Shape::COMPSOLID)
336 // check the compsolid is selected
337 if (aCSIt->second.size() == 1 && aCSIt->first->isEqual(aCSIt->second.front()))
340 // process all sub-solids of compsolid
341 ListOfShape aNotUsedSolids;
342 for (GeomAPI_ShapeExplorer anExp(aCSIt->first, GeomAPI_Shape::SOLID);
343 anExp.more(); anExp.next()) {
344 GeomShapePtr aSolidInCompSolid = anExp.current();
345 ListOfShape::const_iterator anIt = aCSIt->second.begin();
346 for (; anIt != aCSIt->second.end(); ++anIt)
347 if (aSolidInCompSolid->isEqual(*anIt))
350 if (anIt == aCSIt->second.end())
351 aNotUsedSolids.push_back(aSolidInCompSolid);
354 if (!aNotUsedSolids.empty())
355 theNotUsed.push_back(std::pair<GeomShapePtr, ListOfShape>(aCSIt->first, aNotUsedSolids));
359 static bool cutSubs(const GeomShapePtr& theFirstArgument,
360 CompsolidSubs& theSubsToCut,
361 const ListOfShape& theTools,
362 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
363 std::string& theError)
365 if (theTools.empty())
368 std::shared_ptr<GeomAlgoAPI_MakeShape> aCutAlgo;
370 for (CompsolidSubs::iterator aUIt= theSubsToCut.begin(); aUIt != theSubsToCut.end(); ++aUIt) {
371 if (aUIt->first == theFirstArgument)
372 continue; // no need to split unused subs of the first compsolid
374 // cut from current list of solids
376 new GeomAlgoAPI_Boolean(aUIt->second, theTools, GeomAlgoAPI_Boolean::BOOL_CUT));
377 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, "", theError))
379 theMakeShapeList->appendAlgo(aCutAlgo);
381 // update list of un-selected objects of the partition
382 GeomAPI_Shape::ShapeType aType = aUIt->second.front()->shapeType();
383 aUIt->second.clear();
384 for (GeomAPI_ShapeExplorer anExp(aCutAlgo->shape(), aType); anExp.more(); anExp.next())
385 aUIt->second.push_back(anExp.current());
390 bool cutUnusedSubs(CompsolidSubs& theObjects, CompsolidSubs& theNotUsed,
391 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
392 std::string& theError)
394 GeomShapePtr aFirstArgument = theObjects.front().first;
396 // compose a set of tools for the CUT operation:
397 // find the list of unused subs of the first argument or use itself
398 ListOfShape aToolsForUsed;
399 CompsolidSubs::iterator aUIt = theNotUsed.begin();
400 for (; aUIt != theNotUsed.end(); ++aUIt)
401 if (aUIt->first == aFirstArgument) {
402 aToolsForUsed.insert(aToolsForUsed.end(), aUIt->second.begin(), aUIt->second.end());
405 ListOfShape aToolsForUnused;
406 aToolsForUnused.push_back(aFirstArgument);
409 return cutSubs(aFirstArgument, theObjects, aToolsForUsed, theMakeShapeList, theError)
410 && cutSubs(aFirstArgument, theNotUsed, aToolsForUnused, theMakeShapeList, theError);