1 // Copyright (C) 2014-2022 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 email : webmaster.salome@opencascade.com
20 #include "FeaturesPlugin_Partition.h"
22 #include <ModelAPI_AttributeBoolean.h>
23 #include <ModelAPI_AttributeDouble.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_ShapeBuilder.h>
41 #include <GeomAlgoAPI_ShapeTools.h>
42 #include <GeomAlgoAPI_Tools.h>
44 #include <GeomAPI_Face.h>
45 #include <GeomAPI_ShapeExplorer.h>
46 #include <GeomAPI_ShapeIterator.h>
53 static const double DEFAULT_FUZZY = 1.e-5;
56 //=================================================================================================
57 FeaturesPlugin_Partition::FeaturesPlugin_Partition()
61 //=================================================================================================
62 void FeaturesPlugin_Partition::initAttributes()
64 data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
66 data()->addAttribute(USE_FUZZY_ID(), ModelAPI_AttributeBoolean::typeId());
67 data()->addAttribute(FUZZY_PARAM_ID(), ModelAPI_AttributeDouble::typeId());
68 boolean(USE_FUZZY_ID())->setValue(false); // Do NOT use the fuzzy parameter by default.
69 real(FUZZY_PARAM_ID())->setValue(DEFAULT_FUZZY);
71 initVersion(BOP_VERSION_9_4(), selectionList(BASE_OBJECTS_ID()));
74 //=================================================================================================
75 void FeaturesPlugin_Partition::execute()
77 GeomAPI_ShapeHierarchy anObjects;
81 processAttribute(BASE_OBJECTS_ID(), anObjects, aPlanes);
82 if(anObjects.empty()) {
83 static const std::string aFeatureError = "Error: No objects for partition.";
84 setError(aFeatureError);
88 // Getting fuzzy parameter.
89 // Used as additional tolerance to eliminate tiny results.
90 // Using -1 as fuzzy value in the GeomAlgoAPI means to ignore it during the boolean operation!
91 bool aUseFuzzy = boolean(USE_FUZZY_ID())->value();
92 double aFuzzy = (aUseFuzzy ? real(FUZZY_PARAM_ID())->value() : -1);
94 ListOfShape aBaseObjects = anObjects.objects();
95 aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end());
97 // resize planes to the bounding box of operated shapes
98 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
99 resizePlanes(anObjects.objects(), aPlanes, aMakeShapeList);
101 // cut unused solids of composolids from the objects of partition
102 ListOfShape aTargetObjects, anUnusedSubs;
104 if (!cutSubs(anObjects, aTargetObjects, anUnusedSubs, aFuzzy, aMakeShapeList, aError)) {
108 aBaseObjects.insert(aBaseObjects.end(), anUnusedSubs.begin(), anUnusedSubs.end());
110 // perform partition first time to split target solids by planes
111 std::shared_ptr<GeomAlgoAPI_Partition> aPartitionAlgo(
112 new GeomAlgoAPI_Partition(aTargetObjects, aPlanes, aFuzzy));
114 // Checking that the algorithm worked properly.
115 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
120 aMakeShapeList->appendAlgo(aPartitionAlgo);
121 GeomShapePtr aResultShape = aPartitionAlgo->shape();
123 if (!anUnusedSubs.empty()) {
124 // second pass of a partition to split shared faces of compsolids
125 aTargetObjects.clear();
126 aTargetObjects.push_back(aResultShape);
127 aTargetObjects.insert(aTargetObjects.end(), anUnusedSubs.begin(), anUnusedSubs.end());
129 aPartitionAlgo.reset(new GeomAlgoAPI_Partition(aTargetObjects, ListOfShape()));
131 // Checking that the algorithm worked properly.
132 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), aError)) {
137 aMakeShapeList->appendAlgo(aPartitionAlgo);
138 aResultShape = aPartitionAlgo->shape();
141 int aResultIndex = 0;
143 if (data()->version().empty()) {
144 // default behaviors of Partition
145 if(aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
146 for(GeomAPI_ShapeIterator anIt(aResultShape); anIt.more(); anIt.next()) {
147 storeResult(aBaseObjects, aPlanes, anIt.current(), aMakeShapeList, aResultIndex);
151 storeResult(aBaseObjects, aPlanes, aResultShape, aMakeShapeList, aResultIndex);
156 // merge hierarchies of compounds containing objects and tools
157 GeomShapePtr aFirstShape = aResultShape;
158 GeomAPI_ShapeIterator anIt;
159 if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
160 anIt = GeomAPI_ShapeIterator(aResultShape);
161 aFirstShape = anIt.current();
165 GeomShapePtr aResultCompound =
166 keepUnusedSubsOfCompound(aFirstShape, anObjects, GeomAPI_ShapeHierarchy(), aMakeShapeList);
169 if (aResultCompound->shapeType() != GeomAPI_Shape::COMPOUND) {
170 // put the shape into compound
172 aShapes.push_back(aResultCompound);
173 aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
175 std::shared_ptr<GeomAlgoAPI_ShapeBuilder> aBuilder(new GeomAlgoAPI_ShapeBuilder);
176 for (; anIt.more(); anIt.next())
177 aBuilder->add(aResultCompound, anIt.current());
178 aMakeShapeList->appendAlgo(aBuilder);
181 storeResult(aBaseObjects, aPlanes, aResultCompound, aMakeShapeList, aResultIndex);
185 // Remove the rest results if there were produced in the previous pass.
186 removeResults(aResultIndex);
189 //=================================================================================================
190 void FeaturesPlugin_Partition::storeResult(
191 ListOfShape& theObjects, ListOfShape& thePlanes,
192 const GeomShapePtr theResultShape,
193 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
196 // Create result body.
197 ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
199 // if result is same as one of the base object, no modification was performed
200 for(ListOfShape::const_iterator anObj = theObjects.cbegin(); anObj != theObjects.cend(); ++anObj)
202 if (anObj->get() && (*anObj)->isSame(theResultShape)) {
203 aResultBody->store(theResultShape, false);
204 setResult(aResultBody, theIndex);
209 aResultBody->storeModified(theObjects, theResultShape, theMakeShape);
211 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
212 theObjects.insert(theObjects.end(), thePlanes.begin(), thePlanes.end());
213 for (ListOfShape::const_iterator anIt = theObjects.cbegin();
214 anIt != theObjects.cend();
217 GeomShapePtr aShape = *anIt;
218 aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::EDGE);
219 aResultBody->loadModifiedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
220 aResultBody->loadDeletedShapes(theMakeShape, aShape, GeomAPI_Shape::FACE);
223 setResult(aResultBody, theIndex);
227 //=================================================================================================
228 static bool cutSubs(ListOfShape& theSubsToCut,
229 const ListOfShape& theTools,
230 const double theFuzzy,
231 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
232 std::string& theError)
234 if (theSubsToCut.empty() || theTools.empty())
237 // cut from current list of solids
238 std::shared_ptr<GeomAlgoAPI_MakeShape> aCutAlgo(
239 new GeomAlgoAPI_Boolean(theSubsToCut, theTools, GeomAlgoAPI_Tools::BOOL_CUT, theFuzzy));
240 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, "", theError))
242 theMakeShapeList->appendAlgo(aCutAlgo);
244 // update list of un-selected objects of the partition
245 GeomAPI_Shape::ShapeType aType = theSubsToCut.front()->shapeType();
246 theSubsToCut.clear();
247 for (GeomAPI_ShapeExplorer anExp(aCutAlgo->shape(), aType); anExp.more(); anExp.next())
248 theSubsToCut.push_back(anExp.current());
252 //=================================================================================================
253 bool FeaturesPlugin_Partition::cutSubs(
254 GeomAPI_ShapeHierarchy& theHierarchy,
255 ListOfShape& theUsed,
256 ListOfShape& theNotUsed,
257 const double theFuzzy,
258 std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theMakeShapeList,
259 std::string& theError)
264 GeomAPI_ShapeHierarchy::iterator anIt = theHierarchy.begin();
266 // compose a set of tools for the CUT operation:
267 // find the list of unused subs of the first argument or use itself
268 ListOfShape aToolsForUsed, aToolsForUnused;
269 GeomShapePtr aFirstArgument = theHierarchy.parent(*anIt, false);
270 if (aFirstArgument && aFirstArgument->shapeType() == GeomAPI_Shape::COMPSOLID) {
271 theHierarchy.splitCompound(aFirstArgument, theUsed, aToolsForUsed);
272 theNotUsed = aToolsForUsed;
275 aFirstArgument = *anIt;
276 theUsed.push_back(aFirstArgument);
278 aToolsForUnused.push_back(aFirstArgument);
282 for (++anIt; anIt != theHierarchy.end() && isOk; ++anIt) {
283 ListOfShape aUsed, aNotUsed;
285 GeomShapePtr aParent = theHierarchy.parent(*anIt, false);
286 if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) {
287 aParent = theHierarchy.parent(*anIt); // get parent once again to mark its subs as processed
288 theHierarchy.splitCompound(aParent, aUsed, aNotUsed);
291 aUsed.push_back(*anIt);
293 isOk = ::cutSubs(aUsed, aToolsForUsed, theFuzzy, theMakeShapeList, theError)
294 && ::cutSubs(aNotUsed, aToolsForUnused, theFuzzy, theMakeShapeList, theError);
296 theUsed.insert(theUsed.end(), aUsed.begin(), aUsed.end());
297 theNotUsed.insert(theNotUsed.end(), aNotUsed.begin(), aNotUsed.end());