0022967: Boolean operations between two cylinders with orthogonal axis generate a...
[occt.git] / src / BOP / BOP_ArgumentAnalyzer.cxx
1 // File:      BOP_ArgumentAnalyzer.cxx
2 // Created:   02.09.04 16:26:31
3 // Copyright: Open Cascade 2004
4
5 #include <BOP_ArgumentAnalyzer.ixx>
6 #include <BOP_CheckResult.hxx>
7 #include <BOP_ShellSolid.hxx>
8 #include <BOP_WireSolid.hxx>
9 #include <BOP_WireShell.hxx>
10 #include <BOP_WireEdgeSet.hxx>
11 #include <BOP_FaceBuilder.hxx>
12
13 #include <TopExp.hxx>
14 #include <TopExp_Explorer.hxx>
15 #include <BRep_Builder.hxx>
16 #include <BRep_Tool.hxx>
17 #include <BRepExtrema_DistShapeShape.hxx>
18 #include <gp_Pnt.hxx>
19 #include <TopoDS_Iterator.hxx>
20 #include <TopoDS.hxx>
21 #include <TopoDS_Vertex.hxx>
22 #include <TopoDS_Edge.hxx>
23 #include <TopoDS_Wire.hxx>
24 #include <TopoDS_Shell.hxx>
25 #include <TopoDS_Solid.hxx>
26 #include <TopTools_ListOfShape.hxx>
27 #include <TopTools_ListIteratorOfListOfShape.hxx>
28 #include <TopTools_SequenceOfShape.hxx>
29 #include <TopTools_MapOfShape.hxx>
30
31 #include <TColStd_Array2OfBoolean.hxx>
32
33 #include <IntTools_Context.hxx>
34 #include <IntTools_Range.hxx>
35 #include <IntTools_ShrunkRange.hxx>
36 #include <IntTools_EdgeEdge.hxx>
37 #include <IntTools_CommonPrt.hxx>
38
39 #include <BOPTools_DSFiller.hxx>
40 #include <BOPTools_Tools3D.hxx>
41 #include <BOPTools_Checker.hxx>
42 #include <BOPTools_CheckResult.hxx>
43 #include <BOPTools_ListOfCheckResults.hxx>
44 #include <BOPTools_ListIteratorOfListOfCheckResults.hxx>
45
46 #include <Standard_ErrorHandler.hxx>
47 #include <Standard_Failure.hxx>
48
49 static Standard_Boolean TestShapeType(const TopoDS_Shape & TheShape);
50
51 static Standard_Boolean CheckEdge(const TopoDS_Edge& theEdge);
52
53 static Standard_Boolean TestSubShapeType(const TopAbs_ShapeEnum theT1,
54                                          const TopAbs_ShapeEnum theT2,
55                                          const BOP_Operation    theOP);
56
57 // ================================================================================
58 // function: Constructor
59 // purpose:
60 // ================================================================================
61 BOP_ArgumentAnalyzer::BOP_ArgumentAnalyzer() : 
62 myStopOnFirst(Standard_False),
63 myOperation(BOP_UNKNOWN),
64 myArgumentTypeMode(Standard_False),
65 mySelfInterMode(Standard_False),
66 mySmallEdgeMode(Standard_False),
67 myRebuildFaceMode(Standard_False),
68 myTangentMode(Standard_False),
69 myMergeVertexMode(Standard_False),
70 myMergeEdgeMode(Standard_False)
71 // myMergeFaceMode(Standard_False)
72 {
73 }
74
75 // ================================================================================
76 // function: SetShape1
77 // purpose:
78 // ================================================================================
79 void BOP_ArgumentAnalyzer::SetShape1(const TopoDS_Shape & TheShape)
80 {
81   myShape1 = TheShape;
82 }
83
84 // ================================================================================
85 // function: SetShape2
86 // purpose:
87 // ================================================================================
88 void BOP_ArgumentAnalyzer::SetShape2(const TopoDS_Shape & TheShape)
89 {
90   myShape2 = TheShape;
91 }
92
93 // ================================================================================
94 // function: GetShape1
95 // purpose:
96 // ================================================================================
97 const TopoDS_Shape & BOP_ArgumentAnalyzer::GetShape1() const
98 {
99   return myShape1;
100 }
101
102 // ================================================================================
103 // function: GetShape2
104 // purpose:
105 // ================================================================================
106 const TopoDS_Shape & BOP_ArgumentAnalyzer::GetShape2() const
107 {
108   return myShape2;
109 }
110
111 // ================================================================================
112 // function: OperationType
113 // purpose:
114 // ================================================================================
115 BOP_Operation& BOP_ArgumentAnalyzer::OperationType() 
116 {
117   return myOperation;
118 }
119
120 // ================================================================================
121 // function: StopOnFirstFaulty
122 // purpose:
123 // ================================================================================
124 Standard_Boolean & BOP_ArgumentAnalyzer::StopOnFirstFaulty()
125 {
126   return myStopOnFirst;
127 }
128
129 // ================================================================================
130 // function: Perform
131 // purpose:
132 // ================================================================================
133 void BOP_ArgumentAnalyzer::Perform()
134 {
135   try {
136     OCC_CATCH_SIGNALS
137     myResult.Clear();
138
139     if(myArgumentTypeMode) {
140       TestTypes();
141     }
142
143     if(mySelfInterMode) {
144       TestSelfInterferences();
145     }
146
147     if(mySmallEdgeMode) {
148       if(!(!myResult.IsEmpty() && myStopOnFirst))
149         TestSmallEdge();
150     }
151
152     if(myRebuildFaceMode) {
153       if(!(!myResult.IsEmpty() && myStopOnFirst))
154         TestRebuildFace();
155     }
156
157     if(myTangentMode) {
158       if(!(!myResult.IsEmpty() && myStopOnFirst))
159         TestTangent();
160     }
161
162     if(myMergeVertexMode) {
163       if(!(!myResult.IsEmpty() && myStopOnFirst))
164         TestMergeVertex();
165     }
166     
167     if(myMergeEdgeMode) {
168       if(!(!myResult.IsEmpty() && myStopOnFirst))
169         TestMergeEdge();
170     }
171     
172 //     if(myMergeFaceMode) {
173 //       TestMergeFace();
174 //     }
175   }
176   catch(Standard_Failure) {
177     BOP_CheckResult aResult;
178     aResult.SetCheckStatus(BOP_CheckUnknown);
179     myResult.Append(aResult);
180   }
181 }
182
183 // ================================================================================
184 // function: HasFaulty
185 // purpose:
186 // ================================================================================
187 Standard_Boolean BOP_ArgumentAnalyzer::HasFaulty() const
188 {
189   return ( !myResult.IsEmpty());
190 }
191
192 // ================================================================================
193 // function: GetCheckResult
194 // purpose:
195 // ================================================================================
196 const BOP_ListOfCheckResult& BOP_ArgumentAnalyzer::GetCheckResult() const
197 {
198   return myResult;
199 }
200
201 // ================================================================================
202 // function: TestTypes
203 // purpose:
204 // ================================================================================
205 void BOP_ArgumentAnalyzer::TestTypes()
206 {
207   Standard_Boolean isS1 = myShape1.IsNull(), isS2 = myShape2.IsNull();
208
209   if(isS1 && isS2) {
210     BOP_CheckResult aResult;
211     aResult.SetCheckStatus(BOP_BadType);
212     myResult.Append(aResult);
213     return;
214   }
215
216   Standard_Boolean testS1 = TestShapeType(myShape1);
217   Standard_Boolean testS2 = TestShapeType(myShape2);
218
219   // single shape check (begin)
220   if((isS1 && !isS2) || (!isS1 && isS2)) {
221 //     Standard_Boolean testS = (isS1) ? testS1 : testS2;
222     Standard_Boolean testS = (isS1) ? testS2 : testS1;
223
224     if(!testS) {
225       const TopoDS_Shape & aS = (isS1) ? myShape1 : myShape2;
226       BOP_CheckResult aResult;
227       aResult.SetShape1(aS);
228       aResult.SetCheckStatus(BOP_BadType);
229       myResult.Append(aResult);
230       return;
231     }
232     
233   } // single shape is set (end)
234   // two shapes check (begin)
235   else {
236     // test compounds and compsolids
237     if(!testS1 || !testS2) {
238       BOP_CheckResult aResult;
239       if(!testS1 && !testS2) {
240         aResult.SetShape1(myShape1);
241         aResult.SetShape2(myShape2);
242       }
243       else {
244         const TopoDS_Shape & aS = (!testS1) ? myShape1 : myShape2;
245         if(!testS1)
246           aResult.SetShape1(aS);
247         else
248           aResult.SetShape2(aS);
249       }
250       aResult.SetCheckStatus(BOP_BadType);
251       myResult.Append(aResult);
252       return;
253     }
254     // test faces, wires, edges
255     TopAbs_ShapeEnum aT1 = myShape1.ShapeType(), aT2 = myShape2.ShapeType();
256
257     if(aT1 != TopAbs_COMPOUND && aT2 != TopAbs_COMPOUND) {
258       Standard_Boolean aTestRes = TestSubShapeType(aT1,aT2,myOperation);
259       if(!aTestRes) {
260         BOP_CheckResult aResult;
261         aResult.SetShape1(myShape1);
262         aResult.SetShape2(myShape2);
263         aResult.SetCheckStatus(BOP_BadType);
264         myResult.Append(aResult);
265         return;
266       }
267     }
268     else {
269       Standard_Boolean aTestRes = Standard_True;
270       if(aT1 == TopAbs_COMPOUND && aT2 != TopAbs_COMPOUND) {
271         TopoDS_Iterator itS1(myShape1);
272         while(itS1.More()) {
273           aT1 = itS1.Value().ShapeType();
274           aTestRes = TestSubShapeType(aT1,aT2,myOperation);
275           if(!aTestRes)
276             break;
277           itS1.Next();
278         }
279       }
280       else if(aT1 != TopAbs_COMPOUND && aT2 == TopAbs_COMPOUND) {
281         TopoDS_Iterator itS2(myShape2);
282         while(itS2.More()) {
283           aT2 = itS2.Value().ShapeType();
284           aTestRes = TestSubShapeType(aT1,aT2,myOperation);
285           if(!aTestRes)
286             break;
287           itS2.Next();
288         }
289       }
290       else {
291         TopoDS_Iterator itS1(myShape1);
292         while(itS1.More()) {
293           aT1 = itS1.Value().ShapeType();
294           TopoDS_Iterator itS2(myShape2);
295           while(itS2.More()) {
296             aT2 = itS2.Value().ShapeType();
297             aTestRes = TestSubShapeType(aT1,aT2,myOperation);
298             if(!aTestRes)
299               break;
300             itS2.Next();
301           }
302           if(!aTestRes)
303             break;
304           itS1.Next();
305         }
306       }
307
308       if(!aTestRes) {
309         BOP_CheckResult aResult;
310         aResult.SetShape1(myShape1);
311         aResult.SetShape2(myShape2);
312         aResult.SetCheckStatus(BOP_BadType);
313         myResult.Append(aResult);
314         return;
315       }
316     }
317   } // both shapes are set (end)
318 }
319
320 // ================================================================================
321 // function: TestSelfInterferences
322 // purpose:
323 // ================================================================================
324 void BOP_ArgumentAnalyzer::TestSelfInterferences()
325 {
326   Standard_Integer i = 0;
327
328   for(i = 0; i < 2; i++) {
329     TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2;
330
331     if(aS.IsNull())
332       continue;
333     BOPTools_Checker aChecker(aS);
334     aChecker.Perform();
335
336     if (aChecker.HasFaulty()) {
337       const BOPTools_ListOfCheckResults& aResultList = aChecker.GetCheckResult();
338       BOPTools_ListIteratorOfListOfCheckResults anIt(aResultList);
339
340       for(; anIt.More(); anIt.Next()) {
341         const BOPTools_CheckResult& aCheckResult = anIt.Value();
342
343         if((aCheckResult.GetCheckStatus() == BOPTools_CHKUNKNOWN) ||
344            (aCheckResult.GetCheckStatus() == BOPTools_BADSHRANKRANGE) ||
345            (aCheckResult.GetCheckStatus() == BOPTools_NULLSRANKRANGE)) {
346           continue;
347         }
348         BOP_CheckResult aResult;
349         if(i == 0)
350           aResult.SetShape1(myShape1);
351         else
352           aResult.SetShape2(myShape2);
353         TopTools_ListIteratorOfListOfShape anIt2(aCheckResult.GetShapes());
354
355         for(; anIt2.More(); anIt2.Next()) {
356           if(i == 0)
357             aResult.AddFaultyShape1(anIt2.Value());
358           else
359             aResult.AddFaultyShape2(anIt2.Value());
360         }
361         aResult.SetCheckStatus(BOP_SelfIntersect);
362         myResult.Append(aResult);
363
364         if(myStopOnFirst) {
365           return;
366         }
367       }
368     }
369   }
370 }
371
372 // ================================================================================
373 // function: TestSmallEdge
374 // purpose:
375 // ================================================================================
376 void BOP_ArgumentAnalyzer::TestSmallEdge() 
377 {
378   Standard_Integer i = 0;
379   BRepExtrema_DistShapeShape aDist;
380
381   for(i = 0; i < 2; i++) {
382     TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2;
383
384     if(aS.IsNull())
385       continue;
386
387     TopExp_Explorer anExp(aS, TopAbs_EDGE);
388
389     for(; anExp.More(); anExp.Next()) {
390       TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current());
391
392       if(!CheckEdge(anEdge)) {
393         Standard_Boolean bKeepResult = Standard_True;
394
395         if(myOperation == BOP_SECTION) {
396           TopoDS_Shape anOtherS = (i == 0) ? myShape2 : myShape1;
397           
398           if(!anOtherS.IsNull()) {
399 //          BRepExtrema_DistShapeShape aDist;
400             aDist.LoadS2(anOtherS);
401             
402             Standard_Boolean bVertexIsOnShape = Standard_False;
403             Standard_Integer ii = 0;
404             TopExp_Explorer anExpV(anEdge, TopAbs_VERTEX);
405             
406             for(; anExpV.More(); anExpV.Next()) {
407               TopoDS_Shape aV = anExpV.Current();
408
409               aDist.LoadS1(aV);
410               aDist.Perform();
411
412               if(aDist.IsDone()) {
413
414                 for(ii = 1; ii <= aDist.NbSolution(); ii++) {
415                   Standard_Real aTolerance = BRep_Tool::Tolerance(TopoDS::Vertex(aV));
416                   TopoDS_Shape aSupportShape = aDist.SupportOnShape2(ii);
417
418                   switch(aSupportShape.ShapeType()) {
419                   case TopAbs_VERTEX: {
420                     aTolerance += BRep_Tool::Tolerance(TopoDS::Vertex(aSupportShape));
421                     break;
422                   }
423                   case TopAbs_EDGE: {
424                     aTolerance += BRep_Tool::Tolerance(TopoDS::Edge(aSupportShape));
425                     break;
426                   }
427                   case TopAbs_FACE: {
428                     aTolerance += BRep_Tool::Tolerance(TopoDS::Face(aSupportShape));
429                     break;
430                   }
431                   default:
432                     break;
433                   }
434                   
435                   if(aDist.Value() < aTolerance) {
436                     bVertexIsOnShape = Standard_True;
437                     break;
438                   }
439                 }
440               }
441             }
442
443             if(!bVertexIsOnShape) {
444               bKeepResult = Standard_False;
445             }
446           }
447         }
448
449         if(bKeepResult) {
450           BOP_CheckResult aResult;
451
452           if(i == 0) {
453             aResult.SetShape1(myShape1);
454             aResult.AddFaultyShape1(anEdge);
455           }
456           else {
457             aResult.SetShape2(myShape2);
458             aResult.AddFaultyShape2(anEdge);
459           }
460           
461           aResult.SetCheckStatus(BOP_TooSmallEdge);
462           myResult.Append(aResult);
463
464           if(myStopOnFirst) {
465             return;
466           }
467         }
468       }
469     }
470   }
471 }
472
473 // ================================================================================
474 // function: TestRebuildFace
475 // purpose:
476 // ================================================================================
477 void BOP_ArgumentAnalyzer::TestRebuildFace() 
478 {
479   if((myOperation == BOP_SECTION) ||
480      (myOperation == BOP_UNKNOWN))
481     return;
482   Standard_Integer i = 0;
483
484   for(i = 0; i < 2; i++) {
485     TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2;
486
487     if(aS.IsNull())
488       continue;
489
490     TopExp_Explorer anExp(aS, TopAbs_FACE);
491
492     for(; anExp.More(); anExp.Next()) {
493       TopoDS_Face aFace = TopoDS::Face(anExp.Current());
494
495       BOP_WireEdgeSet aWES (aFace);
496       TopExp_Explorer anExpE(aFace, TopAbs_EDGE);
497       Standard_Integer nbstartedges = 0;
498
499       for(; anExpE.More(); anExpE.Next()) {
500         aWES.AddStartElement(anExpE.Current());
501         nbstartedges++;
502       }
503       BOP_FaceBuilder aFB;
504       aFB.Do(aWES);
505       const TopTools_ListOfShape& aLF = aFB.NewFaces();
506       Standard_Boolean bBadFace = Standard_False;
507
508       if(aLF.Extent() != 1) {
509         bBadFace = Standard_True;
510       }
511       else {
512         Standard_Integer nbedgeused = 0;
513         anExpE.Init(aLF.First(), TopAbs_EDGE);
514
515         for(; anExpE.More(); anExpE.Next(), nbedgeused++);
516
517         if(nbstartedges != nbedgeused) {
518           bBadFace = Standard_True;
519         }
520       }
521
522       if(bBadFace) {
523         BOP_CheckResult aResult;
524
525         if(i == 0) {
526           aResult.SetShape1(myShape1);
527           aResult.AddFaultyShape1(aFace);
528         }
529         else {
530           aResult.SetShape2(myShape2);
531           aResult.AddFaultyShape2(aFace);
532         }
533           
534         aResult.SetCheckStatus(BOP_NonRecoverableFace);
535         myResult.Append(aResult);
536
537         if(myStopOnFirst) {
538           return;
539         }
540       }
541     }
542   }
543 }
544
545 // ================================================================================
546 // function: TestTangent
547 // purpose:
548 // ================================================================================
549 void BOP_ArgumentAnalyzer::TestTangent() 
550 {
551  // not implemented
552 }
553
554 // ================================================================================
555 // function: TestMergeSubShapes
556 // purpose:
557 // ================================================================================
558  void BOP_ArgumentAnalyzer::TestMergeSubShapes(const TopAbs_ShapeEnum theType) 
559 {
560   if(myShape1.IsNull() || myShape2.IsNull())
561     return;
562
563   BOP_CheckStatus aStatus = BOP_CheckUnknown;
564
565   switch(theType) {
566   case TopAbs_VERTEX: {
567     aStatus = BOP_IncompatibilityOfVertex;
568     break;
569   }
570   case TopAbs_EDGE: {
571     aStatus = BOP_IncompatibilityOfEdge;
572     break;
573   }
574   case TopAbs_FACE: {
575     aStatus = BOP_IncompatibilityOfFace;
576     break;
577   }
578   default: 
579     return;
580   }
581   TopExp_Explorer anExp1(myShape1, theType);
582   TopExp_Explorer anExp2(myShape2, theType);
583   TopTools_SequenceOfShape aSeq1, aSeq2;
584   TopTools_MapOfShape aMap1, aMap2;
585
586   for(; anExp1.More(); anExp1.Next()) {
587     TopoDS_Shape aS1 = anExp1.Current();
588
589     if(aMap1.Contains(aS1))
590       continue;
591     aSeq1.Append(aS1);
592     aMap1.Add(aS1);
593   }
594
595   for(; anExp2.More(); anExp2.Next()) {
596     TopoDS_Shape aS2 = anExp2.Current();
597     if(aMap2.Contains(aS2))
598       continue;
599     aSeq2.Append(aS2);
600     aMap2.Add(aS2);
601   }
602
603   TColStd_Array2OfBoolean anArrayOfFlag(1, aSeq1.Length(), 1, aSeq2.Length());
604   Standard_Integer i = 0, j = 0;
605   for(i = 1; i <= aSeq1.Length(); i++)
606     for(j = 1; j <= aSeq2.Length(); j++)
607       anArrayOfFlag.SetValue(i, j, Standard_False);
608
609   for(i = 1; i <= aSeq1.Length(); i++) {
610     TopoDS_Shape aS1 = aSeq1.Value(i);
611     TopTools_ListOfShape aListOfS2;
612     Standard_Integer nbs = 0;
613
614     for(j = 1; j <= aSeq2.Length(); j++) {
615       TopoDS_Shape aS2 = aSeq2.Value(j);
616       Standard_Boolean bIsEqual = Standard_False;
617
618       if(theType == TopAbs_VERTEX) {
619
620         TopoDS_Vertex aV1 = TopoDS::Vertex(aS1);
621         TopoDS_Vertex aV2 = TopoDS::Vertex(aS2);
622         gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
623         gp_Pnt aP2 = BRep_Tool::Pnt(aV2);
624         Standard_Real aDist = aP1.Distance(aP2);
625
626         if(aDist <= (BRep_Tool::Tolerance(aV1) + BRep_Tool::Tolerance(aV2))) {
627           bIsEqual = Standard_True;
628         }
629       }
630       else if(theType == TopAbs_EDGE) {
631         Standard_Integer aDiscretize = 30;
632         Standard_Real    aDeflection = 0.01;
633         TopoDS_Edge aE1 = TopoDS::Edge(aS1);
634         TopoDS_Edge aE2 = TopoDS::Edge(aS2);
635
636         IntTools_EdgeEdge aEE;
637         aEE.SetEdge1 (aE1);
638         aEE.SetEdge2 (aE2);
639         aEE.SetTolerance1 (BRep_Tool::Tolerance(aE1));
640         aEE.SetTolerance2 (BRep_Tool::Tolerance(aE2));
641         aEE.SetDiscretize (aDiscretize);
642         aEE.SetDeflection (aDeflection);
643
644         Standard_Real f = 0., l = 0.;
645         BRep_Tool::Range(aE1, f, l);
646         aEE.SetRange1(f, l);
647
648         BRep_Tool::Range(aE2, f, l);
649         aEE.SetRange2(f, l);
650
651         aEE.Perform();
652
653         if (aEE.IsDone()) {
654           const IntTools_SequenceOfCommonPrts& aCPrts = aEE.CommonParts();
655           Standard_Integer ii = 0;
656
657           for (ii = 1; ii <= aCPrts.Length(); ii++) {
658             const IntTools_CommonPrt& aCPart = aCPrts(ii);
659
660             if (aCPart.Type() == TopAbs_EDGE) {
661               bIsEqual = Standard_True;
662             }
663           }
664         }
665       }
666       else if(theType == TopAbs_FACE) {
667         // not yet implemented!
668       }
669
670       if(bIsEqual) {
671         anArrayOfFlag.SetValue(i, j, Standard_True );
672         aListOfS2.Append(aS2);
673         nbs++;
674       }
675     }
676
677     if(nbs > 1) {
678       BOP_CheckResult aResult;
679
680       aResult.SetShape1(myShape1);
681       aResult.SetShape2(myShape2);
682       aResult.AddFaultyShape1(aS1);
683       TopTools_ListIteratorOfListOfShape anIt(aListOfS2);
684
685       for(; anIt.More(); anIt.Next()) {
686         aResult.AddFaultyShape2(anIt.Value());
687       }
688
689       aResult.SetCheckStatus(aStatus);
690       myResult.Append(aResult);
691
692       if(myStopOnFirst) {
693         return;
694       }
695     }
696   }
697
698   for(i = 1; i <= aSeq2.Length(); i++) {
699     TopoDS_Shape aS2 = aSeq2.Value(i);
700     TopTools_ListOfShape aListOfS1;
701     Standard_Integer nbs = 0;
702
703     for(j = 1; j <= aSeq1.Length(); j++) {
704       TopoDS_Shape aS1 = aSeq1.Value(j);
705
706       if(anArrayOfFlag.Value(j, i)) {
707         aListOfS1.Append(aS1);
708         nbs++;
709       }
710     }
711
712     if(nbs > 1) {
713       BOP_CheckResult aResult;
714
715       aResult.SetShape1(myShape1);
716       aResult.SetShape2(myShape2);
717       TopTools_ListIteratorOfListOfShape anIt(aListOfS1);
718
719       for(; anIt.More(); anIt.Next()) {
720         aResult.AddFaultyShape1(anIt.Value());
721       }
722       aResult.AddFaultyShape2(aS2);
723
724       aResult.SetCheckStatus(aStatus);
725       myResult.Append(aResult);
726
727       if(myStopOnFirst) {
728         return;
729       }
730     }
731   }
732 }
733
734 // ================================================================================
735 // function: TestMergeVertex
736 // purpose:
737 // ================================================================================
738 void BOP_ArgumentAnalyzer::TestMergeVertex() 
739 {
740   TestMergeSubShapes(TopAbs_VERTEX); 
741 }
742
743 // ================================================================================
744 // function: TestMergeEdge
745 // purpose:
746 // ================================================================================
747 void BOP_ArgumentAnalyzer::TestMergeEdge() 
748 {
749   TestMergeSubShapes(TopAbs_EDGE); 
750 }
751
752 // ================================================================================
753 // function: TestMergeFace
754 // purpose:
755 // ================================================================================
756 // void BOP_ArgumentAnalyzer::TestMergeFace() 
757 // {
758   // not implemented
759 // }
760
761 // ----------------------------------------------------------------------
762 // static function: TestShapeType
763 // purpose:
764 // ----------------------------------------------------------------------
765 Standard_Boolean TestShapeType(const TopoDS_Shape & TheShape)
766 {
767   if(TheShape.IsNull())
768     return Standard_False;
769
770   TopAbs_ShapeEnum aT = TheShape.ShapeType();
771
772   if(aT == TopAbs_COMPOUND && BOPTools_Tools3D::IsEmptyShape(TheShape))
773     return Standard_False;
774
775   TopoDS_Iterator anIt;
776   TopoDS_Shape aSTmp, aShape;
777   Standard_Integer aNbShapes, TreatRes = 0;
778
779   if(aT==TopAbs_COMPOUND || aT==TopAbs_COMPSOLID) {
780     aNbShapes=0;
781     anIt.Initialize(TheShape);
782     for (; anIt.More(); anIt.Next()) {
783       if(!aNbShapes) {
784         aSTmp=anIt.Value();
785       }
786       aNbShapes++;
787       if(aNbShapes>1) {
788         break;
789       }
790     }
791     if(aT == TopAbs_COMPOUND) {
792       if (aNbShapes==1) {
793         TreatRes = BOPTools_DSFiller::TreatCompound(TheShape, aSTmp);
794         if(TreatRes != 0)
795           return Standard_False;
796         aShape=aSTmp;
797         aT = aShape.ShapeType();
798       }
799       else if (aNbShapes>1) {
800         TreatRes = BOPTools_DSFiller::TreatCompound(TheShape, aSTmp);
801         if(TreatRes != 0)
802           return Standard_False;
803         aShape=aSTmp;
804         aT=aShape.ShapeType();
805       }
806     }
807   }
808
809   if(aT==TopAbs_COMPOUND || aT==TopAbs_COMPSOLID) {
810     return Standard_False;
811   }
812
813   return Standard_True;
814 }
815
816 // ----------------------------------------------------------------------
817 // static function: CheckEdge
818 // purpose:
819 // ----------------------------------------------------------------------
820 Standard_Boolean CheckEdge(const TopoDS_Edge& theEdge) 
821 {
822   Handle(IntTools_Context) aContext;
823   TopoDS_Vertex aV1, aV2;
824   //
825   //modified by NIZNHY-PKV Tue Jan 31 15:07:13 2012f
826   aContext=new IntTools_Context;
827   ////modified by NIZNHY-PKV Tue Jan 31 15:07:16 2012t
828   TopExp::Vertices(theEdge, aV1, aV2);
829
830
831   if(aV1.IsNull() || aV2.IsNull() || BRep_Tool::Degenerated(theEdge))
832     return Standard_True;
833   Standard_Real aFirst = 0., aLast = 0.;
834   BRep_Tool::Range(theEdge, aFirst, aLast);
835   IntTools_Range aRange(aFirst, aLast);
836   IntTools_ShrunkRange aSR(theEdge, aV1, aV2, aRange, aContext);
837
838   if (!aSR.IsDone() || aSR.ErrorStatus() == 6) {
839     return Standard_False;
840   }
841   return Standard_True;
842 }
843
844 // ----------------------------------------------------------------------
845 // static function: TestSubShapeType
846 // purpose:
847 // ----------------------------------------------------------------------
848 Standard_Boolean TestSubShapeType(const TopAbs_ShapeEnum theT1,
849                                   const TopAbs_ShapeEnum theT2,
850                                   const BOP_Operation    theOP)
851 {
852   TopAbs_ShapeEnum aT1 = theT1, aT2 = theT2;
853
854   if(aT1==TopAbs_FACE) {
855     if(aT2==TopAbs_SOLID || aT2==TopAbs_SHELL || aT2==TopAbs_FACE ||
856        aT2==TopAbs_WIRE || aT2==TopAbs_EDGE) {
857       aT1=TopAbs_SHELL;
858     }
859   }
860   if(aT2==TopAbs_FACE) {
861     if(aT1==TopAbs_SOLID || aT1==TopAbs_SHELL ||
862        aT1==TopAbs_WIRE || aT1==TopAbs_EDGE) {
863       aT2=TopAbs_SHELL;
864     }
865   }
866   if(aT1==TopAbs_EDGE) {
867     if(aT2==TopAbs_SOLID || aT2==TopAbs_SHELL ||
868        aT2==TopAbs_WIRE || aT2==TopAbs_EDGE) {
869       aT1=TopAbs_WIRE;
870     }
871   }
872   if(aT2==TopAbs_EDGE) {
873     if(aT1==TopAbs_SOLID || aT1==TopAbs_SHELL || aT1==TopAbs_WIRE) {
874       aT2=TopAbs_WIRE;
875     }
876   }
877
878   // test operations
879   if(theOP!=BOP_UNKNOWN) {
880     Standard_Boolean opOk;
881     if(aT1==TopAbs_SHELL && aT2==TopAbs_SHELL)
882       opOk = Standard_True;
883     else if(aT1==TopAbs_SOLID && aT2==TopAbs_SOLID)
884       opOk = Standard_True;
885     else if((aT1==TopAbs_SOLID && aT2==TopAbs_SHELL) ||
886             (aT2==TopAbs_SOLID && aT1==TopAbs_SHELL))
887       opOk = Standard_True;
888     else if(aT1==TopAbs_WIRE && aT2==TopAbs_WIRE)
889       opOk = Standard_True;
890     else if((aT1==TopAbs_WIRE  && aT2==TopAbs_SHELL) ||
891             (aT2==TopAbs_WIRE  && aT1==TopAbs_SHELL))
892       opOk = Standard_True;
893     else if((aT1==TopAbs_WIRE  && aT2==TopAbs_SOLID) ||
894             (aT2==TopAbs_WIRE  && aT1==TopAbs_SOLID))
895       opOk = Standard_True;
896     else 
897       opOk = Standard_False;
898
899     if(!opOk) {
900       return Standard_False;
901     }
902
903     if((aT1==TopAbs_SHELL && aT2==TopAbs_SOLID) ||
904        (aT2==TopAbs_SHELL && aT1==TopAbs_SOLID)) {
905       if(!BOP_ShellSolid::CheckArgTypes(aT1,aT2,theOP)) {
906         return Standard_False;
907       }
908     }
909     if((aT1==TopAbs_WIRE && aT2==TopAbs_SOLID) ||
910        (aT2==TopAbs_WIRE && aT1==TopAbs_SOLID)) {
911       if(!BOP_WireSolid::CheckArgTypes(aT1,aT2,theOP)) {
912         return Standard_False;
913       }
914     }
915     if((aT1==TopAbs_WIRE && aT2==TopAbs_SHELL) ||
916        (aT1==TopAbs_WIRE && aT2==TopAbs_SHELL)) {
917       if(!BOP_WireShell::CheckArgTypes(aT1,aT2,theOP)) {
918         return Standard_False;
919       }
920     }
921   }
922   
923   return Standard_True;
924 }