1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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>
30 #include <TNaming_CopyShape.hxx>
32 #include <ShapeFix_ShapeTolerance.hxx>
33 #include <ShapeFix_Shape.hxx>
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>
43 #include <TopExp_Explorer.hxx>
44 #include <TopoDS_Compound.hxx>
45 #include <TopoDS_Iterator.hxx>
46 #include <TopTools_MapOfShape.hxx>
47 #include <TopTools_ListOfShape.hxx>
48 #include <TopTools_ListIteratorOfListOfShape.hxx>
50 #include <TColStd_IndexedDataMapOfTransientTransient.hxx>
52 #include <Precision.hxx>
54 #include <Standard_ConstructionError.hxx>
55 #include <StdFail_NotDone.hxx>
57 //=======================================================================
60 //=======================================================================
61 const Standard_GUID& GEOMImpl_BooleanDriver::GetID()
63 static Standard_GUID aBooleanDriver("FF1BBB21-5D14-4df2-980B-3A668264EA16");
64 return aBooleanDriver;
67 //=======================================================================
68 //function : GEOMImpl_BooleanDriver
70 //=======================================================================
71 GEOMImpl_BooleanDriver::GEOMImpl_BooleanDriver()
75 //=======================================================================
78 //=======================================================================
79 Standard_Integer GEOMImpl_BooleanDriver::Execute (TFunction_Logbook& log) const
81 if (Label().IsNull()) return 0;
82 Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
84 GEOMImpl_IBoolean aCI (aFunction);
85 Standard_Integer aType = aFunction->GetType();
95 Handle(GEOM_Function) aRefShape1 = aCI.GetShape1();
96 Handle(GEOM_Function) aRefShape2 = aCI.GetShape2();
97 TopoDS_Shape aShape1 = aRefShape1->GetValue();
98 TopoDS_Shape aShape2 = aRefShape2->GetValue();
100 if (!aShape1.IsNull() && !aShape2.IsNull()) {
101 // check arguments for Mantis issue 0021019
102 BRepCheck_Analyzer ana (aShape1, Standard_True);
104 StdFail_NotDone::Raise("Boolean operation will not be performed, because argument shape is not valid");
107 StdFail_NotDone::Raise("Boolean operation will not be performed, because argument shape is not valid");
109 aShape = performOperation (aShape1, aShape2, aType);
116 case BOOLEAN_COMMON_LIST:
117 case BOOLEAN_FUSE_LIST:
119 Handle(TColStd_HSequenceOfTransient) aShapes = aCI.GetShapes();
120 const Standard_Integer nbShapes = aShapes->Length();
122 Handle(GEOM_Function) aRefShape;
123 TopoDS_Shape aShape2;
124 Standard_Integer aSimpleType =
125 (aType == BOOLEAN_FUSE_LIST ? BOOLEAN_FUSE : BOOLEAN_COMMON);
128 aRefShape = Handle(GEOM_Function)::DownCast(aShapes->Value(1));
129 aShape = aRefShape->GetValue();
131 if (!aShape.IsNull()) {
132 BRepCheck_Analyzer anAna (aShape, Standard_True);
134 if (!anAna.IsValid()) {
135 StdFail_NotDone::Raise("Boolean operation will not be performed, because argument shape is not valid");
138 for (i = 2; i <= nbShapes; i++) {
139 aRefShape = Handle(GEOM_Function)::DownCast(aShapes->Value(i));
140 aShape2 = aRefShape->GetValue();
143 if (!anAna.IsValid()) {
144 StdFail_NotDone::Raise("Boolean operation will not be performed, because argument shape is not valid");
147 aShape = performOperation (aShape, aShape2, aSimpleType);
149 if (aShape.IsNull()) {
157 case BOOLEAN_CUT_LIST:
159 Handle(GEOM_Function) aRefObject = aCI.GetShape1();
161 aShape = aRefObject->GetValue();
163 if (!aShape.IsNull()) {
164 // check arguments for Mantis issue 0021019
165 BRepCheck_Analyzer anAna (aShape, Standard_True);
167 if (!anAna.IsValid()) {
168 StdFail_NotDone::Raise("Boolean operation will not be performed, because argument shape is not valid");
171 Handle(TColStd_HSequenceOfTransient) aTools = aCI.GetShapes();
172 const Standard_Integer nbShapes = aTools->Length();
174 Handle(GEOM_Function) aRefTool;
177 for (i = 1; i <= nbShapes; i++) {
178 aRefTool = Handle(GEOM_Function)::DownCast(aTools->Value(i));
179 aTool = aRefTool->GetValue();
182 if (!anAna.IsValid()) {
183 StdFail_NotDone::Raise("Boolean operation will not be performed, because argument shape is not valid");
186 aShape = performOperation (aShape, aTool, BOOLEAN_CUT);
188 if (aShape.IsNull()) {
199 aFunction->SetValue(aShape);
201 log.SetTouched(Label());
206 //=======================================================================
207 //function : performOperation
209 //=======================================================================
210 TopoDS_Shape GEOMImpl_BooleanDriver::performOperation
211 (const TopoDS_Shape theShape1,
212 const TopoDS_Shape theShape2,
213 const Standard_Integer theType)const
217 // perform COMMON operation
218 if (theType == BOOLEAN_COMMON) {
223 TopTools_ListOfShape listShape1, listShape2;
224 GEOMUtils::AddSimpleShapes(theShape1, listShape1);
225 GEOMUtils::AddSimpleShapes(theShape2, listShape2);
227 Standard_Boolean isCompound =
228 (listShape1.Extent() > 1 || listShape2.Extent() > 1);
230 TopTools_ListIteratorOfListOfShape itSub1 (listShape1);
231 for (; itSub1.More(); itSub1.Next()) {
232 TopoDS_Shape aValue1 = itSub1.Value();
233 TopTools_ListIteratorOfListOfShape itSub2 (listShape2);
234 for (; itSub2.More(); itSub2.Next()) {
235 TopoDS_Shape aValue2 = itSub2.Value();
236 BRepAlgoAPI_Common BO (aValue1, aValue2);
238 StdFail_NotDone::Raise("Common operation can not be performed on the given shapes");
241 TopoDS_Shape aStepResult = BO.Shape();
243 // check result of this step: if it is a compound (boolean operations
244 // allways return a compound), we add all sub-shapes of it.
245 // This allows to avoid adding empty compounds,
246 // resulting from COMMON on two non-intersecting shapes.
247 if (aStepResult.ShapeType() == TopAbs_COMPOUND) {
248 TopoDS_Iterator aCompIter (aStepResult);
249 for (; aCompIter.More(); aCompIter.Next()) {
250 // add shape in a result
251 B.Add(C, aCompIter.Value());
255 // add shape in a result
256 B.Add(C, aStepResult);
265 // As GlueFaces has been improved to keep all kind of shapes
266 TopExp_Explorer anExp (C, TopAbs_VERTEX);
268 aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
274 // perform CUT operation
275 else if (theType == BOOLEAN_CUT) {
280 TopTools_ListOfShape listShapes, listTools;
281 GEOMUtils::AddSimpleShapes(theShape1, listShapes);
282 GEOMUtils::AddSimpleShapes(theShape2, listTools);
284 Standard_Boolean isCompound = (listShapes.Extent() > 1);
286 TopTools_ListIteratorOfListOfShape itSub1 (listShapes);
287 for (; itSub1.More(); itSub1.Next()) {
288 TopoDS_Shape aCut = itSub1.Value();
290 TopTools_ListIteratorOfListOfShape itSub2 (listTools);
291 for (; itSub2.More(); itSub2.Next()) {
292 TopoDS_Shape aTool = itSub2.Value();
293 BRepAlgoAPI_Cut BO (aCut, aTool);
295 StdFail_NotDone::Raise("Cut operation can not be performed on the given shapes");
300 // check result of this step: if it is a compound (boolean operations
301 // allways return a compound), we add all sub-shapes of it.
302 // This allows to avoid adding empty compounds,
303 // resulting from CUT of parts
304 if (aCut.ShapeType() == TopAbs_COMPOUND) {
305 TopoDS_Iterator aCompIter (aCut);
306 for (; aCompIter.More(); aCompIter.Next()) {
307 // add shape in a result
308 B.Add(C, aCompIter.Value());
312 // add shape in a result
321 // As GlueFaces has been improved to keep all kind of shapes
322 TopExp_Explorer anExp (C, TopAbs_VERTEX);
324 aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
330 // perform FUSE operation
331 else if (theType == BOOLEAN_FUSE) {
333 BRepAlgoAPI_Fuse BO (theShape1, theShape2);
335 StdFail_NotDone::Raise("Fuse operation can not be performed on the given shapes");
340 // perform SECTION operation
341 else if (theType == BOOLEAN_SECTION) {
346 TopTools_ListOfShape listShape1, listShape2;
347 GEOMUtils::AddSimpleShapes(theShape1, listShape1);
348 GEOMUtils::AddSimpleShapes(theShape2, listShape2);
350 Standard_Boolean isCompound =
351 (listShape1.Extent() > 1 || listShape2.Extent() > 1);
353 TopTools_ListIteratorOfListOfShape itSub1 (listShape1);
354 for (; itSub1.More(); itSub1.Next()) {
355 TopoDS_Shape aValue1 = itSub1.Value();
356 TopTools_ListIteratorOfListOfShape itSub2 (listShape2);
357 for (; itSub2.More(); itSub2.Next()) {
358 TopoDS_Shape aValue2 = itSub2.Value();
359 BRepAlgoAPI_Section BO (aValue1, aValue2, Standard_False);
360 // Set approximation to have an attached 3D BSpline geometry to each edge,
361 // where analytic curve is not possible. Without this flag in some cases
362 // we obtain BSpline curve of degree 1 (C0), which is slowly
363 // processed by some algorithms (Partition for example).
364 BO.Approximation(Standard_True);
365 //modified by NIZNHY-PKV Tue Oct 18 14:34:16 2011f
366 BO.ComputePCurveOn1(Standard_True);
367 BO.ComputePCurveOn2(Standard_True);
368 //modified by NIZNHY-PKV Tue Oct 18 14:34:18 2011t
372 StdFail_NotDone::Raise("Section operation can not be performed on the given shapes");
375 TopoDS_Shape aStepResult = BO.Shape();
377 // check result of this step: if it is a compound (boolean operations
378 // allways return a compound), we add all sub-shapes of it.
379 // This allows to avoid adding empty compounds,
380 // resulting from SECTION on two non-intersecting shapes.
381 if (aStepResult.ShapeType() == TopAbs_COMPOUND) {
382 TopoDS_Iterator aCompIter (aStepResult);
383 for (; aCompIter.More(); aCompIter.Next()) {
384 // add shape in a result
385 B.Add(C, aCompIter.Value());
389 // add shape in a result
390 B.Add(C, aStepResult);
399 // As GlueFaces has been improved to keep all kind of shapes
400 TopExp_Explorer anExp (C, TopAbs_VERTEX);
402 aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
412 if (aShape.IsNull()) return aShape;
414 // as boolean operations always produce compound, lets simplify it
415 // for the case, if it contains only one sub-shape
416 TopTools_ListOfShape listShapeRes;
417 GEOMUtils::AddSimpleShapes(aShape, listShapeRes);
418 if (listShapeRes.Extent() == 1) {
419 aShape = listShapeRes.First();
420 if (aShape.IsNull()) return aShape;
423 // 08.07.2008 skl for bug 19761 from Mantis
424 BRepCheck_Analyzer ana (aShape, Standard_True);
426 if (!ana.IsValid()) {
427 ShapeFix_ShapeTolerance aSFT;
428 aSFT.LimitTolerance(aShape, Precision::Confusion(),
429 Precision::Confusion(), TopAbs_SHAPE);
430 Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape(aShape);
432 aShape = aSfs->Shape();
435 Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
438 // BEGIN: Mantis issue 0021060: always limit tolerance of BOP result
439 // 1. Get shape parameters for comparison
440 int nbTypes [TopAbs_SHAPE];
442 for (int iType = 0; iType < TopAbs_SHAPE; ++iType)
444 nbTypes[aShape.ShapeType()]++;
446 TopTools_MapOfShape aMapOfShape;
447 aMapOfShape.Add(aShape);
448 TopTools_ListOfShape aListOfShape;
449 aListOfShape.Append(aShape);
451 TopTools_ListIteratorOfListOfShape itL (aListOfShape);
452 for (; itL.More(); itL.Next()) {
453 TopoDS_Iterator it (itL.Value());
454 for (; it.More(); it.Next()) {
455 TopoDS_Shape s = it.Value();
456 if (aMapOfShape.Add(s)) {
457 aListOfShape.Append(s);
458 nbTypes[s.ShapeType()]++;
464 // 2. Limit tolerance
465 TopoDS_Shape aShapeCopy;
466 TColStd_IndexedDataMapOfTransientTransient aMapTShapes;
467 TNaming_CopyShape::CopyTool(aShape, aMapTShapes, aShapeCopy);
468 ShapeFix_ShapeTolerance aSFT;
469 aSFT.LimitTolerance(aShapeCopy, Precision::Confusion(), Precision::Confusion(), TopAbs_SHAPE);
470 Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape (aShapeCopy);
472 aShapeCopy = aSfs->Shape();
474 // 3. Check parameters
475 ana.Init(aShapeCopy);
477 int iType, nbTypesCopy [TopAbs_SHAPE];
479 for (iType = 0; iType < TopAbs_SHAPE; ++iType)
480 nbTypesCopy[iType] = 0;
481 nbTypesCopy[aShapeCopy.ShapeType()]++;
483 TopTools_MapOfShape aMapOfShape;
484 aMapOfShape.Add(aShapeCopy);
485 TopTools_ListOfShape aListOfShape;
486 aListOfShape.Append(aShapeCopy);
488 TopTools_ListIteratorOfListOfShape itL (aListOfShape);
489 for (; itL.More(); itL.Next()) {
490 TopoDS_Iterator it (itL.Value());
491 for (; it.More(); it.Next()) {
492 TopoDS_Shape s = it.Value();
493 if (aMapOfShape.Add(s)) {
494 aListOfShape.Append(s);
495 nbTypesCopy[s.ShapeType()]++;
501 for (iType = 0; iType < TopAbs_SHAPE && isEqual; ++iType) {
502 if (nbTypes[iType] != nbTypesCopy[iType])
508 // END: Mantis issue 0021060
513 //=======================================================================
514 //function : GEOMImpl_BooleanDriver_Type_
516 //=======================================================================
517 Standard_EXPORT Handle_Standard_Type& GEOMImpl_BooleanDriver_Type_()
519 static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver);
520 if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver);
521 static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared);
522 if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared);
523 static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient);
524 if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient);
526 static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL};
527 static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_BooleanDriver",
528 sizeof(GEOMImpl_BooleanDriver),
530 (Standard_Address)_Ancestors,
531 (Standard_Address)NULL);
536 //=======================================================================
537 //function : DownCast
539 //=======================================================================
540 const Handle(GEOMImpl_BooleanDriver) Handle(GEOMImpl_BooleanDriver)::DownCast(const Handle(Standard_Transient)& AnObject)
542 Handle(GEOMImpl_BooleanDriver) _anOtherObject;
544 if (!AnObject.IsNull()) {
545 if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_BooleanDriver))) {
546 _anOtherObject = Handle(GEOMImpl_BooleanDriver)((Handle(GEOMImpl_BooleanDriver)&)AnObject);
550 return _anOtherObject;