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 "GeomAlgoAPI_Boolean.h"
22 #include <GeomAlgoAPI_DFLoader.h>
23 #include <GeomAlgoAPI_ShapeTools.h>
25 #include <BOPAlgo_BOP.hxx>
26 #include <TopTools_ListOfShape.hxx>
27 #include <TopoDS_Iterator.hxx>
28 #include <TopExp_Explorer.hxx>
31 //=================================================================================================
32 GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const GeomShapePtr theObject,
33 const GeomShapePtr theTool,
34 const GeomAlgoAPI_Tools::BOPType theOperationType,
35 const double theFuzzy/*= -1*/)
37 ListOfShape aListWithObject, aListWithTool;
38 aListWithObject.push_back(theObject);
39 aListWithTool.push_back(theTool);
40 build(aListWithObject, aListWithTool, theOperationType, theFuzzy);
43 //=================================================================================================
44 GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const GeomShapePtr theObject,
45 const ListOfShape& theTools,
46 const GeomAlgoAPI_Tools::BOPType theOperationType,
47 const double theFuzzy/*= -1*/)
49 ListOfShape aListWithObject;
50 aListWithObject.push_back(theObject);
51 build(aListWithObject, theTools, theOperationType, theFuzzy);
54 //=================================================================================================
55 GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const ListOfShape& theObjects,
56 const ListOfShape& theTools,
57 const GeomAlgoAPI_Tools::BOPType theOperationType,
58 const double theFuzzy/*= -1*/)
60 build(theObjects, theTools, theOperationType, theFuzzy);
64 //=================================================================================================
65 void GeomAlgoAPI_Boolean::build(const ListOfShape& theObjects,
66 const ListOfShape& theTools,
67 const GeomAlgoAPI_Tools::BOPType theOperationType,
68 const double theFuzzy)
70 if (theObjects.empty() || theTools.empty()) {
75 TopTools_ListOfShape anObjects;
76 for(ListOfShape::const_iterator
77 anObjectsIt = theObjects.begin(); anObjectsIt != theObjects.end(); anObjectsIt++)
79 anObjects.Append((*anObjectsIt)->impl<TopoDS_Shape>());
83 TopTools_ListOfShape aTools;
84 for(ListOfShape::const_iterator
85 aToolsIt = theTools.begin(); aToolsIt != theTools.end(); aToolsIt++)
87 aTools.Append((*aToolsIt)->impl<TopoDS_Shape>());
90 // Creating boolean operation.
91 BOPAlgo_BOP* aBuilder = new BOPAlgo_BOP();
92 switch (theOperationType) {
93 case GeomAlgoAPI_Tools::BOOL_CUT: {
94 aBuilder->SetOperation(BOPAlgo_CUT);
97 case GeomAlgoAPI_Tools::BOOL_FUSE: {
98 aBuilder->SetOperation(BOPAlgo_FUSE);
101 case GeomAlgoAPI_Tools::BOOL_COMMON: {
102 aBuilder->SetOperation(BOPAlgo_COMMON);
109 this->setImpl(aBuilder);
110 this->setBuilderType(OCCT_BOPAlgo_Builder);
111 aBuilder->SetArguments(anObjects);
112 aBuilder->SetTools(aTools);
114 // Set parallel processing mode (default is false)
115 Standard_Boolean bRunParallel = Standard_True;
116 aBuilder->SetRunParallel(bRunParallel);
118 // Set fuzzy value to eliminate thin results
119 // => Either use the value set by the user (if positive)
120 // => or use the old default value of 1.e-5
121 Standard_Real aFuzzy = (theFuzzy > 0 ? theFuzzy : 1.e-5);
122 aBuilder->SetFuzzyValue(aFuzzy);
124 // Building and getting result.
126 if (aBuilder->HasErrors())
128 TopoDS_Shape aResult = aBuilder->Shape();
130 if(aResult.ShapeType() == TopAbs_COMPOUND) {
131 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
133 if(aResult.ShapeType() == TopAbs_COMPOUND) {
134 std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
135 aGeomShape->setImpl(new TopoDS_Shape(aResult));
136 ListOfShape aResults;
137 aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
138 GeomAPI_Shape::COMPSOLID,
140 aResult = aGeomShape->impl<TopoDS_Shape>();
143 std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
144 aShape->setImpl(new TopoDS_Shape(aResult));
145 this->setShape(aShape);
149 //=================================================================================================
150 static bool isHistoryType(TopAbs_ShapeEnum theType) {
151 return theType == TopAbs_VERTEX || theType == TopAbs_EDGE ||
152 theType == TopAbs_FACE || theType == TopAbs_SOLID;
155 //=================================================================================================
156 /// searches the corresponding result for theOld
157 static void searchResult(const TopoDS_Shape& theOld, const TopoDS_Shape& theResult,
158 BOPAlgo_BOP* theBuilder, TopTools_MapOfShape& theNews)
160 if (theResult.ShapeType() == theOld.ShapeType()) { // check some sub-shape produces a sub-result
161 if (theOld.IsSame(theResult)) {
162 theNews.Add(theResult);
165 // searching for new result by sub-shapes of aSubType type
166 TopAbs_ShapeEnum aSubType = TopAbs_ShapeEnum(int(theOld.ShapeType()) + 1);
167 while(aSubType < TopAbs_VERTEX && !isHistoryType(aSubType))
168 aSubType = TopAbs_ShapeEnum(int(aSubType) + 1);
169 if (aSubType == TopAbs_SHAPE)
171 TopTools_MapOfShape aResSubs;
172 for(TopExp_Explorer aResExp(theResult, aSubType); aResExp.More(); aResExp.Next())
173 aResSubs.Add(aResExp.Current());
174 for(TopExp_Explorer anExp(theOld, aSubType); anExp.More(); anExp.Next()) {
175 const TopTools_ListOfShape& aNewSubs = theBuilder->Modified(anExp.Current());
176 // searching for this new sub in theResult
177 for(TopTools_ListIteratorOfListOfShape aNewSub(aNewSubs); aNewSub.More(); aNewSub.Next()) {
178 if (aResSubs.Contains(aNewSub.Value())) {
179 theNews.Add(theResult);
184 } else if (theResult.ShapeType() < theOld.ShapeType()) { // recursive search among sub-shapes
185 for(TopoDS_Iterator aSubResults(theResult); aSubResults.More(); aSubResults.Next()) {
186 searchResult(theOld, aSubResults.Value(), theBuilder, theNews);
191 //=================================================================================================
192 // check the shape is on the higher level of compound or compsolid
193 bool isInComp(const TopoDS_Shape& theComp, const TopoDS_Shape& theShape) {
194 if (theComp.ShapeType() == TopAbs_COMPOUND || theComp.ShapeType() == TopAbs_COMPSOLID) {
195 for(TopoDS_Iterator anIter(theComp); anIter.More(); anIter.Next()) {
196 if (isInComp(anIter.Value(), theShape))
199 } else return theShape.IsSame(theComp);
203 //=================================================================================================
204 /// make arguments of Fuse produce result shapes with "modified" evolution
205 void GeomAlgoAPI_Boolean::modified(const GeomShapePtr theOldShape, ListOfShape& theNewShapes)
207 BOPAlgo_BOP* aBuilder = this->implPtr<BOPAlgo_BOP>();
208 if (aBuilder->Operation() == BOPAlgo_FUSE) { // only for fuse and when old is and argument
209 TopoDS_Shape anOld = theOldShape->impl<TopoDS_Shape>();
210 bool isOldComp = anOld.ShapeType() == TopAbs_COMPOUND || anOld.ShapeType() == TopAbs_COMPSOLID;
212 TopTools_ListIteratorOfListOfShape anIter(aBuilder->Arguments());
213 for(; !aFound && anIter.More(); anIter.Next())
214 aFound = anOld.IsSame(anIter.Value()) || (!isOldComp && isInComp(anIter.Value(), anOld));
215 for(anIter.Initialize(aBuilder->Tools()); !aFound && anIter.More(); anIter.Next())
216 aFound = anOld.IsSame(anIter.Value()) || (!isOldComp && isInComp(anIter.Value(), anOld));
218 TopoDS_Shape aResult = aBuilder->Shape();
219 TopTools_MapOfShape aNewsMap;
220 searchResult(anOld, aResult, aBuilder, aNewsMap);
221 if (!aNewsMap.IsEmpty()) {
222 for(TopTools_MapIteratorOfMapOfShape aNewsIter(aNewsMap);
223 aNewsIter.More(); aNewsIter.Next())
225 GeomShapePtr aShape(new GeomAPI_Shape);
226 aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aNewsIter.Value()));
227 theNewShapes.push_back(aShape);
233 GeomAlgoAPI_MakeShape::modified(theOldShape, theNewShapes); // default behavior