1 // Created on: 2009-05-05
2 // Created by: Sergey ZARITCHNY
3 // Copyright (c) 2009-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 #include <Adaptor3d_HCurve.hxx>
18 #include <BRepAdaptor_Surface.hxx>
19 #include <BRepAlgoAPI_BooleanOperation.hxx>
20 #include <BRepAlgoAPI_Common.hxx>
21 #include <BRepAlgoAPI_Cut.hxx>
22 #include <BRepAlgoAPI_Fuse.hxx>
23 #include <BRepAlgoAPI_Section.hxx>
24 #include <BRepCheck_Analyzer.hxx>
25 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
26 #include <BRepCheck_ListOfStatus.hxx>
27 #include <BRepCheck_Result.hxx>
28 #include <BRepLib.hxx>
29 #include <DNaming.hxx>
30 #include <DNaming_BooleanOperationDriver.hxx>
31 #include <GeomAbs_SurfaceType.hxx>
32 #include <ModelDefinitions.hxx>
33 #include <Precision.hxx>
34 #include <Standard_GUID.hxx>
35 #include <Standard_Real.hxx>
36 #include <Standard_Type.hxx>
37 #include <TDataStd_Integer.hxx>
38 #include <TDataStd_Real.hxx>
39 #include <TDF_Label.hxx>
40 #include <TFunction_Function.hxx>
41 #include <TFunction_Logbook.hxx>
42 #include <TNaming.hxx>
43 #include <TNaming_Builder.hxx>
44 #include <TNaming_NamedShape.hxx>
46 #include <TopExp_Explorer.hxx>
47 #include <TopLoc_Location.hxx>
49 #include <TopoDS_Iterator.hxx>
50 #include <TopoDS_Solid.hxx>
51 #include <TopoDS_Vertex.hxx>
52 #include <TopTools_IndexedMapOfShape.hxx>
53 #include <TopTools_ListIteratorOfListOfShape.hxx>
54 #include <TopTools_MapOfShape.hxx>
56 IMPLEMENT_STANDARD_RTTIEXT(DNaming_BooleanOperationDriver,TFunction_Driver)
58 static Standard_Boolean FixSameParameter(const TopoDS_Shape& theShape,
59 BRepCheck_Analyzer& theAnalyzer,
60 const Standard_Boolean bIgnoreNotSPErrors = Standard_False );
61 static void FindSPErrorEdges(const TopoDS_Shape& theShape,
62 const BRepCheck_Analyzer& theAnalyzer,
63 TopTools_IndexedMapOfShape& theMap);
65 static Standard_Boolean FindOtherErrors(const TopoDS_Shape& theShape,
66 const BRepCheck_Analyzer& theAnalyzer,
67 const TopTools_IndexedMapOfShape& theMap);
69 //=======================================================================
70 //function : DNaming_BooleanOperationDriver
71 //purpose : Constructor
72 //=======================================================================
73 DNaming_BooleanOperationDriver::DNaming_BooleanOperationDriver()
76 //=======================================================================
78 //purpose : Validates labels of a function in <log>.
79 //=======================================================================
80 void DNaming_BooleanOperationDriver::Validate(Handle(TFunction_Logbook)&) const
83 //=======================================================================
84 //function : MustExecute
85 //purpose : Analyse in <log> if the loaded function must be executed
86 //=======================================================================
87 Standard_Boolean DNaming_BooleanOperationDriver::MustExecute(const Handle(TFunction_Logbook)&) const
92 //=======================================================================
94 //purpose : Execute the function and push in <log> the impacted labels
95 //=======================================================================
96 Standard_Integer DNaming_BooleanOperationDriver::Execute(Handle(TFunction_Logbook)& theLog) const
98 Handle(TFunction_Function) aFunction;
99 Label().FindAttribute(TFunction_Function::GetID(),aFunction);
100 if(aFunction.IsNull()) return -1;
102 // Handle(TDataStd_UAttribute) anObject = DNaming::GetObjectFromFunction(aFunction);
103 // if(anObject.IsNull()) return -1;
104 // Handle(TNaming_NamedShape) anObjectNS = DNaming::GetObjectValue(anObject);
105 Handle(TFunction_Function) aPrevFun = DNaming::GetPrevFunction(aFunction);
106 if(aPrevFun.IsNull()) return -1;
107 const TDF_Label& aLab = RESPOSITION(aPrevFun);
108 Handle(TNaming_NamedShape) anObjectNS;
109 aLab.FindAttribute(TNaming_NamedShape::GetID(), anObjectNS);
110 if (anObjectNS.IsNull() || anObjectNS->IsEmpty()) {
112 std::cout<<"BooleanOperationDriver:: Object is empty"<<std::endl;
114 aFunction->SetFailure(WRONG_ARGUMENT);
118 Handle(TDataStd_UAttribute) aToolObj = DNaming::GetObjectArg(aFunction,BOOL_TOOL);
119 Handle(TNaming_NamedShape) aToolNS = DNaming::GetObjectValue(aToolObj);
121 if (aToolNS.IsNull() || aToolNS->IsEmpty()) {
123 std::cout<<"BooleanOperationDriver:: Tool is empty"<<std::endl;
125 aFunction->SetFailure(WRONG_ARGUMENT);
129 TopoDS_Shape aTOOL = aToolNS->Get();
130 TopoDS_Shape anOBJECT = anObjectNS->Get();
131 if (aTOOL.IsNull() || anOBJECT.IsNull()) {
133 std::cout<<"BooleanOperationDriver:: Tool is null"<<std::endl;
135 aFunction->SetFailure(WRONG_ARGUMENT);
139 Standard_Boolean anIsDone = Standard_False;
142 if(aFunction->GetDriverGUID() == FUSE_GUID){
143 BRepAlgoAPI_Fuse aMkFuse (anOBJECT, aTOOL);
144 anIsDone = CheckAndLoad(aMkFuse, aFunction);
147 else if(aFunction->GetDriverGUID() == CUT_GUID){
148 BRepAlgoAPI_Cut aMkCut (anOBJECT, aTOOL);
149 anIsDone = CheckAndLoad(aMkCut, aFunction);
152 else if(aFunction->GetDriverGUID() == COMMON_GUID){
153 BRepAlgoAPI_Common aMkCom (anOBJECT, aTOOL);
154 anIsDone = CheckAndLoad(aMkCom, aFunction);
157 else if(aFunction->GetDriverGUID() == SECTION_GUID){
158 BRepAlgoAPI_Section aMkSect (anOBJECT, aTOOL);
159 anIsDone = CheckAndLoad(aMkSect, aFunction);
162 aFunction->SetFailure(UNSUPPORTED_FUNCTION);
165 if(!anIsDone) return -1;
167 theLog->SetValid(RESPOSITION(aFunction),Standard_True);
168 aFunction->SetFailure(DONE);
173 //===================================================================
174 //=======================================================================
175 //function : ShapeType
177 //=======================================================================
179 static TopAbs_ShapeEnum ShapeType(const TopoDS_Shape& theShape) {
180 TopAbs_ShapeEnum TypeSh = theShape.ShapeType();
181 if (TypeSh == TopAbs_COMPOUND || TypeSh == TopAbs_COMPSOLID) {
182 TopoDS_Iterator itr(theShape);
183 if (!itr.More()) return TypeSh;
184 TypeSh = ShapeType(itr.Value());
185 if(TypeSh == TopAbs_COMPOUND) return TypeSh;
187 for(; itr.More(); itr.Next())
188 if(ShapeType(itr.Value()) != TypeSh) return TopAbs_COMPOUND;
192 //=====================================================================
193 static Standard_Boolean IsValidSurfType(const TopoDS_Face& theFace) {
194 BRepAdaptor_Surface anAdapt(theFace);
195 Handle( Adaptor3d_HCurve ) aBasisCurve;
196 const GeomAbs_SurfaceType& aType = anAdapt.GetType();
197 if(aType == GeomAbs_Sphere)
198 return Standard_True;
199 /* if(aType == GeomAbs_Cylinder || aType == GeomAbs_Cone || Type == GeomAbs_Sphere)
200 return Standard_True;
201 else if(aType == GeomAbs_SurfaceOfRevolution){
202 aBasisCurve = anAdapt.BasisCurve();
203 if (aBasisCurve->GetType() == GeomAbs_Line)
204 return Standard_True;
206 else if(aType == GeomAbs_SurfaceOfExtrusion) {
207 aBasisCurve = anAdapt.BasisCurve();
208 if (aBasisCurve->GetType() == GeomAbs_Circle || aBasisCurve->GetType() == GeomAbs_Ellipse)
209 return Standard_True;
213 //ModDbgTools_Write(theFace, "Surf");
215 return Standard_False;
217 //=======================================================================
218 //function : IsWRCase
220 //=======================================================================
222 static Standard_Boolean IsWRCase(const BRepAlgoAPI_BooleanOperation& MS) {
224 const TopoDS_Shape& ObjSh = MS.Shape1();
225 const TopoDS_Shape& ToolSh = MS.Shape2();
226 const TopAbs_ShapeEnum& Type1 = ShapeType(ObjSh);
227 if(Type1 == TopAbs_COMPOUND || Type1 > TopAbs_FACE) return Standard_False;
228 const TopAbs_ShapeEnum& Type2 = ShapeType(ToolSh);
229 if(Type2 == TopAbs_COMPOUND || Type2 > TopAbs_FACE) return Standard_False;
230 TopTools_ListOfShape aList;
232 if(Type1 != TopAbs_FACE) {
233 TopExp_Explorer anExp(ObjSh, TopAbs_FACE);
234 for(;anExp.More();anExp.Next()) {
235 if(IsValidSurfType(TopoDS::Face(anExp.Current())))
236 aList.Append(anExp.Current());
239 if(IsValidSurfType(TopoDS::Face(ObjSh)))
242 if(aList.Extent() == 0) {
243 if(Type2 != TopAbs_FACE) {
244 TopExp_Explorer anExp(ToolSh, TopAbs_FACE);
245 for(;anExp.More();anExp.Next()) {
246 if(IsValidSurfType(TopoDS::Face(anExp.Current())))
247 aList.Append(anExp.Current());
250 if(IsValidSurfType(TopoDS::Face(ToolSh)))
251 aList.Append(ToolSh);
253 if(aList.Extent() > 0) return Standard_True;
254 return Standard_False;
257 //=======================================================================
258 //function : LoadNamingDS
260 //=======================================================================
261 void DNaming_BooleanOperationDriver::LoadNamingDS (const TDF_Label& theResultLabel,
262 BRepAlgoAPI_BooleanOperation& MS) const
265 const TopoDS_Shape& ResSh = MS.Shape();
266 const TopoDS_Shape& ObjSh = MS.Shape1();
267 const TopoDS_Shape& ToolSh = MS.Shape2();
268 if (ResSh.IsNull()) {
270 std::cout<<"LoadFuseNamingDS: The result of the boolean operation is null"<<std::endl;
276 DNaming::LoadResult(theResultLabel, MS);
278 TopTools_DataMapOfShapeShape SubShapes;
279 TopExp_Explorer Exp(ResSh, TopAbs_FACE);
280 for (; Exp.More(); Exp.Next()) {
281 SubShapes.Bind(Exp.Current(),Exp.Current());
284 // Naming of modified faces:
285 TNaming_Builder modFB (theResultLabel.NewChild()); //FindChild(1,Standard_True));
286 DNaming::LoadAndOrientModifiedShapes (MS, ObjSh, TopAbs_FACE, modFB,SubShapes);
287 DNaming::LoadAndOrientModifiedShapes (MS, ToolSh, TopAbs_FACE, modFB, SubShapes);
289 // Naming of deleted faces:
291 TNaming_Builder delB (theResultLabel.NewChild()); // FindChild(2,Standard_True));
292 DNaming::LoadDeletedShapes (MS, ObjSh, TopAbs_FACE, delB);
293 DNaming::LoadDeletedShapes (MS, ToolSh, TopAbs_FACE, delB);
298 Exp.Init(ResSh, TopAbs_EDGE);
299 for (; Exp.More(); Exp.Next()) {
300 SubShapes.Bind(Exp.Current(),Exp.Current());
303 const TopTools_ListOfShape& aList = MS.SectionEdges();
304 Standard_Boolean theCase(Standard_False);
305 TopTools_MapOfShape aView;
306 if(aList.Extent() > 0 && aList.Extent() < 3)
307 theCase = Standard_True;
309 TopTools_ListIteratorOfListOfShape it(aList);
310 for(;it.More();it.Next()) {
311 TopoDS_Shape newShape = it.Value();
312 if (SubShapes.IsBound(newShape))
313 newShape.Orientation((SubShapes(newShape)).Orientation());
314 TNaming_Builder secED (theResultLabel.NewChild());
315 secED.Generated(newShape);
317 TopoDS_Vertex Vfirst, Vlast;
318 TopExp::Vertices(TopoDS::Edge(newShape), Vfirst, Vlast, Standard_True);
319 if(aView.Add(Vfirst)) {
320 TNaming_Builder secV (theResultLabel.NewChild());
321 secV.Generated(Vfirst);
323 if(aView.Add(Vlast)) {
324 TNaming_Builder secV (theResultLabel.NewChild());
325 secV.Generated(Vlast);
332 //=======================================================================
333 //function : LoadNamingDS
335 //=======================================================================
336 void DNaming_BooleanOperationDriver::LoadSectionNDS (const TDF_Label& theResultLabel,
337 BRepAlgoAPI_BooleanOperation& MS) const
340 const TopoDS_Shape& ResSh = MS.Shape();
341 const TopoDS_Shape& ObjSh = MS.Shape1();
342 const TopoDS_Shape& ToolSh = MS.Shape2();
343 if (ResSh.IsNull()) {
345 std::cout<<"LoadSectionNamingDS: The result of the boolean operation is null"<<std::endl;
351 DNaming::LoadResult(theResultLabel, MS);
353 TopTools_DataMapOfShapeShape SubShapes;
354 TopExp_Explorer Exp(ResSh, TopAbs_EDGE);
355 for (; Exp.More(); Exp.Next()) {
356 SubShapes.Bind(Exp.Current(),Exp.Current());
359 // Naming of modified faces:
360 TNaming_Builder genEdB (theResultLabel.NewChild()); //FindChild(1,Standard_True));
361 DNaming::LoadAndOrientGeneratedShapes (MS, ObjSh, TopAbs_FACE, genEdB,SubShapes);
362 DNaming::LoadAndOrientGeneratedShapes (MS, ToolSh, TopAbs_FACE, genEdB, SubShapes);
365 //=======================================================================
366 //function : CheckAndLoad
367 //purpose : checks result of operation and performs Topological Naming
368 //=======================================================================
369 Standard_Boolean DNaming_BooleanOperationDriver::CheckAndLoad
370 (BRepAlgoAPI_BooleanOperation& theMkOpe,
371 const Handle(TFunction_Function)& theFunction) const
374 if (theMkOpe.IsDone() && !theMkOpe.Shape().IsNull()) {
375 if (theMkOpe.Shape().ShapeType() == TopAbs_COMPOUND) {
376 if (theMkOpe.Shape().NbChildren() == 0) {
377 theFunction->SetFailure(NULL_RESULT);
378 return Standard_False;
381 BRepCheck_Analyzer aCheck (theMkOpe.Shape());
382 Standard_Boolean aResIsValid = Standard_True;
383 if(!aCheck.IsValid(theMkOpe.Shape()))
384 aResIsValid = FixSameParameter(theMkOpe.Shape(), aCheck);
386 if(theFunction->GetDriverGUID() == FUSE_GUID) {
387 LoadNamingDS(RESPOSITION(theFunction), theMkOpe);
389 else if(theFunction->GetDriverGUID() == CUT_GUID) {
390 LoadNamingDS(RESPOSITION(theFunction), theMkOpe); // the same naming only for case of solids
391 } else if(theFunction->GetDriverGUID() == COMMON_GUID) {
392 LoadNamingDS(RESPOSITION(theFunction), theMkOpe);
393 } else if(theFunction->GetDriverGUID() == SECTION_GUID) {
394 LoadSectionNDS(RESPOSITION(theFunction), theMkOpe);
397 theFunction->SetFailure(DONE);
398 return Standard_True;
400 theFunction->SetFailure(RESULT_NOT_VALID);
401 return Standard_False;
404 theFunction->SetFailure(ALGO_FAILED);
405 return Standard_False;
408 // ------------------------------------------------------------------------
409 // static function: FixSameParameter
411 // ------------------------------------------------------------------------
412 Standard_Boolean FixSameParameter(const TopoDS_Shape& theShape,
413 BRepCheck_Analyzer& theAnalyzer,
414 const Standard_Boolean bIgnoreNotSPErrors) {
416 Standard_Integer bDoFix = Standard_True;
417 TopTools_IndexedMapOfShape aMapE;
419 FindSPErrorEdges(theShape, theAnalyzer, aMapE);
421 if(!bIgnoreNotSPErrors) {
422 if(FindOtherErrors(theShape, theAnalyzer, aMapE)) {
423 bDoFix = Standard_False;
428 Standard_Integer i = 0;
430 for(i = 1; i <= aMapE.Extent(); i++) {
431 const TopoDS_Shape& aE = aMapE(i);
432 BRepLib::SameParameter(aE, Precision::Confusion(), Standard_True);
435 if(!aMapE.IsEmpty()) {
436 theAnalyzer.Init(theShape);
437 return theAnalyzer.IsValid();
440 return Standard_False;
443 // ------------------------------------------------------------------------
444 // static function: FindSPErrorEdges
446 // ------------------------------------------------------------------------
447 void FindSPErrorEdges(const TopoDS_Shape& theShape,
448 const BRepCheck_Analyzer& theAnalyzer,
449 TopTools_IndexedMapOfShape& theMap) {
450 BRepCheck_ListIteratorOfListOfStatus itl;
452 TopoDS_Iterator anIt(theShape);
454 for (; anIt.More(); anIt.Next()) {
455 FindSPErrorEdges(anIt.Value(), theAnalyzer, theMap);
458 if(theShape.ShapeType() == TopAbs_FACE) {
459 TopExp_Explorer anExpE(theShape, TopAbs_EDGE);
461 for(; anExpE.More(); anExpE.Next()) {
462 Handle(BRepCheck_Result) aResult = theAnalyzer.Result(anExpE.Current());
464 if(aResult.IsNull() || theMap.Contains(anExpE.Current()))
467 for (aResult->InitContextIterator();
468 aResult->MoreShapeInContext();
469 aResult->NextShapeInContext()) {
470 if (aResult->ContextualShape().IsSame(theShape)) {
471 itl.Initialize(aResult->StatusOnShape());
473 for(; itl.More(); itl.Next()) {
474 if((itl.Value() == BRepCheck_InvalidSameParameterFlag) ||
475 (itl.Value() == BRepCheck_InvalidCurveOnSurface)) {
476 theMap.Add(anExpE.Current());
484 else if(theShape.ShapeType() == TopAbs_EDGE) {
485 Handle(BRepCheck_Result) aResult = theAnalyzer.Result(theShape);
486 itl.Initialize(aResult->Status());
488 for(; itl.More(); itl.Next()) {
489 if((itl.Value() == BRepCheck_InvalidSameParameterFlag) ||
490 (itl.Value() == BRepCheck_InvalidCurveOnSurface)) {
491 theMap.Add(theShape);
498 // ------------------------------------------------------------------------
499 // static function: FindOtherErrors
501 // ------------------------------------------------------------------------
502 Standard_Boolean FindOtherErrors(const TopoDS_Shape& theShape,
503 const BRepCheck_Analyzer& theAnalyzer,
504 const TopTools_IndexedMapOfShape& theMap) {
506 Standard_Boolean bOtherFound = Standard_False;
507 BRepCheck_ListIteratorOfListOfStatus itl;
508 TopoDS_Iterator anIt(theShape);
510 for (; anIt.More(); anIt.Next()) {
511 if(FindOtherErrors(anIt.Value(), theAnalyzer, theMap))
512 return Standard_True;
514 Handle(BRepCheck_Result) aResult = theAnalyzer.Result(theShape);
516 if (!aResult.IsNull()) {
518 if(!theMap.Contains(theShape) && !aResult->Status().IsEmpty()) {
519 if(aResult->Status().First() != BRepCheck_NoError) {
520 bOtherFound = Standard_True;
523 TopExp_Explorer anExpF(theShape, TopAbs_FACE);
525 for(; anExpF.More(); anExpF.Next()) {
526 TopExp_Explorer anExpE(anExpF.Current(), TopAbs_EDGE);
528 for(; anExpE.More(); anExpE.Next()) {
529 Handle(BRepCheck_Result) aResultE = theAnalyzer.Result(anExpE.Current());
531 if(aResultE.IsNull())
533 bOtherFound = Standard_False;
535 for (aResultE->InitContextIterator();
536 aResultE->MoreShapeInContext();
537 aResultE->NextShapeInContext()) {
539 if (aResultE->ContextualShape().IsSame(anExpF.Current()) ||
540 aResultE->ContextualShape().IsSame(theShape)) {
541 itl.Initialize(aResultE->StatusOnShape());
546 if(itl.Value() != BRepCheck_NoError) {
547 if(theMap.Contains(anExpE.Current())) {
548 for(; itl.More(); itl.Next()) {
550 if((itl.Value() != BRepCheck_InvalidSameParameterFlag) &&
551 (itl.Value() != BRepCheck_InvalidCurveOnSurface) &&
552 (itl.Value() != BRepCheck_NoError)) {
553 return Standard_True;
558 return Standard_True;
568 for (aResult->InitContextIterator();
569 !bOtherFound && aResult->MoreShapeInContext();
570 aResult->NextShapeInContext()) {
571 if(!aResult->StatusOnShape().IsEmpty()) {
572 bOtherFound = (aResult->StatusOnShape().First() != BRepCheck_NoError);
578 TopAbs_ShapeEnum aType = theShape.ShapeType();
580 if((aType == TopAbs_VERTEX) ||
581 (aType == TopAbs_EDGE) ||
582 (aType == TopAbs_WIRE) ||
583 (aType == TopAbs_FACE) ||
584 (aType == TopAbs_SHELL)) {
585 for (aResult->InitContextIterator();
586 aResult->MoreShapeInContext();
587 aResult->NextShapeInContext()) {
588 if(!aResult->StatusOnShape().IsEmpty()) {
589 if(aResult->StatusOnShape().First() != BRepCheck_NoError) {
590 return Standard_True;
598 itl.Initialize(aResult->Status());
600 for(; itl.More(); itl.Next()) {
601 if((itl.Value() != BRepCheck_InvalidSameParameterFlag) &&
602 (itl.Value() != BRepCheck_InvalidCurveOnSurface) &&
603 (itl.Value() != BRepCheck_NoError)) {
604 return Standard_True;