Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Boolean.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
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 "GeomAlgoAPI_Boolean.h"
21
22 #include <GeomAlgoAPI_DFLoader.h>
23 #include <GeomAlgoAPI_ShapeTools.h>
24
25 #include <BOPAlgo_BOP.hxx>
26 #include <TopTools_ListOfShape.hxx>
27 #include <TopoDS_Iterator.hxx>
28 #include <TopExp_Explorer.hxx>
29
30
31 //=================================================================================================
32 GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const GeomShapePtr theObject,
33                                          const GeomShapePtr theTool,
34                                          const GeomAlgoAPI_Tools::BOPType theOperationType,
35                                          const double theFuzzy/*= -1*/)
36 {
37   ListOfShape aListWithObject, aListWithTool;
38   aListWithObject.push_back(theObject);
39   aListWithTool.push_back(theTool);
40   build(aListWithObject, aListWithTool, theOperationType, theFuzzy);
41 }
42
43 //=================================================================================================
44 GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const GeomShapePtr theObject,
45                                          const ListOfShape& theTools,
46                                          const GeomAlgoAPI_Tools::BOPType theOperationType,
47                                          const double theFuzzy/*= -1*/)
48 {
49   ListOfShape aListWithObject;
50   aListWithObject.push_back(theObject);
51   build(aListWithObject, theTools, theOperationType, theFuzzy);
52 }
53
54 //=================================================================================================
55 GeomAlgoAPI_Boolean::GeomAlgoAPI_Boolean(const ListOfShape& theObjects,
56                                          const ListOfShape& theTools,
57                                          const GeomAlgoAPI_Tools::BOPType theOperationType,
58                                          const double theFuzzy/*= -1*/)
59 {
60   build(theObjects, theTools, theOperationType, theFuzzy);
61 }
62
63
64 //=================================================================================================
65 void GeomAlgoAPI_Boolean::build(const ListOfShape& theObjects,
66                                 const ListOfShape& theTools,
67                                 const GeomAlgoAPI_Tools::BOPType theOperationType,
68                                 const double theFuzzy)
69 {
70   if (theObjects.empty() || theTools.empty()) {
71     return;
72   }
73
74   // Getting objects.
75   TopTools_ListOfShape anObjects;
76   for(ListOfShape::const_iterator
77     anObjectsIt = theObjects.begin(); anObjectsIt != theObjects.end(); anObjectsIt++)
78   {
79     anObjects.Append((*anObjectsIt)->impl<TopoDS_Shape>());
80   }
81
82   // Getting tools.
83   TopTools_ListOfShape aTools;
84   for(ListOfShape::const_iterator
85     aToolsIt = theTools.begin(); aToolsIt != theTools.end(); aToolsIt++)
86   {
87     aTools.Append((*aToolsIt)->impl<TopoDS_Shape>());
88   }
89
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);
95       break;
96     }
97     case GeomAlgoAPI_Tools::BOOL_FUSE: {
98       aBuilder->SetOperation(BOPAlgo_FUSE);
99       break;
100     }
101     case GeomAlgoAPI_Tools::BOOL_COMMON: {
102       aBuilder->SetOperation(BOPAlgo_COMMON);
103       break;
104     }
105     default: {
106       return;
107     }
108   }
109   this->setImpl(aBuilder);
110   this->setBuilderType(OCCT_BOPAlgo_Builder);
111   aBuilder->SetArguments(anObjects);
112   aBuilder->SetTools(aTools);
113
114   // Set parallel processing mode (default is false)
115   Standard_Boolean bRunParallel = Standard_True;
116   aBuilder->SetRunParallel(bRunParallel);
117
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);
123
124   // Building and getting result.
125   aBuilder->Perform();
126   if (aBuilder->HasErrors())
127     return;
128   TopoDS_Shape aResult = aBuilder->Shape();
129
130   if(aResult.ShapeType() == TopAbs_COMPOUND) {
131     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
132   }
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,
139                                                        aResults);
140     aResult = aGeomShape->impl<TopoDS_Shape>();
141   }
142
143   std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
144   aShape->setImpl(new TopoDS_Shape(aResult));
145   this->setShape(aShape);
146   this->setDone(true);
147 }
148
149 //=================================================================================================
150 static bool isHistoryType(TopAbs_ShapeEnum theType) {
151   return theType == TopAbs_VERTEX || theType == TopAbs_EDGE ||
152          theType == TopAbs_FACE || theType == TopAbs_SOLID;
153 }
154
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)
159 {
160   if (theResult.ShapeType() == theOld.ShapeType()) { // check some sub-shape produces a sub-result
161     if (theOld.IsSame(theResult)) {
162       theNews.Add(theResult);
163       return;
164     }
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)
170       return;
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);
180           return;
181         }
182       }
183     }
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);
187     }
188   }
189 }
190
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))
197         return true;
198     }
199   } else return theShape.IsSame(theComp);
200   return false;
201 }
202
203 //=================================================================================================
204 /// make arguments of Fuse produce result shapes with "modified" evolution
205 void GeomAlgoAPI_Boolean::modified(const GeomShapePtr theOldShape, ListOfShape& theNewShapes)
206 {
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;
211     bool aFound = false;
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));
217     if (aFound) {
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())
224         {
225           GeomShapePtr aShape(new GeomAPI_Shape);
226           aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aNewsIter.Value()));
227           theNewShapes.push_back(aShape);
228         }
229         return;
230       }
231     }
232   }
233   GeomAlgoAPI_MakeShape::modified(theOldShape, theNewShapes); // default behavior
234 }