0023933: Self intersection reported after Fuse operation.
[occt.git] / src / BOPAlgo / BOPAlgo_ArgumentAnalyzer.cxx
1 // Created on: 2004-09-02
2 // Copyright (c) 2004-2012 OPEN CASCADE SAS
3 //
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
8 //
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 //
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
18
19 #include <BOPAlgo_ArgumentAnalyzer.ixx>
20
21 #include <Standard_ErrorHandler.hxx>
22 #include <Standard_Failure.hxx>
23 #include <TopExp.hxx>
24 #include <TopExp_Explorer.hxx>
25 #include <BRep_Builder.hxx>
26 #include <BRep_Tool.hxx>
27 #include <BRepExtrema_DistShapeShape.hxx>
28 #include <gp_Pnt.hxx>
29 #include <TopoDS_Iterator.hxx>
30 #include <TopoDS.hxx>
31 #include <TopoDS_Vertex.hxx>
32 #include <TopoDS_Edge.hxx>
33 #include <TopoDS_Wire.hxx>
34 #include <TopoDS_Shell.hxx>
35 #include <TopoDS_Solid.hxx>
36 #include <BOPCol_ListOfShape.hxx>
37 #include <BOPCol_SequenceOfShape.hxx>
38 #include <BOPCol_MapOfShape.hxx>
39
40 #include <TColStd_Array2OfBoolean.hxx>
41
42 #include <IntTools_Range.hxx>
43 #include <IntTools_EdgeEdge.hxx>
44 #include <IntTools_CommonPrt.hxx>
45
46 #include <BOPAlgo_Operation.hxx>
47 #include <BOPAlgo_CheckerSI.hxx>
48 #include <BOPAlgo_BuilderFace.hxx>
49
50 #include <BOPDS_DS.hxx>
51 #include <BOPDS_VectorOfInterfVV.hxx>
52 #include <BOPDS_VectorOfInterfVE.hxx>
53 #include <BOPDS_VectorOfInterfEE.hxx>
54 #include <BOPDS_VectorOfInterfVF.hxx>
55 #include <BOPDS_VectorOfInterfEF.hxx>
56 #include <BOPDS_VectorOfInterfFF.hxx>
57
58 #include <BOPInt_Context.hxx>
59
60 #include <BOPTools_AlgoTools3D.hxx>
61 #include <BOPTools_AlgoTools.hxx>
62 #include <BOPCol_ListOfShape.hxx>
63
64 // ================================================================================
65 // function: Constructor
66 // purpose:
67 // ================================================================================
68 BOPAlgo_ArgumentAnalyzer::BOPAlgo_ArgumentAnalyzer() : 
69 myStopOnFirst(Standard_False),
70 myOperation(BOPAlgo_UNKNOWN),
71 myArgumentTypeMode(Standard_False),
72 mySelfInterMode(Standard_False),
73 mySmallEdgeMode(Standard_False),
74 myRebuildFaceMode(Standard_False),
75 myTangentMode(Standard_False),
76 myMergeVertexMode(Standard_False),
77 myMergeEdgeMode(Standard_False),
78 myEmpty1(Standard_False),
79 myEmpty2(Standard_False)
80 // myMergeFaceMode(Standard_False)
81 {
82 }
83
84 // ================================================================================
85 // function: SetShape1
86 // purpose:
87 // ================================================================================
88 void BOPAlgo_ArgumentAnalyzer::SetShape1(const TopoDS_Shape & TheShape)
89 {
90   myShape1 = TheShape;
91 }
92
93 // ================================================================================
94 // function: SetShape2
95 // purpose:
96 // ================================================================================
97 void BOPAlgo_ArgumentAnalyzer::SetShape2(const TopoDS_Shape & TheShape)
98 {
99   myShape2 = TheShape;
100 }
101
102 // ================================================================================
103 // function: GetShape1
104 // purpose:
105 // ================================================================================
106 const TopoDS_Shape & BOPAlgo_ArgumentAnalyzer::GetShape1() const
107 {
108   return myShape1;
109 }
110
111 // ================================================================================
112 // function: GetShape2
113 // purpose:
114 // ================================================================================
115 const TopoDS_Shape & BOPAlgo_ArgumentAnalyzer::GetShape2() const
116 {
117   return myShape2;
118 }
119
120 // ================================================================================
121 // function: OperationType
122 // purpose:
123 // ================================================================================
124 BOPAlgo_Operation& BOPAlgo_ArgumentAnalyzer::OperationType() 
125 {
126   return myOperation;
127 }
128
129 // ================================================================================
130 // function: StopOnFirstFaulty
131 // purpose:
132 // ================================================================================
133 Standard_Boolean & BOPAlgo_ArgumentAnalyzer::StopOnFirstFaulty()
134 {
135   return myStopOnFirst;
136 }
137
138 // ================================================================================
139 // function: Prepare
140 // purpose:
141 // ================================================================================
142 void BOPAlgo_ArgumentAnalyzer::Prepare()
143 {
144   Standard_Boolean isS1 = myShape1.IsNull(), isS2 = myShape2.IsNull();
145   if (!isS1) {
146     myEmpty1 = BOPTools_AlgoTools3D::IsEmptyShape(myShape1);
147   }
148   if (!isS2) {
149     myEmpty2 = BOPTools_AlgoTools3D::IsEmptyShape(myShape2);
150   }
151 }
152 // ================================================================================
153 // function: Perform
154 // purpose:
155 // ================================================================================
156 void BOPAlgo_ArgumentAnalyzer::Perform()
157 {
158   try {
159     OCC_CATCH_SIGNALS
160     myResult.Clear();
161
162     Prepare();
163
164     if(myArgumentTypeMode) {
165       TestTypes();
166     }
167
168     if(mySelfInterMode) {
169       TestSelfInterferences();
170     }
171
172     if(mySmallEdgeMode) {
173       if(!(!myResult.IsEmpty() && myStopOnFirst))
174         TestSmallEdge();
175     }
176
177     if(myRebuildFaceMode) {
178       if(!(!myResult.IsEmpty() && myStopOnFirst))
179         TestRebuildFace();
180     }
181
182     if(myTangentMode) {
183       if(!(!myResult.IsEmpty() && myStopOnFirst))
184         TestTangent();
185     }
186
187     if(myMergeVertexMode) {
188       if(!(!myResult.IsEmpty() && myStopOnFirst))
189         TestMergeVertex();
190     }
191     
192     if(myMergeEdgeMode) {
193       if(!(!myResult.IsEmpty() && myStopOnFirst))
194         TestMergeEdge();
195     }
196   }
197   catch(Standard_Failure) {
198     BOPAlgo_CheckResult aResult;
199     aResult.SetCheckStatus(BOPAlgo_CheckUnknown);
200     myResult.Append(aResult);
201   }
202 }
203
204 // ================================================================================
205 // function: HasFaulty
206 // purpose:
207 // ================================================================================
208 Standard_Boolean BOPAlgo_ArgumentAnalyzer::HasFaulty() const
209 {
210   return ( !myResult.IsEmpty());
211 }
212
213 // ================================================================================
214 // function: GetCheckResult
215 // purpose:
216 // ================================================================================
217 const BOPAlgo_ListOfCheckResult& BOPAlgo_ArgumentAnalyzer::GetCheckResult() const
218 {
219   return myResult;
220 }
221
222 // ================================================================================
223 // function: TestTypes
224 // purpose:
225 // ================================================================================
226 void BOPAlgo_ArgumentAnalyzer::TestTypes()
227 {
228   Standard_Boolean isS1 = myShape1.IsNull(), isS2 = myShape2.IsNull();
229
230   if(isS1 && isS2) {
231     BOPAlgo_CheckResult aResult;
232     aResult.SetCheckStatus(BOPAlgo_BadType);
233     myResult.Append(aResult);
234     return;
235   }
236
237   //single shape check
238   if((isS1 && !isS2) || (!isS1 && isS2)) {
239     Standard_Boolean bIsEmpty = (isS1) ? myEmpty2 : myEmpty1;
240
241     if(bIsEmpty || myOperation!=BOPAlgo_UNKNOWN) {
242       const TopoDS_Shape & aS = (isS1) ? myShape2 : myShape1;
243       BOPAlgo_CheckResult aResult;
244       aResult.SetShape1(aS);
245       aResult.SetCheckStatus(BOPAlgo_BadType);
246       myResult.Append(aResult);
247       return;
248     }
249   }
250   // two shapes check (begin)
251   else {
252     if(myEmpty1 || myEmpty2) {
253       BOPAlgo_CheckResult aResult;
254       if(myEmpty1 && myEmpty2) {
255         aResult.SetShape1(myShape1);
256         aResult.SetShape2(myShape2);
257       }
258       else {
259         const TopoDS_Shape & aS = myEmpty1 ? myShape1 : myShape2;
260         if(myEmpty1)
261           aResult.SetShape1(aS);
262         else
263           aResult.SetShape2(aS);
264       }
265       aResult.SetCheckStatus(BOPAlgo_BadType);
266       myResult.Append(aResult);
267       return;
268     }
269     //
270     Standard_Integer aDim1, aDim2;
271     Standard_Boolean bBadTypes = Standard_False;
272     //
273     aDim1 = BOPTools_AlgoTools::Dimension(myShape1);
274     aDim2 = BOPTools_AlgoTools::Dimension(myShape2);
275     if (aDim1 < aDim2) {
276       if (myOperation == BOPAlgo_FUSE ||
277           myOperation == BOPAlgo_CUT21) {
278         bBadTypes = Standard_True;
279       }
280     }
281     else if (aDim1 > aDim2) {
282       if (myOperation == BOPAlgo_FUSE ||
283           myOperation == BOPAlgo_CUT) {
284         bBadTypes = Standard_True;
285       }
286     }
287     if (bBadTypes) {
288       BOPAlgo_CheckResult aResult;
289       aResult.SetShape1(myShape1);
290       aResult.SetShape2(myShape2);
291       aResult.SetCheckStatus(BOPAlgo_BadType);
292       myResult.Append(aResult);
293     }
294   }
295 }
296
297 // ================================================================================
298 // function: TestSelfInterferences
299 // purpose:
300 // ================================================================================
301 void BOPAlgo_ArgumentAnalyzer::TestSelfInterferences()
302 {
303   Standard_Integer ii = 0, j;
304   Standard_Boolean bSelfInt;
305
306   for(ii = 0; ii < 2; ii++) {
307     TopoDS_Shape aS = (ii == 0) ? myShape1 : myShape2;
308
309     if(aS.IsNull())
310       continue;
311
312     Standard_Boolean bIsEmpty = (ii == 0) ? myEmpty1 : myEmpty2;
313     if (bIsEmpty) {
314       continue;
315     }
316
317     BOPAlgo_CheckerSI aChecker;
318     BOPCol_ListOfShape anArgs;
319     anArgs.Append(aS);
320     aChecker.SetArguments(anArgs);
321     //
322     aChecker.Perform();
323     Standard_Integer iErr = aChecker.ErrorStatus();
324     //
325     const BOPDS_PDS& theDS = aChecker.PDS();
326     BOPDS_VectorOfInterfVV& aVVs=theDS->InterfVV();
327     BOPDS_VectorOfInterfVE& aVEs=theDS->InterfVE();
328     BOPDS_VectorOfInterfEE& aEEs=theDS->InterfEE();
329     BOPDS_VectorOfInterfVF& aVFs=theDS->InterfVF();
330     BOPDS_VectorOfInterfEF& aEFs=theDS->InterfEF();
331     BOPDS_VectorOfInterfFF& aFFs=theDS->InterfFF();
332     //
333     Standard_Integer aNb[6] = {aVVs.Extent(), aVEs.Extent(), aEEs.Extent(), 
334                                aVFs.Extent(), aEFs.Extent(), aFFs.Extent()};
335     //
336     Standard_Integer ind = 0;
337     for (Standard_Integer aTypeInt = 0; aTypeInt < 6; ++aTypeInt) {
338       for (Standard_Integer i = 0; i < aNb[aTypeInt]; ++i) {
339         BOPDS_Interf* aInt = (aTypeInt==0) ? (BOPDS_Interf*)(&aVVs(i)) : 
340           ((aTypeInt==1) ? (BOPDS_Interf*)(&aVEs(i)) :
341            ((aTypeInt==2) ? (BOPDS_Interf*)(&aEEs(i)) : 
342             ((aTypeInt==3) ? (BOPDS_Interf*)(&aVFs(i)) :
343              ((aTypeInt==4) ? (BOPDS_Interf*)(&aEFs(i)) : (BOPDS_Interf*)(&aFFs(i))))));
344         //
345         Standard_Integer nI1 = aInt->Index1();
346         Standard_Integer nI2 = aInt->Index2();
347         if (nI1 == nI2) {
348           continue;
349         }
350         //
351         if (aTypeInt == 4) {
352           BOPDS_InterfEF& aEF=aEFs(i);
353           if (aEF.CommonPart().Type()==TopAbs_SHAPE) {
354             continue;
355           }
356         }
357         //
358         const TopoDS_Shape& aS1 = theDS->Shape(nI1);
359         const TopoDS_Shape& aS2 = theDS->Shape(nI2);
360         //
361         if (aTypeInt == 5) {
362           bSelfInt = Standard_False;
363           BOPDS_InterfFF& aFF = aFFs(i);
364           BOPDS_VectorOfPoint& aVP=aFF.ChangePoints();
365           Standard_Integer aNbP=aVP.Extent();
366           BOPDS_VectorOfCurve& aVC=aFF.ChangeCurves();
367           Standard_Integer aNbC=aVC.Extent();
368           if (!aNbP && !aNbC) {
369             continue;
370           }
371           for (j=0; j<aNbC; ++j) {
372             BOPDS_Curve& aNC=aVC(j);
373             BOPDS_ListOfPaveBlock& aLPBC=aNC.ChangePaveBlocks();
374             if (aLPBC.Extent()) {
375               bSelfInt = Standard_True;
376               break;
377             }
378           }
379           if (!bSelfInt) {
380             continue;
381           }
382         }
383         //
384         BOPAlgo_CheckResult aResult;
385         if(ii == 0)
386           aResult.SetShape1(myShape1);
387         else
388           aResult.SetShape2(myShape2);
389
390         if(ii == 0) {
391           aResult.AddFaultyShape1(aS1);
392           aResult.AddFaultyShape1(aS2);
393         }
394         else {
395           aResult.AddFaultyShape2(aS1);
396           aResult.AddFaultyShape2(aS2);
397         }
398         aResult.SetCheckStatus(BOPAlgo_SelfIntersect);
399         myResult.Append(aResult);
400       }
401     }
402     if (iErr) {
403       BOPAlgo_CheckResult aResult;
404       if(ii == 0)
405         aResult.SetShape1(myShape1);
406       else
407         aResult.SetShape2(myShape2);
408       
409       if(ii == 0) {
410         aResult.AddFaultyShape1(myShape1);
411       }
412       else {
413         aResult.AddFaultyShape2(myShape2);
414       }
415       aResult.SetCheckStatus(BOPAlgo_OperationAborted);
416       myResult.Append(aResult);
417     }
418   }
419   
420 }
421
422 // ================================================================================
423 // function: TestSmallEdge
424 // purpose:
425 // ================================================================================
426 void BOPAlgo_ArgumentAnalyzer::TestSmallEdge() 
427 {
428   Standard_Integer i = 0;
429   BRepExtrema_DistShapeShape aDist;
430   Handle(BOPInt_Context) aCtx;
431   //
432   aCtx = new BOPInt_Context;
433   
434   for(i = 0; i < 2; i++) {
435     TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2;
436
437     if(aS.IsNull())
438       continue;
439
440     TopExp_Explorer anExp(aS, TopAbs_EDGE);
441
442     for(; anExp.More(); anExp.Next()) {
443       TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current());
444
445       if(BOPTools_AlgoTools::IsMicroEdge(anEdge, aCtx)) {
446         Standard_Boolean bKeepResult = Standard_True;
447         
448         if(myOperation == BOPAlgo_SECTION) {
449           TopoDS_Shape anOtherS = (i == 0) ? myShape2 : myShape1;
450           
451           if(!anOtherS.IsNull()) {
452             aDist.LoadS2(anOtherS);
453             
454             Standard_Boolean bVertexIsOnShape = Standard_False;
455             Standard_Integer ii = 0;
456             TopExp_Explorer anExpV(anEdge, TopAbs_VERTEX);
457             
458             for(; anExpV.More(); anExpV.Next()) {
459               TopoDS_Shape aV = anExpV.Current();
460               
461               aDist.LoadS1(aV);
462               aDist.Perform();
463               
464               if(aDist.IsDone()) {
465                 
466                 for(ii = 1; ii <= aDist.NbSolution(); ii++) {
467                   Standard_Real aTolerance = BRep_Tool::Tolerance(TopoDS::Vertex(aV));
468                   TopoDS_Shape aSupportShape = aDist.SupportOnShape2(ii);
469                   
470                   switch(aSupportShape.ShapeType()) {
471                   case TopAbs_VERTEX: {
472                     aTolerance += BRep_Tool::Tolerance(TopoDS::Vertex(aSupportShape));
473                     break;
474                   }
475                   case TopAbs_EDGE: {
476                     aTolerance += BRep_Tool::Tolerance(TopoDS::Edge(aSupportShape));
477                     break;
478                   }
479                   case TopAbs_FACE: {
480                     aTolerance += BRep_Tool::Tolerance(TopoDS::Face(aSupportShape));
481                     break;
482                   }
483                   default:
484                     break;
485                   }
486                   
487                   if(aDist.Value() < aTolerance) {
488                     bVertexIsOnShape = Standard_True;
489                     break;
490                   }
491                 }
492               }
493             }
494             
495             if(!bVertexIsOnShape) {
496               bKeepResult = Standard_False;
497             }
498           }
499         }
500         
501         if(bKeepResult) {
502           BOPAlgo_CheckResult aResult;
503           
504           if(i == 0) {
505             aResult.SetShape1(myShape1);
506             aResult.AddFaultyShape1(anEdge);
507           }
508           else {
509             aResult.SetShape2(myShape2);
510             aResult.AddFaultyShape2(anEdge);
511           }
512           
513           aResult.SetCheckStatus(BOPAlgo_TooSmallEdge);
514           myResult.Append(aResult);
515           
516           if(myStopOnFirst) {
517             return;
518           }
519         }
520       }
521     }
522   }
523 }
524
525 // ================================================================================
526 // function: TestRebuildFace
527 // purpose:
528 // ================================================================================
529 void BOPAlgo_ArgumentAnalyzer::TestRebuildFace() 
530 {
531   if((myOperation == BOPAlgo_SECTION) ||
532      (myOperation == BOPAlgo_UNKNOWN))
533     return;
534   Standard_Integer i = 0;
535
536   for(i = 0; i < 2; i++) {
537     TopoDS_Shape aS = (i == 0) ? myShape1 : myShape2;
538
539     if(aS.IsNull())
540       continue;
541
542     TopExp_Explorer anExp(aS, TopAbs_FACE);
543     BOPCol_ListOfShape aLS;
544
545     for(; anExp.More(); anExp.Next()) {
546       TopoDS_Face aFace = TopoDS::Face(anExp.Current());
547
548       TopoDS_Face aFF = aFace;
549       aFF.Orientation(TopAbs_FORWARD);
550       TopExp_Explorer anExpE(aFF, TopAbs_EDGE);
551       Standard_Integer nbstartedges = 0;
552       aLS.Clear();
553       //
554       for(; anExpE.More(); anExpE.Next()) {
555         const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&anExpE.Current()));
556         TopAbs_Orientation anOriE=aE.Orientation();
557         //
558         if (anOriE==TopAbs_INTERNAL) {
559           TopoDS_Edge aEE=aE;
560           aEE.Orientation(TopAbs_FORWARD);
561           aLS.Append(aEE);
562           aEE.Orientation(TopAbs_REVERSED);
563           aLS.Append(aEE);
564         }
565         else {
566           aLS.Append(aE);
567         }
568         nbstartedges++;
569       }
570       BOPAlgo_BuilderFace aBF;
571       aBF.SetFace(aFace);
572       aBF.SetShapes(aLS);
573       aBF.Perform();
574       const BOPCol_ListOfShape& aLF = aBF.Areas();
575       Standard_Boolean bBadFace = Standard_False;
576
577       if(aLF.Extent() != 1) {
578         bBadFace = Standard_True;
579       }
580       else {
581         Standard_Integer nbedgeused = 0;
582         anExpE.Init(aLF.First(), TopAbs_EDGE);
583         
584         for(; anExpE.More(); anExpE.Next(), nbedgeused++);
585         
586         if(nbstartedges != nbedgeused) {
587           bBadFace = Standard_True;
588         }
589       }
590
591       if(bBadFace) {
592         BOPAlgo_CheckResult aResult;
593         
594         if(i == 0) {
595           aResult.SetShape1(myShape1);
596           aResult.AddFaultyShape1(aFace);
597         }
598         else {
599           aResult.SetShape2(myShape2);
600           aResult.AddFaultyShape2(aFace);
601         }
602         
603         aResult.SetCheckStatus(BOPAlgo_NonRecoverableFace);
604         myResult.Append(aResult);
605         
606         if(myStopOnFirst) {
607           return;
608         }
609       }
610     }
611   }
612 }
613
614 // ================================================================================
615 // function: TestTangent
616 // purpose:
617 // ================================================================================
618 void BOPAlgo_ArgumentAnalyzer::TestTangent() 
619 {
620  // not implemented
621 }
622
623 // ================================================================================
624 // function: TestMergeSubShapes
625 // purpose:
626 // ================================================================================
627  void BOPAlgo_ArgumentAnalyzer::TestMergeSubShapes(const TopAbs_ShapeEnum theType) 
628 {
629   if(myShape1.IsNull() || myShape2.IsNull())
630     return;
631
632   if (myEmpty1 || myEmpty2) 
633     return;
634
635   BOPAlgo_CheckStatus aStatus = BOPAlgo_CheckUnknown;
636
637   switch(theType) {
638   case TopAbs_VERTEX: {
639     aStatus = BOPAlgo_IncompatibilityOfVertex;
640     break;
641   }
642   case TopAbs_EDGE: {
643     aStatus = BOPAlgo_IncompatibilityOfEdge;
644     break;
645   }
646   case TopAbs_FACE: {
647     aStatus = BOPAlgo_IncompatibilityOfFace;
648     break;
649   }
650   default: 
651     return;
652   }
653   TopExp_Explorer anExp1(myShape1, theType);
654   TopExp_Explorer anExp2(myShape2, theType);
655   BOPCol_SequenceOfShape aSeq1, aSeq2;
656   BOPCol_MapOfShape aMap1, aMap2;
657
658   for(; anExp1.More(); anExp1.Next()) {
659     TopoDS_Shape aS1 = anExp1.Current();
660
661     if(aMap1.Contains(aS1))
662       continue;
663     aSeq1.Append(aS1);
664     aMap1.Add(aS1);
665   }
666
667   for(; anExp2.More(); anExp2.Next()) {
668     TopoDS_Shape aS2 = anExp2.Current();
669     if(aMap2.Contains(aS2))
670       continue;
671     aSeq2.Append(aS2);
672     aMap2.Add(aS2);
673   }
674
675   TColStd_Array2OfBoolean anArrayOfFlag(1, aSeq1.Length(), 1, aSeq2.Length());
676   Standard_Integer i = 0, j = 0;
677   for(i = 1; i <= aSeq1.Length(); i++)
678     for(j = 1; j <= aSeq2.Length(); j++)
679       anArrayOfFlag.SetValue(i, j, Standard_False);
680
681   for(i = 1; i <= aSeq1.Length(); i++) {
682     TopoDS_Shape aS1 = aSeq1.Value(i);
683     BOPCol_ListOfShape aListOfS2;
684     Standard_Integer nbs = 0;
685
686     for(j = 1; j <= aSeq2.Length(); j++) {
687       TopoDS_Shape aS2 = aSeq2.Value(j);
688       Standard_Boolean bIsEqual = Standard_False;
689
690       if(theType == TopAbs_VERTEX) {
691
692         TopoDS_Vertex aV1 = TopoDS::Vertex(aS1);
693         TopoDS_Vertex aV2 = TopoDS::Vertex(aS2);
694         gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
695         gp_Pnt aP2 = BRep_Tool::Pnt(aV2);
696         Standard_Real aDist = aP1.Distance(aP2);
697
698         if(aDist <= (BRep_Tool::Tolerance(aV1) + BRep_Tool::Tolerance(aV2))) {
699           bIsEqual = Standard_True;
700         }
701       }
702       else if(theType == TopAbs_EDGE) {
703         Standard_Integer aDiscretize = 30;
704         Standard_Real    aDeflection = 0.01;
705         TopoDS_Edge aE1 = TopoDS::Edge(aS1);
706         TopoDS_Edge aE2 = TopoDS::Edge(aS2);
707         
708         IntTools_EdgeEdge aEE;
709         aEE.SetEdge1 (aE1);
710         aEE.SetEdge2 (aE2);
711         aEE.SetTolerance1 (BRep_Tool::Tolerance(aE1));
712         aEE.SetTolerance2 (BRep_Tool::Tolerance(aE2));
713         aEE.SetDiscretize (aDiscretize);
714         aEE.SetDeflection (aDeflection);
715         
716         Standard_Real f = 0., l = 0.;
717         BRep_Tool::Range(aE1, f, l);
718         aEE.SetRange1(f, l);
719         
720         BRep_Tool::Range(aE2, f, l);
721         aEE.SetRange2(f, l);
722         
723         aEE.Perform();
724         
725         if (aEE.IsDone()) {
726           const IntTools_SequenceOfCommonPrts& aCPrts = aEE.CommonParts();
727           Standard_Integer ii = 0;
728           
729           for (ii = 1; ii <= aCPrts.Length(); ii++) {
730             const IntTools_CommonPrt& aCPart = aCPrts(ii);
731             
732             if (aCPart.Type() == TopAbs_EDGE) {
733               bIsEqual = Standard_True;
734             }
735           }
736         }
737       }
738       else if(theType == TopAbs_FACE) {
739         // not yet implemented!
740       }
741
742       if(bIsEqual) {
743         anArrayOfFlag.SetValue(i, j, Standard_True );
744         aListOfS2.Append(aS2);
745         nbs++;
746       }
747     }
748
749     if(nbs > 1) {
750       BOPAlgo_CheckResult aResult;
751
752       aResult.SetShape1(myShape1);
753       aResult.SetShape2(myShape2);
754       aResult.AddFaultyShape1(aS1);
755       BOPCol_ListIteratorOfListOfShape anIt(aListOfS2);
756
757       for(; anIt.More(); anIt.Next()) {
758         aResult.AddFaultyShape2(anIt.Value());
759       }
760
761       aResult.SetCheckStatus(aStatus);
762       myResult.Append(aResult);
763
764       if(myStopOnFirst) {
765         return;
766       }
767     }
768   }
769
770   for(i = 1; i <= aSeq2.Length(); i++) {
771     TopoDS_Shape aS2 = aSeq2.Value(i);
772     BOPCol_ListOfShape aListOfS1;
773     Standard_Integer nbs = 0;
774
775     for(j = 1; j <= aSeq1.Length(); j++) {
776       TopoDS_Shape aS1 = aSeq1.Value(j);
777
778       if(anArrayOfFlag.Value(j, i)) {
779         aListOfS1.Append(aS1);
780         nbs++;
781       }
782     }
783     
784     if(nbs > 1) {
785       BOPAlgo_CheckResult aResult;
786
787       aResult.SetShape1(myShape1);
788       aResult.SetShape2(myShape2);
789       BOPCol_ListIteratorOfListOfShape anIt(aListOfS1);
790
791       for(; anIt.More(); anIt.Next()) {
792         aResult.AddFaultyShape1(anIt.Value());
793       }
794       aResult.AddFaultyShape2(aS2);
795
796       aResult.SetCheckStatus(aStatus);
797       myResult.Append(aResult);
798
799       if(myStopOnFirst) {
800         return;
801       }
802     }
803   }
804 }
805
806 // ================================================================================
807 // function: TestMergeVertex
808 // purpose:
809 // ================================================================================
810 void BOPAlgo_ArgumentAnalyzer::TestMergeVertex() 
811 {
812   TestMergeSubShapes(TopAbs_VERTEX); 
813 }
814
815 // ================================================================================
816 // function: TestMergeEdge
817 // purpose:
818 // ================================================================================
819 void BOPAlgo_ArgumentAnalyzer::TestMergeEdge() 
820 {
821   TestMergeSubShapes(TopAbs_EDGE); 
822 }
823
824 // ================================================================================
825 // function: TestMergeFace
826 // purpose:
827 // ================================================================================
828 // void BOPAlgo_ArgumentAnalyzer::TestMergeFace() 
829 // {
830   // not implemented
831 // }