]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOMImpl/GEOMImpl_BooleanDriver.cxx
Salome HOME
bf82f5136a13d1b932d71beaa4b533e6c9abf4ef
[modules/geom.git] / src / GEOMImpl / GEOMImpl_BooleanDriver.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 #include <GEOMImpl_BooleanDriver.hxx>
23 #include <GEOMImpl_IBoolean.hxx>
24 #include <GEOMImpl_Types.hxx>
25 #include <GEOMImpl_GlueDriver.hxx>
26 #include <GEOM_Function.hxx>
27
28 #include <BRep_Builder.hxx>
29 #include <BRepAlgo.hxx>
30 #include <BRepAlgoAPI_Common.hxx>
31 #include <BRepAlgoAPI_Cut.hxx>
32 #include <BRepAlgoAPI_Fuse.hxx>
33 #include <BRepAlgoAPI_Section.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <TopoDS_Shape.hxx>
36 #include <TopoDS_Compound.hxx>
37 #include <TopoDS_Iterator.hxx>
38 #include <TopTools_MapOfShape.hxx>
39 #include <TopTools_ListOfShape.hxx>
40 #include <TopTools_ListIteratorOfListOfShape.hxx>
41 #include <Precision.hxx>
42 #include <BRepCheck_Analyzer.hxx>
43 #include <ShapeFix_ShapeTolerance.hxx>
44 #include <ShapeFix_Shape.hxx>
45
46 #include <Standard_ConstructionError.hxx>
47 #include <StdFail_NotDone.hxx>
48
49 //=======================================================================
50 //function : GetID
51 //purpose  :
52 //=======================================================================
53 const Standard_GUID& GEOMImpl_BooleanDriver::GetID()
54 {
55   static Standard_GUID aBooleanDriver("FF1BBB21-5D14-4df2-980B-3A668264EA16");
56   return aBooleanDriver;
57 }
58
59
60 //=======================================================================
61 //function : GEOMImpl_BooleanDriver
62 //purpose  :
63 //=======================================================================
64 GEOMImpl_BooleanDriver::GEOMImpl_BooleanDriver()
65 {
66 }
67
68 void AddSimpleShapes(TopoDS_Shape theShape, TopTools_ListOfShape& theList)
69 {
70   if (theShape.ShapeType() != TopAbs_COMPOUND &&
71       theShape.ShapeType() != TopAbs_COMPSOLID) {
72     theList.Append(theShape);
73     return;
74   }
75
76   TopTools_MapOfShape mapShape;
77   TopoDS_Iterator It (theShape, Standard_True, Standard_True);
78
79   for (; It.More(); It.Next()) {
80     TopoDS_Shape aShape_i = It.Value();
81     if (mapShape.Add(aShape_i)) {
82       if (aShape_i.ShapeType() == TopAbs_COMPOUND ||
83           aShape_i.ShapeType() == TopAbs_COMPSOLID) {
84         AddSimpleShapes(aShape_i, theList);
85       } else {
86         theList.Append(aShape_i);
87       }
88     }
89   }
90 }
91
92 //=======================================================================
93 //function : Execute
94 //purpose  :
95 //=======================================================================
96 Standard_Integer GEOMImpl_BooleanDriver::Execute(TFunction_Logbook& log) const
97 {
98   if (Label().IsNull()) return 0;
99   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
100
101   GEOMImpl_IBoolean aCI (aFunction);
102   Standard_Integer aType = aFunction->GetType();
103
104   TopoDS_Shape aShape;
105
106   Handle(GEOM_Function) aRefShape1 = aCI.GetShape1();
107   Handle(GEOM_Function) aRefShape2 = aCI.GetShape2();
108   TopoDS_Shape aShape1 = aRefShape1->GetValue();
109   TopoDS_Shape aShape2 = aRefShape2->GetValue();
110   if (!aShape1.IsNull() && !aShape2.IsNull()) {
111
112     // perform COMMON operation
113     if (aType == BOOLEAN_COMMON) {
114       BRep_Builder B;
115       TopoDS_Compound C;
116       B.MakeCompound(C);
117
118       TopTools_ListOfShape listShape1, listShape2;
119       AddSimpleShapes(aShape1, listShape1);
120       AddSimpleShapes(aShape2, listShape2);
121
122       Standard_Boolean isCompound =
123         (listShape1.Extent() > 1 || listShape2.Extent() > 1);
124
125       TopTools_ListIteratorOfListOfShape itSub1 (listShape1);
126       for (; itSub1.More(); itSub1.Next()) {
127         TopoDS_Shape aValue1 = itSub1.Value();
128         TopTools_ListIteratorOfListOfShape itSub2 (listShape2);
129         for (; itSub2.More(); itSub2.Next()) {
130           TopoDS_Shape aValue2 = itSub2.Value();
131           BRepAlgoAPI_Common BO (aValue1, aValue2);
132           if (!BO.IsDone()) {
133             StdFail_NotDone::Raise("Common operation can not be performed on the given shapes");
134           }
135           if (isCompound) {
136             TopoDS_Shape aStepResult = BO.Shape();
137
138             // check result of this step: if it is a compound (boolean operations
139             // allways return a compound), we add all sub-shapes of it.
140             // This allows to avoid adding empty compounds,
141             // resulting from COMMON on two non-intersecting shapes.
142             if (aStepResult.ShapeType() == TopAbs_COMPOUND) {
143               TopoDS_Iterator aCompIter (aStepResult);
144               for (; aCompIter.More(); aCompIter.Next()) {
145                 // add shape in a result
146                 B.Add(C, aCompIter.Value());
147               }
148             }
149             else {
150               // add shape in a result
151               B.Add(C, aStepResult);
152             }
153           }
154           else
155             aShape = BO.Shape();
156         }
157       }
158
159       if (isCompound) {
160         /*
161         TopTools_ListOfShape listShapeC;
162         AddSimpleShapes(C, listShapeC);
163         TopTools_ListIteratorOfListOfShape itSubC (listShapeC);
164         bool isOnlySolids = true;
165         for (; itSubC.More(); itSubC.Next()) {
166           TopoDS_Shape aValueC = itSubC.Value();
167           if (aValueC.ShapeType() != TopAbs_SOLID) isOnlySolids = false;
168         }
169         if (isOnlySolids)
170           aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion());
171         else
172           aShape = C;
173         */
174
175         // As GlueFaces has been improved to keep all kind of shapes
176         TopExp_Explorer anExp (C, TopAbs_VERTEX);
177         if (anExp.More())
178           aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
179         else
180           aShape = C;
181       }
182     }
183
184     // perform CUT operation
185     else if (aType == BOOLEAN_CUT) {
186       BRep_Builder B;
187       TopoDS_Compound C;
188       B.MakeCompound(C);
189
190       TopTools_ListOfShape listShapes, listTools;
191       AddSimpleShapes(aShape1, listShapes);
192       AddSimpleShapes(aShape2, listTools);
193
194       Standard_Boolean isCompound = (listShapes.Extent() > 1);
195
196       TopTools_ListIteratorOfListOfShape itSub1 (listShapes);
197       for (; itSub1.More(); itSub1.Next()) {
198         TopoDS_Shape aCut = itSub1.Value();
199         // tools
200         TopTools_ListIteratorOfListOfShape itSub2 (listTools);
201         for (; itSub2.More(); itSub2.Next()) {
202           TopoDS_Shape aTool = itSub2.Value();
203           BRepAlgoAPI_Cut BO (aCut, aTool);
204           if (!BO.IsDone()) {
205             StdFail_NotDone::Raise("Cut operation can not be performed on the given shapes");
206           }
207           aCut = BO.Shape();
208         }
209         if (isCompound) {
210           // check result of this step: if it is a compound (boolean operations
211           // allways return a compound), we add all sub-shapes of it.
212           // This allows to avoid adding empty compounds,
213           // resulting from CUT of parts
214           if (aCut.ShapeType() == TopAbs_COMPOUND) {
215             TopoDS_Iterator aCompIter (aCut);
216             for (; aCompIter.More(); aCompIter.Next()) {
217               // add shape in a result
218               B.Add(C, aCompIter.Value());
219             }
220           }
221           else {
222             // add shape in a result
223             B.Add(C, aCut);
224           }
225         }
226         else
227           aShape = aCut;
228       }
229
230       if (isCompound) {
231         /*
232         TopTools_ListOfShape listShapeC;
233         AddSimpleShapes(C, listShapeC);
234         TopTools_ListIteratorOfListOfShape itSubC (listShapeC);
235         bool isOnlySolids = true;
236         for (; itSubC.More(); itSubC.Next()) {
237           TopoDS_Shape aValueC = itSubC.Value();
238           if (aValueC.ShapeType() != TopAbs_SOLID) isOnlySolids = false;
239         }
240         if (isOnlySolids)
241           aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion());
242         else
243           aShape = C;
244         */
245
246         // As GlueFaces has been improved to keep all kind of shapes
247         TopExp_Explorer anExp (C, TopAbs_VERTEX);
248         if (anExp.More())
249           aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
250         else
251           aShape = C;
252       }
253     }
254
255     // perform FUSE operation
256     else if (aType == BOOLEAN_FUSE) {
257       /* Fix for NPAL15379: refused
258       // Check arguments
259       TopTools_ListOfShape listShape1, listShape2;
260       AddSimpleShapes(aShape1, listShape1);
261       AddSimpleShapes(aShape2, listShape2);
262
263       Standard_Boolean isIntersect = Standard_False;
264
265       if (listShape1.Extent() > 1 && !isIntersect) {
266         // check intersections inside the first compound
267         TopTools_ListIteratorOfListOfShape it1 (listShape1);
268         for (; it1.More() && !isIntersect; it1.Next()) {
269           TopoDS_Shape aValue1 = it1.Value();
270           TopTools_ListIteratorOfListOfShape it2 (listShape1);
271           for (; it2.More() && !isIntersect; it2.Next()) {
272             TopoDS_Shape aValue2 = it2.Value();
273             if (aValue2 != aValue1) {
274               BRepAlgoAPI_Section BO (aValue1, aValue2);
275               if (BO.IsDone()) {
276                 TopoDS_Shape aSect = BO.Shape();
277                 TopExp_Explorer anExp (aSect, TopAbs_EDGE);
278                 if (anExp.More()) {
279                   isIntersect = Standard_True;
280                 }
281               }
282             }
283           }
284         }
285       }
286
287       if (listShape2.Extent() > 1 && !isIntersect) {
288         // check intersections inside the second compound
289         TopTools_ListIteratorOfListOfShape it1 (listShape2);
290         for (; it1.More() && !isIntersect; it1.Next()) {
291           TopoDS_Shape aValue1 = it1.Value();
292           TopTools_ListIteratorOfListOfShape it2 (listShape2);
293           for (; it2.More() && !isIntersect; it2.Next()) {
294             TopoDS_Shape aValue2 = it2.Value();
295             if (aValue2 != aValue1) {
296               BRepAlgoAPI_Section BO (aValue1, aValue2);
297               if (BO.IsDone()) {
298                 TopoDS_Shape aSect = BO.Shape();
299                 TopExp_Explorer anExp (aSect, TopAbs_EDGE);
300                 if (anExp.More()) {
301                   isIntersect = Standard_True;
302                 }
303               }
304             }
305           }
306         }
307       }
308
309       if (isIntersect) {
310         // have intersections inside compounds
311         // check intersections between compounds
312         TopTools_ListIteratorOfListOfShape it1 (listShape1);
313         for (; it1.More(); it1.Next()) {
314           TopoDS_Shape aValue1 = it1.Value();
315           TopTools_ListIteratorOfListOfShape it2 (listShape2);
316           for (; it2.More(); it2.Next()) {
317             TopoDS_Shape aValue2 = it2.Value();
318             if (aValue2 != aValue1) {
319               BRepAlgoAPI_Section BO (aValue1, aValue2);
320               if (BO.IsDone()) {
321                 TopoDS_Shape aSect = BO.Shape();
322                 TopExp_Explorer anExp (aSect, TopAbs_EDGE);
323                 if (anExp.More()) {
324                   StdFail_NotDone::Raise("Bad argument for Fuse: compound with intersecting sub-shapes");
325                 }
326               }
327             }
328           }
329         }
330       }
331       */
332
333       // Perform
334       BRepAlgoAPI_Fuse BO (aShape1, aShape2);
335       if (!BO.IsDone()) {
336         StdFail_NotDone::Raise("Fuse operation can not be performed on the given shapes");
337       }
338       aShape = BO.Shape();
339     }
340
341     // perform SECTION operation
342     else if (aType == BOOLEAN_SECTION) {
343       BRep_Builder B;
344       TopoDS_Compound C;
345       B.MakeCompound(C);
346
347       TopTools_ListOfShape listShape1, listShape2;
348       AddSimpleShapes(aShape1, listShape1);
349       AddSimpleShapes(aShape2, listShape2);
350
351       Standard_Boolean isCompound =
352         (listShape1.Extent() > 1 || listShape2.Extent() > 1);
353
354       TopTools_ListIteratorOfListOfShape itSub1 (listShape1);
355       for (; itSub1.More(); itSub1.Next()) {
356         TopoDS_Shape aValue1 = itSub1.Value();
357         TopTools_ListIteratorOfListOfShape itSub2 (listShape2);
358         for (; itSub2.More(); itSub2.Next()) {
359           TopoDS_Shape aValue2 = itSub2.Value();
360           BRepAlgoAPI_Section BO (aValue1, aValue2, Standard_False);
361           // Set approximation to have an attached 3D BSpline geometry to each edge,
362           // where analytic curve is not possible. Without this flag in some cases
363           // we obtain BSpline curve of degree 1 (C0), which is slowly
364           // processed by some algorithms (Partition for example).
365           BO.Approximation(Standard_True);
366           BO.Build();
367           if (!BO.IsDone()) {
368             StdFail_NotDone::Raise("Section operation can not be performed on the given shapes");
369           }
370           if (isCompound) {
371             TopoDS_Shape aStepResult = BO.Shape();
372
373             // check result of this step: if it is a compound (boolean operations
374             // allways return a compound), we add all sub-shapes of it.
375             // This allows to avoid adding empty compounds,
376             // resulting from SECTION on two non-intersecting shapes.
377             if (aStepResult.ShapeType() == TopAbs_COMPOUND) {
378               TopoDS_Iterator aCompIter (aStepResult);
379               for (; aCompIter.More(); aCompIter.Next()) {
380                 // add shape in a result
381                 B.Add(C, aCompIter.Value());
382               }
383             }
384             else {
385               // add shape in a result
386               B.Add(C, aStepResult);
387             }
388           }
389           else
390             aShape = BO.Shape();
391         }
392       }
393
394       if (isCompound) {
395         //aShape = C;
396
397         // As GlueFaces has been improved to keep all kind of shapes
398         TopExp_Explorer anExp (C, TopAbs_VERTEX);
399         if (anExp.More())
400           aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
401         else
402           aShape = C;
403       }
404     }
405
406     // UNKNOWN operation
407     else {
408     }
409   }
410
411   if (aShape.IsNull()) return 0;
412
413   // 08.07.2008 skl for bug 19761 from Mantis
414   BRepCheck_Analyzer ana (aShape, Standard_True);
415   ana.Init(aShape);
416   if (!ana.IsValid()) {
417     ShapeFix_ShapeTolerance aSFT;
418     aSFT.LimitTolerance(aShape, Precision::Confusion(),
419                         Precision::Confusion(), TopAbs_SHAPE);
420     Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape(aShape);
421     aSfs->Perform();
422     aShape = aSfs->Shape();
423     ana.Init(aShape);
424     if (!ana.IsValid())
425       Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
426   }
427   //if (!BRepAlgo::IsValid(aShape)) {
428   //  Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
429   //}
430
431   aFunction->SetValue(aShape);
432
433   log.SetTouched(Label());
434
435   return 1;
436 }
437
438
439 //=======================================================================
440 //function :  GEOMImpl_BooleanDriver_Type_
441 //purpose  :
442 //=======================================================================
443 Standard_EXPORT Handle_Standard_Type& GEOMImpl_BooleanDriver_Type_()
444 {
445
446   static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver);
447   if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver);
448   static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared);
449   if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared);
450   static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient);
451   if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient);
452
453
454   static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL};
455   static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_BooleanDriver",
456                                                          sizeof(GEOMImpl_BooleanDriver),
457                                                          1,
458                                                          (Standard_Address)_Ancestors,
459                                                          (Standard_Address)NULL);
460
461   return _aType;
462 }
463
464 //=======================================================================
465 //function : DownCast
466 //purpose  :
467 //=======================================================================
468 const Handle(GEOMImpl_BooleanDriver) Handle(GEOMImpl_BooleanDriver)::DownCast(const Handle(Standard_Transient)& AnObject)
469 {
470   Handle(GEOMImpl_BooleanDriver) _anOtherObject;
471
472   if (!AnObject.IsNull()) {
473      if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_BooleanDriver))) {
474        _anOtherObject = Handle(GEOMImpl_BooleanDriver)((Handle(GEOMImpl_BooleanDriver)&)AnObject);
475      }
476   }
477
478   return _anOtherObject ;
479 }