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