Salome HOME
0021031: EDF 1646 GEOM: Modify Location leads to Position driver failed
[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
23 #include <GEOMImpl_BooleanDriver.hxx>
24 #include <GEOMImpl_IBoolean.hxx>
25 #include <GEOMImpl_Types.hxx>
26 #include <GEOMImpl_GlueDriver.hxx>
27 #include <GEOM_Function.hxx>
28
29 #include <BRep_Builder.hxx>
30 #include <BRepAlgo.hxx>
31 #include <BRepAlgoAPI_Common.hxx>
32 #include <BRepAlgoAPI_Cut.hxx>
33 #include <BRepAlgoAPI_Fuse.hxx>
34 #include <BRepAlgoAPI_Section.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TopoDS_Shape.hxx>
37 #include <TopoDS_Compound.hxx>
38 #include <TopoDS_Iterator.hxx>
39 #include <TopTools_MapOfShape.hxx>
40 #include <TopTools_ListOfShape.hxx>
41 #include <TopTools_ListIteratorOfListOfShape.hxx>
42 #include <Precision.hxx>
43 #include <BRepCheck_Analyzer.hxx>
44 #include <ShapeFix_ShapeTolerance.hxx>
45 #include <ShapeFix_Shape.hxx>
46
47 #include <Standard_ConstructionError.hxx>
48 #include <StdFail_NotDone.hxx>
49
50 //=======================================================================
51 //function : GetID
52 //purpose  :
53 //=======================================================================
54 const Standard_GUID& GEOMImpl_BooleanDriver::GetID()
55 {
56   static Standard_GUID aBooleanDriver("FF1BBB21-5D14-4df2-980B-3A668264EA16");
57   return aBooleanDriver;
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   // as boolean operations always produce compound, lets simplify it
414   // for the case, if it contans only one sub-shape
415   TopTools_ListOfShape listShapeRes;
416   AddSimpleShapes(aShape, listShapeRes);
417   if (listShapeRes.Extent() == 1) {
418     aShape = listShapeRes.First();
419     if (aShape.IsNull()) return 0;
420   }
421
422   // 08.07.2008 skl for bug 19761 from Mantis
423   BRepCheck_Analyzer ana (aShape, Standard_True);
424   ana.Init(aShape);
425   if (!ana.IsValid()) {
426     ShapeFix_ShapeTolerance aSFT;
427     aSFT.LimitTolerance(aShape, Precision::Confusion(),
428                         Precision::Confusion(), TopAbs_SHAPE);
429     Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape(aShape);
430     aSfs->Perform();
431     aShape = aSfs->Shape();
432     ana.Init(aShape);
433     if (!ana.IsValid())
434       Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
435   }
436   //if (!BRepAlgo::IsValid(aShape)) {
437   //  Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
438   //}
439
440   //Alternative case to check shape result Mantis 0020604: EDF 1172
441 /*  TopoDS_Iterator It (aShape, Standard_True, Standard_True);
442   int nbSubshapes=0;
443   for (; It.More(); It.Next())
444     nbSubshapes++;
445   if (!nbSubshapes)
446     Standard_ConstructionError::Raise("Boolean operation aborted : result object is empty compound");*/
447   //end of 0020604: EDF 1172
448   //! the changes temporary commented because of customer needs (see the same mantis bug)
449
450   aFunction->SetValue(aShape);
451
452   log.SetTouched(Label());
453
454   return 1;
455 }
456
457
458 //=======================================================================
459 //function :  GEOMImpl_BooleanDriver_Type_
460 //purpose  :
461 //=======================================================================
462 Standard_EXPORT Handle_Standard_Type& GEOMImpl_BooleanDriver_Type_()
463 {
464
465   static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver);
466   if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver);
467   static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared);
468   if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared);
469   static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient);
470   if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient);
471
472
473   static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL};
474   static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_BooleanDriver",
475                                                          sizeof(GEOMImpl_BooleanDriver),
476                                                          1,
477                                                          (Standard_Address)_Ancestors,
478                                                          (Standard_Address)NULL);
479
480   return _aType;
481 }
482
483 //=======================================================================
484 //function : DownCast
485 //purpose  :
486 //=======================================================================
487 const Handle(GEOMImpl_BooleanDriver) Handle(GEOMImpl_BooleanDriver)::DownCast(const Handle(Standard_Transient)& AnObject)
488 {
489   Handle(GEOMImpl_BooleanDriver) _anOtherObject;
490
491   if (!AnObject.IsNull()) {
492      if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_BooleanDriver))) {
493        _anOtherObject = Handle(GEOMImpl_BooleanDriver)((Handle(GEOMImpl_BooleanDriver)&)AnObject);
494      }
495   }
496
497   return _anOtherObject ;
498 }