bbc5b20572ab217ee14339cdae5d155bb6da9d0e
[occt.git] / src / DNaming / DNaming_BooleanOperationDriver.cxx
1 // Created on: 2009-05-05
2 // Created by: Sergey ZARITCHNY
3 // Copyright (c) 2009-2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20
21
22 #include <DNaming_BooleanOperationDriver.ixx>
23 #include <TFunction_Function.hxx>
24 #include <TDataStd_Real.hxx>
25 #include <TDataStd_Integer.hxx>
26 #include <TFunction_Logbook.hxx>
27 #include <TNaming.hxx>
28 #include <TNaming_NamedShape.hxx>
29 #include <BRepCheck_Analyzer.hxx>
30 #include <TopLoc_Location.hxx>
31 #include <TopoDS.hxx>
32 #include <TopoDS_Solid.hxx>
33 #include <TopoDS_Vertex.hxx>
34 #include <Standard_GUID.hxx>
35 #include <Standard_Real.hxx>
36 #include <TDF_Label.hxx>
37 #include <ModelDefinitions.hxx>
38
39 #include <DNaming.hxx>
40 #include <TNaming_Builder.hxx>
41 #include <BRepAlgoAPI_Fuse.hxx>
42 #include <BRepAlgoAPI_Cut.hxx>
43 #include <BRepAlgoAPI_Common.hxx>
44 #include <TopoDS_Iterator.hxx>
45 #include <TopTools_MapOfShape.hxx>
46 #include <TopExp_Explorer.hxx>
47 #include <TopExp.hxx>
48 #include <TopTools_ListIteratorOfListOfShape.hxx>
49 #include <TopTools_IndexedMapOfShape.hxx>
50 #include <BRepLib.hxx>
51 #include <Precision.hxx>
52 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
53 #include <BRepCheck_Result.hxx>
54 #include <BRepCheck_ListOfStatus.hxx>
55 #include <BRepAdaptor_Surface.hxx>
56 #include <Adaptor3d_HCurve.hxx>
57 #include <GeomAbs_SurfaceType.hxx>
58
59 static Standard_Boolean FixSameParameter(const TopoDS_Shape&    theShape,
60                                              BRepCheck_Analyzer&    theAnalyzer,
61                                              const Standard_Boolean bIgnoreNotSPErrors = Standard_False );
62 static void FindSPErrorEdges(const TopoDS_Shape&         theShape,
63                              const BRepCheck_Analyzer&   theAnalyzer,
64                              TopTools_IndexedMapOfShape& theMap);
65
66 static Standard_Boolean FindOtherErrors(const TopoDS_Shape&               theShape,
67                                         const BRepCheck_Analyzer&         theAnalyzer,
68                                         const TopTools_IndexedMapOfShape& theMap);
69
70 //=======================================================================
71 //function : DNaming_BooleanOperationDriver
72 //purpose  : Constructor
73 //=======================================================================
74 DNaming_BooleanOperationDriver::DNaming_BooleanOperationDriver()
75 {}
76
77 //=======================================================================
78 //function : Validate
79 //purpose  : Validates labels of a function in <log>.
80 //=======================================================================
81 void DNaming_BooleanOperationDriver::Validate(TFunction_Logbook& theLog) const
82 {}
83
84 //=======================================================================
85 //function : MustExecute
86 //purpose  : Analyse in <log> if the loaded function must be executed
87 //=======================================================================
88 Standard_Boolean DNaming_BooleanOperationDriver::MustExecute(const TFunction_Logbook& theLog) const
89 {
90   return Standard_True;
91 }
92
93 //=======================================================================
94 //function : Execute
95 //purpose  : Execute the function and push in <log> the impacted labels
96 //=======================================================================
97 Standard_Integer DNaming_BooleanOperationDriver::Execute(TFunction_Logbook& theLog) const
98 {
99   Handle(TFunction_Function) aFunction;
100   Label().FindAttribute(TFunction_Function::GetID(),aFunction);
101   if(aFunction.IsNull()) return -1;
102
103 //  Handle(TDataStd_UAttribute) anObject = DNaming::GetObjectFromFunction(aFunction);
104 //  if(anObject.IsNull()) return -1;
105 //  Handle(TNaming_NamedShape) anObjectNS = DNaming::GetObjectValue(anObject);
106   Handle(TFunction_Function) aPrevFun = DNaming::GetPrevFunction(aFunction);
107   if(aPrevFun.IsNull()) return -1;
108   const TDF_Label& aLab = RESPOSITION(aPrevFun);
109   Handle(TNaming_NamedShape) anObjectNS;
110   aLab.FindAttribute(TNaming_NamedShape::GetID(), anObjectNS);
111   if (anObjectNS.IsNull() || anObjectNS->IsEmpty()) {
112 #ifdef DEB
113     cout<<"BooleanOperationDriver:: Object is empty"<<endl;
114 #endif
115     aFunction->SetFailure(WRONG_ARGUMENT);
116     return -1;
117   }
118
119   Handle(TDataStd_UAttribute) aToolObj = DNaming::GetObjectArg(aFunction,BOOL_TOOL);
120   Handle(TNaming_NamedShape) aToolNS = DNaming::GetObjectValue(aToolObj);
121
122   if (aToolNS.IsNull() || aToolNS->IsEmpty()) {
123 #ifdef DEB
124     cout<<"BooleanOperationDriver:: Tool is empty"<<endl;
125 #endif
126     aFunction->SetFailure(WRONG_ARGUMENT);
127     return -1;
128   }
129
130   TopoDS_Shape aTOOL = aToolNS->Get();
131   TopoDS_Shape anOBJECT = anObjectNS->Get();
132   if (aTOOL.IsNull() || anOBJECT.IsNull()) {
133 #ifdef DEB
134     cout<<"BooleanOperationDriver:: Tool is null"<<endl;
135 #endif
136     aFunction->SetFailure(WRONG_ARGUMENT);
137     return -1;
138   }
139
140   Standard_Boolean anIsDone = Standard_False;
141
142   //case FUSE 
143   if(aFunction->GetDriverGUID() == FUSE_GUID){
144     BRepAlgoAPI_Fuse aMkFuse (anOBJECT, aTOOL);
145     anIsDone = CheckAndLoad(aMkFuse, aFunction);
146   }
147   //case CUT
148   else if(aFunction->GetDriverGUID() == CUT_GUID){
149     BRepAlgoAPI_Cut aMkCut (anOBJECT, aTOOL);    
150     anIsDone = CheckAndLoad(aMkCut, aFunction);
151   } 
152   // case COMMON
153   else if(aFunction->GetDriverGUID() == COMMON_GUID){
154     BRepAlgoAPI_Common aMkCom (anOBJECT, aTOOL);    
155     anIsDone = CheckAndLoad(aMkCom, aFunction);
156   }
157   else {
158     aFunction->SetFailure(UNSUPPORTED_FUNCTION);
159     return -1;
160   }
161   if(!anIsDone) return -1;
162   else {
163     theLog.SetValid(RESPOSITION(aFunction),Standard_True);  
164     aFunction->SetFailure(DONE);
165     return 0;
166   }
167
168 }
169 //===================================================================
170 //=======================================================================
171 //function : ShapeType
172 //purpose  :
173 //=======================================================================
174
175 static TopAbs_ShapeEnum ShapeType(const TopoDS_Shape& theShape) {
176   TopAbs_ShapeEnum TypeSh = theShape.ShapeType();
177   if (TypeSh == TopAbs_COMPOUND || TypeSh == TopAbs_COMPSOLID) {
178     TopoDS_Iterator itr(theShape);
179     if (!itr.More()) return TypeSh;
180     TypeSh = ShapeType(itr.Value());
181     if(TypeSh == TopAbs_COMPOUND) return TypeSh;
182     itr.Next();
183     for(; itr.More(); itr.Next())
184       if(ShapeType(itr.Value()) != TypeSh) return TopAbs_COMPOUND;
185   }
186   return TypeSh;
187 }
188 //=====================================================================
189 static Standard_Boolean IsValidSurfType(const TopoDS_Face& theFace) {
190   BRepAdaptor_Surface anAdapt(theFace);
191   Handle( Adaptor3d_HCurve ) aBasisCurve;
192   const GeomAbs_SurfaceType& aType = anAdapt.GetType();
193   if(aType == GeomAbs_Sphere)
194     return Standard_True;
195 /*  if(aType == GeomAbs_Cylinder || aType == GeomAbs_Cone || Type == GeomAbs_Sphere)
196     return Standard_True;
197   else if(aType == GeomAbs_SurfaceOfRevolution){
198     aBasisCurve = anAdapt.BasisCurve();
199     if (aBasisCurve->GetType() == GeomAbs_Line)
200       return Standard_True;
201   }
202   else if(aType == GeomAbs_SurfaceOfExtrusion) {
203     aBasisCurve = anAdapt.BasisCurve();
204     if (aBasisCurve->GetType() == GeomAbs_Circle || aBasisCurve->GetType() == GeomAbs_Ellipse)
205       return Standard_True;
206   }
207 */
208 #ifdef DEB
209   //ModDbgTools_Write(theFace, "Surf");
210 #endif
211   return Standard_False;
212 }
213 //=======================================================================
214 //function : IsWRCase
215 //purpose  :
216 //=======================================================================
217
218 static Standard_Boolean IsWRCase(const BRepAlgoAPI_BooleanOperation& MS) {
219
220   const TopoDS_Shape& ObjSh = MS.Shape1();
221   const TopoDS_Shape& ToolSh = MS.Shape2();
222   const TopAbs_ShapeEnum& Type1 = ShapeType(ObjSh);
223   if(Type1  == TopAbs_COMPOUND || Type1 > TopAbs_FACE) return Standard_False;
224   const TopAbs_ShapeEnum& Type2 = ShapeType(ToolSh);
225   if(Type2  == TopAbs_COMPOUND || Type2 > TopAbs_FACE) return Standard_False;
226   TopTools_ListOfShape aList;
227
228   if(Type1 != TopAbs_FACE) {
229     TopExp_Explorer anExp(ObjSh, TopAbs_FACE);
230     for(;anExp.More();anExp.Next()) {
231       if(IsValidSurfType(TopoDS::Face(anExp.Current())))
232         aList.Append(anExp.Current());
233     }
234   } else
235        if(IsValidSurfType(TopoDS::Face(ObjSh)))
236         aList.Append(ObjSh);
237
238   if(aList.Extent() == 0) {
239     if(Type2 != TopAbs_FACE) {
240       TopExp_Explorer anExp(ToolSh, TopAbs_FACE);
241       for(;anExp.More();anExp.Next()) {
242         if(IsValidSurfType(TopoDS::Face(anExp.Current())))
243           aList.Append(anExp.Current());
244       }
245     } else
246       if(IsValidSurfType(TopoDS::Face(ToolSh)))
247         aList.Append(ToolSh);
248   }
249   if(aList.Extent() > 0) return Standard_True;
250   return Standard_False;
251 }
252
253 //=======================================================================
254 //function : LoadNamingDS
255 //purpose  : 
256 //=======================================================================
257 void DNaming_BooleanOperationDriver::LoadNamingDS (const TDF_Label& theResultLabel, 
258                                            BRepAlgoAPI_BooleanOperation& MS) const
259 {
260
261   const TopoDS_Shape& ResSh = MS.Shape();
262   const TopoDS_Shape& ObjSh = MS.Shape1();
263   const TopoDS_Shape& ToolSh = MS.Shape2();
264  if (ResSh.IsNull()) {
265 #ifdef DEB
266    cout<<"LoadFuseNamingDS: The result of the boolean operation is null"<<endl;
267 #endif
268     return;
269   }
270
271   // LoadResult
272   DNaming::LoadResult(theResultLabel, MS);
273
274   TopTools_DataMapOfShapeShape SubShapes;
275   TopExp_Explorer Exp(ResSh, TopAbs_FACE);
276   for (; Exp.More(); Exp.Next()) {
277     SubShapes.Bind(Exp.Current(),Exp.Current());
278   }
279
280  // Naming of modified faces: 
281   TNaming_Builder modFB (theResultLabel.NewChild()); //FindChild(1,Standard_True)); 
282   DNaming::LoadAndOrientModifiedShapes (MS, ObjSh,  TopAbs_FACE, modFB,SubShapes);  
283   DNaming::LoadAndOrientModifiedShapes (MS, ToolSh, TopAbs_FACE, modFB, SubShapes);
284
285   // Naming of deleted faces:
286   if(MS.HasDeleted()){
287     TNaming_Builder delB (theResultLabel.NewChild());  // FindChild(2,Standard_True)); 
288     DNaming::LoadDeletedShapes  (MS, ObjSh,  TopAbs_FACE, delB);
289     DNaming::LoadDeletedShapes  (MS, ToolSh, TopAbs_FACE, delB);
290   }
291
292   if(IsWRCase(MS)) {
293   // Edges 
294     Exp.Init(ResSh, TopAbs_EDGE);
295     for (; Exp.More(); Exp.Next()) {
296       SubShapes.Bind(Exp.Current(),Exp.Current());
297     }
298   
299     const TopTools_ListOfShape& aList = MS.SectionEdges();
300     Standard_Boolean theCase(Standard_False);
301     TopTools_MapOfShape aView;
302     if(aList.Extent() > 0 && aList.Extent() < 3) 
303       theCase = Standard_True;
304     
305     TopTools_ListIteratorOfListOfShape it(aList);
306     for(;it.More();it.Next()) {
307       TopoDS_Shape newShape = it.Value();
308       if (SubShapes.IsBound(newShape)) 
309         newShape.Orientation((SubShapes(newShape)).Orientation());
310       TNaming_Builder secED (theResultLabel.NewChild());
311       secED.Generated(newShape);
312       if(theCase) {
313         TopoDS_Vertex Vfirst, Vlast;
314         TopExp::Vertices(TopoDS::Edge(newShape), Vfirst, Vlast, Standard_True);
315         if(aView.Add(Vfirst)) {
316           TNaming_Builder secV (theResultLabel.NewChild());
317           secV.Generated(Vfirst);
318         }
319         if(aView.Add(Vlast)) {
320           TNaming_Builder secV (theResultLabel.NewChild());
321           secV.Generated(Vlast);
322         }
323       }
324     }
325   }
326 }
327
328 //=======================================================================
329 //function : CheckAndLoad
330 //purpose  : checks result of operation and performs Topological Naming
331 //=======================================================================
332 Standard_Boolean DNaming_BooleanOperationDriver::CheckAndLoad
333   (BRepAlgoAPI_BooleanOperation& theMkOpe, 
334    const Handle(TFunction_Function)& theFunction) const
335 {
336
337   if (theMkOpe.IsDone() && !theMkOpe.Shape().IsNull()) {
338 #ifdef MDTV_DEB   
339     Standard_CString aFileName = "BoolOp.brep";
340     Write(theMkOpe.Shape(), aFileName);
341 #endif
342     if (theMkOpe.Shape().ShapeType() == TopAbs_COMPOUND) {
343       TopoDS_Iterator anItr(theMkOpe.Shape());
344       if(!anItr.More()) {
345         theFunction->SetFailure(NULL_RESULT);
346         return Standard_False;
347       }      
348     }
349     BRepCheck_Analyzer aCheck (theMkOpe.Shape());
350     Standard_Boolean aResIsValid = Standard_True;
351     if(!aCheck.IsValid(theMkOpe.Shape())) 
352       aResIsValid = FixSameParameter(theMkOpe.Shape(), aCheck);
353     if (aResIsValid) {
354       if(theFunction->GetDriverGUID() == FUSE_GUID) {
355         LoadNamingDS(RESPOSITION(theFunction), theMkOpe);
356       }
357       else if(theFunction->GetDriverGUID() == CUT_GUID) {
358         LoadNamingDS(RESPOSITION(theFunction), theMkOpe); // the same naming only for case of solids
359       } else if(theFunction->GetDriverGUID() == COMMON_GUID) {
360         LoadNamingDS(RESPOSITION(theFunction), theMkOpe); 
361       }
362       
363       theFunction->SetFailure(DONE);
364       return Standard_True;
365     } else {
366       theFunction->SetFailure(RESULT_NOT_VALID);
367       return Standard_False;
368     }
369   }
370   theFunction->SetFailure(ALGO_FAILED);
371   return Standard_False;
372 }
373
374 // ------------------------------------------------------------------------
375 // static function: FixSameParameter
376 // purpose:
377 // ------------------------------------------------------------------------
378 Standard_Boolean FixSameParameter(const TopoDS_Shape&    theShape,
379                                       BRepCheck_Analyzer&    theAnalyzer,
380                                       const Standard_Boolean bIgnoreNotSPErrors) {
381
382   Standard_Integer bDoFix = Standard_True;
383   TopTools_IndexedMapOfShape aMapE;
384
385   FindSPErrorEdges(theShape, theAnalyzer, aMapE);
386
387   if(!bIgnoreNotSPErrors) {
388     if(FindOtherErrors(theShape, theAnalyzer, aMapE)) {
389       bDoFix = Standard_False;
390     }
391   }
392
393   if(bDoFix) {
394     Standard_Integer i = 0;
395
396     for(i = 1; i <= aMapE.Extent(); i++) {
397       const TopoDS_Shape& aE = aMapE(i);
398       BRepLib::SameParameter(aE, Precision::Confusion(), Standard_True);
399     }
400
401     if(!aMapE.IsEmpty()) {
402       theAnalyzer.Init(theShape);
403       return theAnalyzer.IsValid();
404     }
405   }
406   return Standard_False;
407 }
408
409 // ------------------------------------------------------------------------
410 // static function: FindSPErrorEdges
411 // purpose:
412 // ------------------------------------------------------------------------
413 void FindSPErrorEdges(const TopoDS_Shape&         theShape,
414                       const BRepCheck_Analyzer&   theAnalyzer,
415                       TopTools_IndexedMapOfShape& theMap) {
416   BRepCheck_ListIteratorOfListOfStatus itl;
417
418   TopoDS_Iterator anIt(theShape);
419
420   for (; anIt.More(); anIt.Next()) {
421     FindSPErrorEdges(anIt.Value(), theAnalyzer, theMap);
422   }
423
424   if(theShape.ShapeType() == TopAbs_FACE) {
425     TopExp_Explorer anExpE(theShape, TopAbs_EDGE);
426     
427     for(; anExpE.More(); anExpE.Next()) {
428       Handle(BRepCheck_Result) aResult = theAnalyzer.Result(anExpE.Current());
429
430       if(aResult.IsNull() || theMap.Contains(anExpE.Current()))
431         continue;
432
433       for (aResult->InitContextIterator();
434            aResult->MoreShapeInContext(); 
435            aResult->NextShapeInContext()) {
436         if (aResult->ContextualShape().IsSame(theShape)) {
437           itl.Initialize(aResult->StatusOnShape());
438
439           for(; itl.More(); itl.Next()) {
440             if((itl.Value() == BRepCheck_InvalidSameParameterFlag) ||
441                (itl.Value() == BRepCheck_InvalidCurveOnSurface)) {
442               theMap.Add(anExpE.Current());
443               break;
444             }
445           }
446         }
447       }
448     }
449   }
450   else if(theShape.ShapeType() == TopAbs_EDGE) {
451     Handle(BRepCheck_Result) aResult = theAnalyzer.Result(theShape);
452     itl.Initialize(aResult->Status());
453     
454     for(; itl.More(); itl.Next()) {
455       if((itl.Value() == BRepCheck_InvalidSameParameterFlag) ||
456          (itl.Value() == BRepCheck_InvalidCurveOnSurface)) {
457         theMap.Add(theShape);
458         break;
459       }
460     }
461   }
462 }
463
464 // ------------------------------------------------------------------------
465 // static function: FindOtherErrors
466 // purpose:
467 // ------------------------------------------------------------------------
468 Standard_Boolean FindOtherErrors(const TopoDS_Shape&               theShape,
469                                  const BRepCheck_Analyzer&         theAnalyzer,
470                                  const TopTools_IndexedMapOfShape& theMap) {
471
472   Standard_Boolean bOtherFound = Standard_False;
473   BRepCheck_ListIteratorOfListOfStatus itl;
474   TopoDS_Iterator anIt(theShape);
475   
476   for (; anIt.More(); anIt.Next()) {
477     if(FindOtherErrors(anIt.Value(), theAnalyzer, theMap))
478       return Standard_True;
479   }
480   Handle(BRepCheck_Result) aResult = theAnalyzer.Result(theShape);
481   
482   if (!aResult.IsNull()) {
483
484     if(!theMap.Contains(theShape) && !aResult->Status().IsEmpty()) {
485       if(aResult->Status().First() != BRepCheck_NoError) {
486         bOtherFound = Standard_True;
487
488         //
489         TopExp_Explorer anExpF(theShape, TopAbs_FACE);
490
491         for(; anExpF.More(); anExpF.Next()) {
492           TopExp_Explorer anExpE(anExpF.Current(), TopAbs_EDGE);
493
494           for(; anExpE.More(); anExpE.Next()) {
495             Handle(BRepCheck_Result) aResultE = theAnalyzer.Result(anExpE.Current());
496
497             if(aResultE.IsNull())
498               continue;
499             bOtherFound = Standard_False;
500
501             for (aResultE->InitContextIterator();
502                  aResultE->MoreShapeInContext(); 
503                  aResultE->NextShapeInContext()) {
504
505               if (aResultE->ContextualShape().IsSame(anExpF.Current()) ||
506                   aResultE->ContextualShape().IsSame(theShape)) {
507                 itl.Initialize(aResultE->StatusOnShape());
508
509                 if(!itl.More())
510                   continue;
511
512                 if(itl.Value() != BRepCheck_NoError) {
513                   if(theMap.Contains(anExpE.Current())) {
514                     for(; itl.More(); itl.Next()) {
515
516                       if((itl.Value() != BRepCheck_InvalidSameParameterFlag) &&
517                          (itl.Value() != BRepCheck_InvalidCurveOnSurface) &&
518                          (itl.Value() != BRepCheck_NoError)) {
519                         return Standard_True;
520                       }
521                     }
522                   }
523                   else {
524                     return Standard_True;
525                   }
526                 }
527               }
528             }
529           }
530         }
531         // 
532
533         if(!bOtherFound) {
534           for (aResult->InitContextIterator(); 
535                !bOtherFound && aResult->MoreShapeInContext(); 
536                aResult->NextShapeInContext()) {
537             if(!aResult->StatusOnShape().IsEmpty()) {
538               bOtherFound = (aResult->StatusOnShape().First() != BRepCheck_NoError);
539             }
540           }
541         }
542       }
543       else {
544         TopAbs_ShapeEnum aType = theShape.ShapeType();
545
546         if((aType == TopAbs_VERTEX) ||
547            (aType == TopAbs_EDGE) ||
548            (aType == TopAbs_WIRE) ||
549            (aType == TopAbs_FACE) ||
550            (aType == TopAbs_SHELL)) {
551           for (aResult->InitContextIterator();
552                aResult->MoreShapeInContext(); 
553                aResult->NextShapeInContext()) {
554             if(!aResult->StatusOnShape().IsEmpty()) {
555               if(aResult->StatusOnShape().First() != BRepCheck_NoError) {
556                 return Standard_True;
557               }
558             }
559           }
560         }
561       }
562     }
563     else {
564       itl.Initialize(aResult->Status());
565       
566       for(; itl.More(); itl.Next()) {
567         if((itl.Value() != BRepCheck_InvalidSameParameterFlag) &&
568            (itl.Value() != BRepCheck_InvalidCurveOnSurface) &&
569            (itl.Value() != BRepCheck_NoError)) {
570           return Standard_True;
571         }
572       }
573     }
574   }
575   
576   return bOtherFound;
577 }