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