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>
42 #include <GeomAPI_Face.h>
43 #include <GeomAPI_ShapeExplorer.h>
44 #include <GeomAPI_ShapeIterator.h>
50 typedef std::list<std::pair<GeomShapePtr, ListOfShape> > CompsolidSubs;
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);
57 static void pullObjectsAndPlanes(const AttributeSelectionListPtr& theSelectedList,
58 CompsolidSubs& theObjects, ListOfShape& thePlanes);
60 static void resizePlanes(const CompsolidSubs& theObjects, ListOfShape& thePlanes,
61 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList);
63 static void unusedSubsOfComposolid(const CompsolidSubs& theObjects, CompsolidSubs& theNotUsed);
65 static bool cutUnusedSubs(CompsolidSubs& theObjects, CompsolidSubs& theNotUsed,
66 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
67 std::string& theError);
69 static bool isAlgoFailed(const std::shared_ptr<GeomAlgoAPI_MakeShape>& theAlgo,
70 std::string& theError);
73 //=================================================================================================
74 FeaturesPlugin_Partition::FeaturesPlugin_Partition()
78 //=================================================================================================
79 void FeaturesPlugin_Partition::initAttributes()
81 data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
84 //=================================================================================================
85 void FeaturesPlugin_Partition::execute()
87 CompsolidSubs anObjects;
91 pullObjectsAndPlanes(selectionList(BASE_OBJECTS_ID()), anObjects, aPlanes);
92 if(anObjects.empty()) {
93 static const std::string aFeatureError = "Error: No objects for partition.";
94 setError(aFeatureError);
98 ListOfShape aBaseObjects;
99 for (CompsolidSubs::iterator anIt = anObjects.begin(); anIt != anObjects.end(); ++anIt)
100 aBaseObjects.insert(aBaseObjects.end(), anIt->second.begin(), anIt->second.end());
101 aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end());
103 // resize planes to the bounding box of operated shapes
104 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
105 resizePlanes(anObjects, aPlanes, aMakeShapeList);
107 // cut unused solids of composolids from the objects of partition
108 CompsolidSubs anUnusedSubs;
109 unusedSubsOfComposolid(anObjects, anUnusedSubs);
110 for (CompsolidSubs::iterator anIt = anUnusedSubs.begin(); anIt != anUnusedSubs.end(); ++anIt)
111 aBaseObjects.insert(aBaseObjects.end(), anIt->second.begin(), anIt->second.end());
114 if (!cutUnusedSubs(anObjects, anUnusedSubs, aMakeShapeList, aError)) {
119 // perform partition first time to split target solids
120 ListOfShape aTargetObjects;
121 for (CompsolidSubs::iterator anIt = anObjects.begin(); anIt != anObjects.end(); ++anIt)
122 aTargetObjects.insert(aTargetObjects.end(), anIt->second.begin(), anIt->second.end());
124 std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
125 new GeomAlgoAPI_Partition(aTargetObjects, aPlanes));
127 // Checking that the algorithm worked properly.
128 if (isAlgoFailed(aPartitionAlgo, aError)) {
133 aMakeShapeList->appendAlgo(aPartitionAlgo);
134 GeomShapePtr aResultShape = aPartitionAlgo->shape();
136 if (!anUnusedSubs.empty()) {
137 // second pass of a partition to split shared faces of compsolids
138 aTargetObjects.clear();
139 aTargetObjects.push_back(aResultShape);
140 for (CompsolidSubs::iterator anIt = anUnusedSubs.begin(); anIt != anUnusedSubs.end(); ++anIt)
141 aTargetObjects.insert(aTargetObjects.end(), anIt->second.begin(), anIt->second.end());
143 aPartitionAlgo.reset(new GeomAlgoAPI_Partition(aTargetObjects, ListOfShape()));
145 // Checking that the algorithm worked properly.
146 if (isAlgoFailed(aPartitionAlgo, aError)) {
151 aMakeShapeList->appendAlgo(aPartitionAlgo);
152 aResultShape = aPartitionAlgo->shape();
155 int aResultIndex = 0;
156 if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
157 for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
158 storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
162 storeResult(aBaseObjects, aPlanes, aResultShape, aMakeShapeList, aResultIndex);
166 // Remove the rest results if there were produced in the previous pass.
167 removeResults(aResultIndex);
170 //=================================================================================================
171 void FeaturesPlugin_Partition::storeResult(
172 ListOfShape& theObjects, ListOfShape& thePlanes,
173 const GeomShapePtr theResultShape,
174 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
177 // Find base. The most complicated is the real modified object (#1799 if box is partitioned by
178 // two planes the box is the base, not planes, independently on the order in the list).
179 GeomShapePtr aBaseShape;
180 for(ListOfShape::const_iterator anIt = theObjects.cbegin(); anIt != theObjects.cend(); ++anIt) {
181 GeomShapePtr anObjectShape = *anIt;
182 GeomShapePtr aCandidate =
183 findBase(anObjectShape, theResultShape, GeomAPI_Shape::VERTEX, theMakeShape);
184 if(!aCandidate.get()) {
185 aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::EDGE, theMakeShape);
187 if (!aCandidate.get())
188 aCandidate = findBase(anObjectShape, theResultShape, GeomAPI_Shape::FACE, theMakeShape);
190 if(aCandidate.get()) {
191 if (!aBaseShape.get() || aBaseShape->shapeType() > aCandidate->shapeType()) {
192 aBaseShape = aCandidate;
197 // Create result body.
198 ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
200 // Store modified shape.
201 if(!aBaseShape.get() || aBaseShape->isEqual(theResultShape)) {
202 aResultBody->store(theResultShape, false);
203 setResult(aResultBody, theIndex);
207 const int aDelTag = 1;
208 /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
209 const int aSubTag = 2;
210 int aModTag = aSubTag + 10000;
211 const std::string aModName = "Modified";
213 aResultBody->storeModified(aBaseShape, theResultShape, aSubTag);
215 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
216 theObjects.insert(theObjects.end(), thePlanes.begin(), thePlanes.end());
218 for(ListOfShape::const_iterator anIt = theObjects.cbegin(); anIt != theObjects.cend(); ++anIt) {
219 GeomShapePtr aShape = *anIt;
220 std::string aModEdgeName = aModName + "_Edge_" + std::to_string((long long)anIndex);
221 aResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), aShape, GeomAPI_Shape::EDGE,
222 aModTag, aModEdgeName, *aMapOfSubShapes.get(), false, true, true);
223 std::string aModFaceName = aModName + "_Face_" + std::to_string((long long)anIndex++);
224 aResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), aShape, GeomAPI_Shape::FACE,
225 aModTag + 1, aModFaceName, *aMapOfSubShapes.get(), false, true, true);
226 aResultBody->loadDeletedShapes(theMakeShape.get(), aShape, GeomAPI_Shape::FACE, aDelTag);
229 setResult(aResultBody, theIndex);
233 //================= Auxiliary functions ===================================================
235 GeomShapePtr findBase(const GeomShapePtr theObjectShape,
236 const GeomShapePtr theResultShape,
237 const GeomAPI_Shape::ShapeType theShapeType,
238 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
240 GeomShapePtr aBaseShape;
241 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
242 for(GeomAPI_ShapeExplorer anObjectSubShapesExp(theObjectShape, theShapeType);
243 anObjectSubShapesExp.more();
244 anObjectSubShapesExp.next()) {
245 GeomShapePtr anObjectSubShape = anObjectSubShapesExp.current();
246 ListOfShape aModifiedShapes;
247 theMakeShape->modified(anObjectSubShape, aModifiedShapes);
248 for(ListOfShape::const_iterator
249 aModIt = aModifiedShapes.cbegin(); aModIt != aModifiedShapes.cend(); ++aModIt) {
250 GeomShapePtr aModShape = *aModIt;
251 if(aMapOfSubShapes->isBound(aModShape)) {
252 aModShape = aMapOfSubShapes->find(aModShape);
254 if(theResultShape->isSubShape(aModShape)) {
255 aBaseShape = theObjectShape;
259 if(aBaseShape.get()) {
267 static CompsolidSubs::iterator findOrAdd(CompsolidSubs& theList, const GeomShapePtr& theCompsolid)
269 CompsolidSubs::iterator aFound = theList.begin();
270 for (; aFound != theList.end(); ++aFound)
271 if (aFound->first == theCompsolid)
273 if (aFound == theList.end()) {
274 theList.push_back(std::pair<GeomShapePtr, ListOfShape>(theCompsolid, ListOfShape()));
275 aFound = --theList.end();
280 void pullObjectsAndPlanes(const AttributeSelectionListPtr& theSelectedList,
281 CompsolidSubs& theObjects, ListOfShape& thePlanes)
283 std::map<ResultBodyPtr, GeomShapePtr> aMapCompsolidShape;
285 int aSize = theSelectedList->size();
286 for (int anIndex = 0; anIndex < aSize; ++anIndex) {
287 AttributeSelectionPtr anObjectAttr = theSelectedList->value(anIndex);
288 ResultPtr aContext = anObjectAttr->context();
289 GeomShapePtr anObject = anObjectAttr->value();
291 GeomShapePtr anOwnerShape = anObject;
292 // check the result is a compsolid and store all used subs in a single list
293 ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
294 if (aResCompSolidPtr && aResCompSolidPtr->shape()->shapeType() == GeomAPI_Shape::COMPSOLID) {
295 std::map<ResultBodyPtr, GeomShapePtr>::const_iterator
296 aFound = aMapCompsolidShape.find(aResCompSolidPtr);
297 if (aFound != aMapCompsolidShape.end())
298 anOwnerShape = aFound->second;
300 anOwnerShape = aResCompSolidPtr->shape();
301 aMapCompsolidShape[aResCompSolidPtr] = anOwnerShape;
305 CompsolidSubs::iterator aFound = findOrAdd(theObjects, anOwnerShape);
306 aFound->second.push_back(anObject);
309 // It could be a construction plane.
310 thePlanes.push_back(anObjectAttr->context()->shape());
315 void resizePlanes(const CompsolidSubs& theObjects, ListOfShape& thePlanes,
316 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList)
318 ListOfShape aSolidsInOperation;
319 for (CompsolidSubs::const_iterator anIt = theObjects.begin(); anIt != theObjects.end(); ++anIt)
320 aSolidsInOperation.insert(aSolidsInOperation.end(), anIt->second.begin(), anIt->second.end());
322 std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
323 GeomAlgoAPI_ShapeTools::getBoundingBox(aSolidsInOperation, 1.0);
325 ListOfShape aPlanesCopy = thePlanes;
328 // Resize planes to fit in bounding box
329 for (ListOfShape::const_iterator anIt = aPlanesCopy.begin(); anIt != aPlanesCopy.end(); ++anIt) {
330 GeomShapePtr aPlane = *anIt;
331 GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
332 std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(new GeomAlgoAPI_MakeShapeCustom);
333 aMkShCustom->addModified(aPlane, aTool);
334 theMakeShapeList->appendAlgo(aMkShCustom);
335 thePlanes.push_back(aTool);
339 void unusedSubsOfComposolid(const CompsolidSubs& theObjects, CompsolidSubs& theNotUsed)
341 for (CompsolidSubs::const_iterator aCSIt = theObjects.begin();
342 aCSIt != theObjects.end(); ++aCSIt) {
343 if (aCSIt->first->shapeType() != GeomAPI_Shape::COMPSOLID)
346 ListOfShape aNotUsedSolids;
347 for (GeomAPI_ShapeExplorer anExp(aCSIt->first, GeomAPI_Shape::SOLID);
348 anExp.more(); anExp.next()) {
349 GeomShapePtr aSolidInCompSolid = anExp.current();
350 ListOfShape::const_iterator anIt = aCSIt->second.begin();
351 for (; anIt != aCSIt->second.end(); ++anIt)
352 if (aSolidInCompSolid->isEqual(*anIt))
355 if (anIt == aCSIt->second.end())
356 aNotUsedSolids.push_back(aSolidInCompSolid);
359 if (!aNotUsedSolids.empty())
360 theNotUsed.push_back(std::pair<GeomShapePtr, ListOfShape>(aCSIt->first, aNotUsedSolids));
364 bool cutUnusedSubs(CompsolidSubs& theObjects, CompsolidSubs& theNotUsed,
365 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
366 std::string& theError)
368 std::shared_ptr<GeomAlgoAPI_MakeShape> aCutAlgo;
370 for (CompsolidSubs::iterator anObjIt = theObjects.begin();
371 anObjIt != theObjects.end(); ++anObjIt) {
372 // get list of unused subs of composolids except the current
374 for (CompsolidSubs::const_iterator aUIt = theNotUsed.begin();
375 aUIt != theNotUsed.end(); ++aUIt) {
376 if (aUIt->first != anObjIt->first)
377 aTools.insert(aTools.end(), aUIt->second.begin(), aUIt->second.end());
382 // cut from current list of solids
384 new GeomAlgoAPI_Boolean(anObjIt->second, aTools, GeomAlgoAPI_Boolean::BOOL_CUT));
385 if (isAlgoFailed(aCutAlgo, theError))
387 theMakeShapeList->appendAlgo(aCutAlgo);
389 // update list of objects of the partition
390 GeomAPI_Shape::ShapeType aType = anObjIt->second.front()->shapeType();
391 anObjIt->second.clear();
392 for (GeomAPI_ShapeExplorer anExp(aCutAlgo->shape(), aType); anExp.more(); anExp.next())
393 anObjIt->second.push_back(anExp.current());
398 bool isAlgoFailed(const std::shared_ptr<GeomAlgoAPI_MakeShape>& theAlgo, std::string& theError)
400 if (!theAlgo->isDone()) {
401 theError = "Error: Partition algorithm failed.";
404 if (theAlgo->shape()->isNull()) {
405 theError = "Error: Resulting shape is Null.";
408 if (!theAlgo->isValid()) {
409 theError = "Error: Resulting shape is not valid.";