3076341cb8a2cd42d8a7c8e5c4086a472a010ad5
[occt.git] / src / BOPTest / BOPTest_CheckCommands.cxx
1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15
16 #include <BOPAlgo_ArgumentAnalyzer.hxx>
17 #include <BOPAlgo_CheckerSI.hxx>
18 #include <BOPAlgo_CheckResult.hxx>
19 #include <BOPCol_ListOfShape.hxx>
20 #include <BOPDS_DS.hxx>
21 #include <BOPDS_MapOfPassKey.hxx>
22 #include <BOPTest.hxx>
23 #include <BOPTest_Objects.hxx>
24 #include <BOPTools_AlgoTools.hxx>
25 #include <BRep_Builder.hxx>
26 #include <BRepBuilderAPI_Copy.hxx>
27 #include <DBRep.hxx>
28 #include <Draw.hxx>
29 #include <OSD_Timer.hxx>
30 #include <TCollection_AsciiString.hxx>
31 #include <TopExp_Explorer.hxx>
32 #include <TopoDS_Compound.hxx>
33 #include <TopoDS_Shape.hxx>
34 #include <TopTools_MapOfShape.hxx>
35 #include <TopTools_ShapeMapHasher.hxx>
36
37 #include <algorithm>
38 #include <functional>
39 #include <vector>
40 //
41 static 
42   void MakeShapeForFullOutput (const TCollection_AsciiString&,
43                                const Standard_Integer,
44                                const BOPCol_ListOfShape&,
45                                Standard_Integer& ,
46                                Draw_Interpretor&,
47                                Standard_Boolean bCurveOnSurf = Standard_False,
48                                Standard_Real aMaxDist = 0.,
49                                Standard_Real aMaxParameter = 0.);
50 //
51 static Standard_Integer bopcheck   (Draw_Interpretor&, Standard_Integer, const char** );
52 static Standard_Integer bopargcheck(Draw_Interpretor&, Standard_Integer, const char** );
53 static Standard_Integer xdistef(Draw_Interpretor&, Standard_Integer, const char** );
54 static Standard_Integer checkcurveonsurf (Draw_Interpretor&, Standard_Integer, const char**);
55
56 //=======================================================================
57 //function : CheckCommands
58 //purpose  : 
59 //=======================================================================
60 void  BOPTest::CheckCommands(Draw_Interpretor& theCommands)
61 {
62   static Standard_Boolean done = Standard_False;
63   if (done) 
64     return;
65
66   done = Standard_True;
67   // Chapter's name
68   const char* g = "BOPTest commands";
69   //
70   theCommands.Add("bopcheck",  
71                   "use bopcheck Shape [level of check: 0 - 9] [-t]",
72                   __FILE__, bopcheck, g);
73   theCommands.Add("bopargcheck" , 
74                   "use bopargcheck without parameters to get ",  
75                   __FILE__, bopargcheck, g);
76   theCommands.Add ("xdistef" ,
77                    "use xdistef edge face",
78                    __FILE__, xdistef, g);
79   theCommands.Add("checkcurveonsurf",
80                   "use checkcurveonsurf shape",
81                   __FILE__, checkcurveonsurf, g);
82 }
83 //=======================================================================
84 //class    : BOPTest_Interf
85 //purpose  : Auxiliary class
86 //=======================================================================
87 class BOPTest_Interf {
88  public:
89   BOPTest_Interf() : myIndex1(-1), myIndex2(-1), myType(-1) {
90   }
91   //
92   ~BOPTest_Interf() {
93   }
94   //
95   void SetIndices(const Standard_Integer theIndex1,
96                   const Standard_Integer theIndex2) {
97     myIndex1=theIndex1; 
98     myIndex2=theIndex2; 
99   }
100   //
101   void Indices(Standard_Integer& theIndex1,
102                Standard_Integer& theIndex2) const {
103     theIndex1=myIndex1; 
104     theIndex2=myIndex2; 
105   }
106   //
107   void SetType(const Standard_Integer theType) {
108     myType=theType;
109   }
110   //
111   Standard_Integer Type() const {
112     return myType;
113   }
114   //
115   bool operator < (const  BOPTest_Interf& aOther) const {
116     bool bFlag;
117     //
118     if (myType==aOther.myType) {
119       if (myIndex1 == aOther.myIndex1) {
120         bFlag=(myIndex2 < aOther.myIndex2);
121       }
122       else {
123         bFlag=(myIndex1 < aOther.myIndex1);
124       }
125     }
126     else {
127       bFlag=(myType < aOther.myType);
128     }
129     //
130     return bFlag;
131   }
132   //
133  protected:
134   Standard_Integer myIndex1;
135   Standard_Integer myIndex2;
136   Standard_Integer myType;
137 };
138 //=======================================================================
139 //function : bopcheck
140 //purpose  : 
141 //=======================================================================
142 Standard_Integer bopcheck (Draw_Interpretor& di, 
143                            Standard_Integer n,  
144                            const char** a )
145 {
146   if (n<2) {
147     di << " use bopcheck Shape [level of check: 0 - 9] [-t]\n";
148     di << " The level of check defines "; 
149     di << " which interferences will be checked:\n";
150     di << " 0 - V/V only\n"; 
151     di << " 1 - V/V, V/E\n";
152     di << " 2 - V/V, V/E, E/E\n"; 
153     di << " 3 - V/V, V/E, E/E , V/F\n"; 
154     di << " 4 - V/V, V/E, E/E, V/F , E/F\n"; 
155     di << " 5 - V/V, V/E, E/E, V/F, E/F, F/F;\n";
156     di << " 6 - V/V, V/E, E/E, V/F, E/F, F/F, V/Z\n";
157     di << " 7 - V/V, V/E, E/E, V/F, E/F, F/F, E/Z\n";
158     di << " 8 - V/V, V/E, E/E, V/F, E/F, F/F, E/Z, F/Z\n";
159     di << " 9 - V/V, V/E, E/E, V/F, E/F, F/F, E/Z, F/Z, Z/Z\n";
160     di << " Default level is 9\n";
161     return 1;
162   }
163   //
164   TopoDS_Shape aS = DBRep::Get(a[1]);
165   if (aS.IsNull()) {
166     di << "null shapes are not allowed here!";
167     return 1;
168   }
169   //
170   Standard_Boolean bRunParallel, bShowTime;
171   Standard_Integer i, aLevel, aNbInterfTypes;
172   Standard_Real aTol;
173   //
174   aNbInterfTypes=BOPDS_DS::NbInterfTypes();
175   //
176   aLevel=aNbInterfTypes-1;
177   //
178   if (n>2) {
179     if (a[2][0] != '-') {
180       aLevel=Draw::Atoi(a[2]); 
181     }
182   }
183   //
184   if (aLevel < 0 || aLevel > aNbInterfTypes-1) {
185     di << "Invalid level";
186     return 1;
187   }
188   //
189   bShowTime=Standard_False;
190   aTol=BOPTest_Objects::FuzzyValue();
191   bRunParallel=BOPTest_Objects::RunParallel(); 
192   //
193   for (i=2; i<n; ++i) {
194     if (!strcmp(a[i], "-t")) {
195       bShowTime=Standard_True;
196     }
197       }
198   //
199   //aLevel = (n==3) ? Draw::Atoi(a[2]) : aNbInterfTypes-1;
200   //-------------------------------------------------------------------
201   char buf[256], aName1[32], aName2[32];
202   char aInterfTypes[10][4] = {
203     "V/V", "V/E", "E/E","V/F", "E/F", "F/F", "V/Z", "E/Z", "F/Z", "Z/Z"
204   };
205   //
206   Standard_Integer iErr, iCnt, n1, n2, iT;
207   TopAbs_ShapeEnum aType1, aType2;
208   BOPAlgo_CheckerSI aChecker;
209   BOPCol_ListOfShape aLS;
210   BOPDS_MapIteratorMapOfPassKey aItMPK;
211   //
212   if (aLevel < (aNbInterfTypes-1)) {
213     di << "Info:\nThe level of check is set to " 
214       << aInterfTypes[aLevel] << ", i.e. intersection(s)\n";
215     
216     for (i=aLevel+1; i<aNbInterfTypes; ++i) {
217       di << aInterfTypes[i];
218       if (i<aNbInterfTypes-1) {
219         di << ", ";
220       }
221     }
222     di << " will not be checked.\n\n";
223   }
224   //
225   aLS.Append(aS);
226   aChecker.SetArguments(aLS);
227   aChecker.SetLevelOfCheck(aLevel);
228   aChecker.SetRunParallel(bRunParallel);
229   aChecker.SetFuzzyValue(aTol);
230   //
231   OSD_Timer aTimer;
232   aTimer.Start();
233   //
234   aChecker.Perform();
235   //
236   aTimer.Stop();
237   //
238   iErr=aChecker.ErrorStatus();
239   //
240   const BOPDS_DS& aDS=*(aChecker.PDS());
241   //
242   const BOPDS_MapOfPassKey& aMPK=aDS.Interferences();
243   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
244   using namespace std;
245   vector <BOPTest_Interf> aVec;
246   vector <BOPTest_Interf>::iterator aIt;
247   BOPTest_Interf aBInterf;
248   //
249   aItMPK.Initialize(aMPK);
250   for (; aItMPK.More(); aItMPK.Next()) {
251     const BOPDS_PassKey& aPK=aItMPK.Value();
252     aPK.Ids(n1, n2);
253     if(aDS.IsNewShape(n1) || aDS.IsNewShape(n2)) {
254       continue;
255     }
256     //
257     const BOPDS_ShapeInfo& aSI1=aDS.ShapeInfo(n1);
258     const BOPDS_ShapeInfo& aSI2=aDS.ShapeInfo(n2);
259     aType1=aSI1.ShapeType();
260     aType2=aSI2.ShapeType();
261     //
262     iT=BOPDS_Tools::TypeToInteger(aType1, aType2);
263     //
264     aBInterf.SetIndices(n1, n2);
265     aBInterf.SetType(iT);
266     //
267     aVec.push_back(aBInterf);
268   }
269   //
270   sort( aVec.begin(), aVec.end(), less<BOPTest_Interf>());
271   //
272   iCnt=0;
273   for (aIt=aVec.begin(); aIt!=aVec.end(); aIt++) {
274     const BOPTest_Interf& aBI=*aIt;
275     //
276     aBI.Indices(n1, n2);
277     if(aDS.IsNewShape(n1) || aDS.IsNewShape(n2)) {
278       continue;
279     }
280     //
281     const TopoDS_Shape& aS1=aDS.Shape(n1);
282     const TopoDS_Shape& aS2=aDS.Shape(n2);
283     //
284     iT=aBI.Type(); 
285     di << aInterfTypes[iT] << ": ";
286     //
287     sprintf(aName1, "x%d", n1);
288     //sprintf(aName1, "x%d", iCnt);
289     DBRep::Set (aName1, aS1);
290     //
291     ++iCnt;
292     sprintf(aName2, "x%d", n2);
293     //sprintf(aName2, "x%d", iCnt);
294     DBRep::Set (aName2, aS2);
295     ++iCnt;
296     //
297     sprintf(buf, "%s %s \n", aName1, aName2);
298     di << buf;
299   }
300   //
301   if (iErr) {
302     di << "There were errors during the operation, ";
303     di << "so the list may be incomplete." << "\n";
304   }
305   //
306   if (!iCnt) {
307     di << " This shape seems to be OK." << "\n";
308   }
309   if (bShowTime)
310   {
311     Sprintf(buf, "  Tps: %7.2lf\n", aTimer.ElapsedTime());
312     di << buf;
313   }
314   return 0;
315 }
316 //=======================================================================
317 //function : bopargcheck
318 //purpose  : 
319 //=======================================================================
320 Standard_Integer bopargcheck (Draw_Interpretor& di,
321                               Standard_Integer n,
322                               const char** a )
323 {
324   if (n<2) {
325     di << "\n";
326     di << " Use >bopargcheck Shape1 [[Shape2] ";
327     di << "[-F/O/C/T/S/U] [/R|F|T|V|E|I|P|C|S]] [#BF]\n\n";
328     di << " -<Boolean Operation>" << "\n";
329     di << " F (fuse)" << "\n";
330     di << " O (common)" << "\n";
331     di << " C (cut)" << "\n";
332     di << " T (cut21)" << "\n";
333     di << " S (section)" << "\n";
334     di << " U (unknown)" << "\n";
335     di << " For example: \"bopargcheck s1 s2 -F\" enables" ;
336     di << " checking for Fuse operation" << "\n";
337     di << " default - section" << "\n" << "\n";
338     di << " /<Test Options>" << "\n";
339     di << " R (disable small edges (shrank range) test)" << "\n";
340     di << " F (disable faces verification test)" << "\n";
341     di << " T (disable tangent faces searching test)" << "\n";
342     di << " V (disable test possibility to merge vertices)" << "\n";
343     di << " E (disable test possibility to merge edges)" << "\n";
344     di << " I (disable self-interference test)" << "\n";
345     di << " P (disable shape type test)" << "\n";
346     di << " C (disable test for shape continuity)" << "\n";
347     di << " S (disable curve on surface check)" << "\n";
348     di << " For example: \"bopargcheck s1 s2 /RI\" disables ";
349     di << "small edge detection and self-intersection detection" << "\n";
350     di << " default - all options are enabled" << "\n" << "\n";
351     di << " #<Additional Test Options>" << "\n";
352     di << " B (stop test on first faulty found); default OFF" << "\n";
353     di << " F (full output for faulty shapes); default - output ";
354     di << "in a short format" << "\n" << "\n";
355     di << " NOTE: <Boolean Operation> and <Test Options> are ";
356     di <<  "used only for couple" << "\n";
357     di << "       of argument shapes, except I and P options ";
358     di << "that are always used for" << "\n";
359     di << "       couple of shapes as well as for ";
360     di <<"single shape test." << "\n";
361     return 1;
362   }
363
364   TopoDS_Shape aS1 = DBRep::Get(a[1]);
365
366   if(aS1.IsNull()) {
367     di << "Error: null shape not allowed!" << "\n";
368     di << "Type bopargcheck without arguments for more ";
369     di <<"information" << "\n";
370     return 1;
371   }
372
373   Standard_Boolean isBO = Standard_False;
374   Standard_Integer indxBO = 0;
375   Standard_Boolean isOP = Standard_False;
376   Standard_Integer indxOP = 0;
377   Standard_Boolean isAD = Standard_False;
378   Standard_Integer indxAD = 0;
379   Standard_Boolean isS2 = Standard_False;
380   Standard_Integer indxS2 = 0;
381   Standard_Real aTolerance = 0;
382
383   aTolerance=BOPTest_Objects::FuzzyValue();
384   
385   if(n >= 3) {
386     Standard_Integer iIndex = 0;
387     for(iIndex = 2; iIndex < n; iIndex++) {
388       if(a[iIndex][0] == '-')   {
389         isBO = Standard_True;
390         indxBO = iIndex;
391       }
392       else if(a[iIndex][0] == '/') {
393         isOP = Standard_True;
394         indxOP = iIndex;
395       }
396       else if(a[iIndex][0] == '#') {
397         isAD = Standard_True;
398         indxAD = iIndex;
399       }
400       else {
401         isS2 = Standard_True;
402         indxS2 = iIndex;
403       }
404     }
405   }
406   
407   // set & test second shape
408   TopoDS_Shape aS22, aS2;
409   if(isS2) {
410     if(indxS2 != 2) {
411       di << "Error: second shape should follow the first one!" << "\n";
412       di << "Type bopargcheck without arguments for more information" << "\n";
413       return 1;
414     }
415     else {
416       aS22 = DBRep::Get(a[2]);
417       if(aS22.IsNull()) {
418         di << "Error: second shape is null!" << "\n";
419         di << "Type bopargcheck without arguments for more information" << "\n";
420         return 1;
421       }
422     }
423   }
424   
425   // init checker
426   BOPAlgo_ArgumentAnalyzer aChecker;
427   aChecker.SetFuzzyValue(aTolerance);
428   aChecker.SetShape1(aS1);
429
430   // set default options (always tested!) for single and couple shapes
431   aChecker.ArgumentTypeMode()   = Standard_True;
432   aChecker.SelfInterMode()      = Standard_True;
433   aChecker.SmallEdgeMode()      = Standard_True;
434   aChecker.RebuildFaceMode()    = Standard_True;
435   aChecker.ContinuityMode()     = Standard_True;
436   aChecker.CurveOnSurfaceMode() = Standard_True;
437
438   // test & set options and operation for two shapes
439   if(!aS22.IsNull()) {
440     aS2 = BRepBuilderAPI_Copy(aS22).Shape();
441     aChecker.SetShape2(aS2);
442     // set operation (default - Section)
443     if(isBO) {
444       if(a[indxBO][1] == 'F' || a[indxBO][1] == 'f') {
445         aChecker.OperationType() = BOPAlgo_FUSE;
446       }
447       else if(a[indxBO][1] == 'O' || a[indxBO][1] == 'o') {
448         aChecker.OperationType() = BOPAlgo_COMMON;
449       }
450       else if(a[indxBO][1] == 'C' || a[indxBO][1] == 'c') {
451         aChecker.OperationType() = BOPAlgo_CUT;
452       }
453       else if(a[indxBO][1] == 'T' || a[indxBO][1] == 't') {
454          aChecker.OperationType() = BOPAlgo_CUT21;
455       }
456       else if(a[indxBO][1] == 'S' || a[indxBO][1] == 's') {
457          aChecker.OperationType() = BOPAlgo_SECTION;
458       }
459       else if(a[indxBO][1] == 'U' || a[indxBO][1] == 'u') {
460         aChecker.OperationType() = BOPAlgo_UNKNOWN;
461       }
462       else {
463         di << "Error: invalid boolean operation type!" << "\n";
464         di << "Type bopargcheck without arguments for more information" << "\n";
465         return 1;
466       }
467     }
468     else
469       aChecker.OperationType() = BOPAlgo_SECTION;
470
471     aChecker.TangentMode()     = Standard_True;
472     aChecker.MergeVertexMode() = Standard_True;
473     aChecker.MergeEdgeMode()   = Standard_True;
474   }
475   
476   // set options (default - all ON)
477   if(isOP) {
478     Standard_Integer ind = 1;
479     while(a[indxOP][ind] != 0) {
480       if(a[indxOP][ind] == 'R' || a[indxOP][ind] == 'r') {
481         aChecker.SmallEdgeMode() = Standard_False;
482       }
483       else if(a[indxOP][ind] == 'F' || a[indxOP][ind] == 'f') {
484         aChecker.RebuildFaceMode() = Standard_False;
485       }
486       else if(a[indxOP][ind] == 'T' || a[indxOP][ind] == 't') {
487         aChecker.TangentMode() = Standard_False;
488       }
489       else if(a[indxOP][ind] == 'V' || a[indxOP][ind] == 'v') {
490         aChecker.MergeVertexMode() = Standard_False;
491       }
492       else if(a[indxOP][ind] == 'E' || a[indxOP][ind] == 'e') {
493         aChecker.MergeEdgeMode() = Standard_False;
494       }
495       else if(a[indxOP][ind] == 'I' || a[indxOP][ind] == 'i') {
496         aChecker.SelfInterMode() = Standard_False;
497       }
498       else if(a[indxOP][ind] == 'P' || a[indxOP][ind] == 'p') {
499         aChecker.ArgumentTypeMode() = Standard_False;
500       }
501       else if(a[indxOP][ind] == 'C' || a[indxOP][ind] == 'c') {
502         aChecker.ContinuityMode() = Standard_False;
503       }
504       else if(a[indxOP][ind] == 'S' || a[indxOP][ind] == 's') {
505         aChecker.CurveOnSurfaceMode() = Standard_False;
506       }
507       else {
508         di << "Error: invalid test option(s)!" << "\n";
509         di << "Type bopargcheck without arguments for more information" << "\n";
510         return 1;
511       }
512       ind++;
513     }
514   }
515
516   // set additional options
517   Standard_Boolean fullOutput = Standard_False;
518   if(isAD) {
519     Standard_Integer ind = 1;
520     while(a[indxAD][ind] != 0) {
521       if(a[indxAD][ind] == 'B' || a[indxAD][ind] == 'b') {
522         aChecker.StopOnFirstFaulty() = Standard_True;
523       }
524       else if(a[indxAD][ind] == 'F' || a[indxAD][ind] == 'f') {
525         fullOutput = Standard_True;
526       }
527       else {
528         di << "Error: invalid additional test option(s)!" << "\n";
529         di << "Type bopargcheck without arguments for more information" << "\n";
530         return 1;
531       }
532       ind++;
533     }
534   }
535
536   // run checker
537   aChecker.Perform();
538
539   // process result of checking
540   if(!aChecker.HasFaulty()) {
541     di << "Shape(s) seem(s) to be valid for BOP."  << "\n";
542   }
543   else {
544     if(!fullOutput) {
545       di << "Faulties, that can not be treated by BOP, are detected." << "\n"; 
546     }
547     else {
548       const BOPAlgo_ListOfCheckResult& aResultList = aChecker.GetCheckResult();
549       BOPAlgo_ListIteratorOfListOfCheckResult anIt(aResultList);
550
551       Standard_Integer S1_BadType = 0, S1_SelfInt = 0, S1_SmalE = 0, S1_BadF = 0, S1_BadV = 0, S1_BadE = 0;
552       Standard_Integer S1_SelfIntAll = 0, S1_SmalEAll = 0, S1_BadFAll = 0, S1_BadVAll = 0, S1_BadEAll = 0;
553       Standard_Integer S2_BadType = 0, S2_SelfInt = 0, S2_SmalE = 0, S2_BadF = 0, S2_BadV = 0, S2_BadE = 0;
554       Standard_Integer S2_SelfIntAll = 0, S2_SmalEAll = 0, S2_BadFAll = 0, S2_BadVAll = 0, S2_BadEAll = 0;
555       Standard_Integer S1_OpAb = 0, S2_OpAb = 0;
556       Standard_Integer S1_C0 = 0, S2_C0 = 0, S1_C0All = 0, S2_C0All = 0;
557       Standard_Integer S1_COnS = 0, S2_COnS = 0, S1_COnSAll = 0, S2_COnSAll = 0;
558       Standard_Boolean hasUnknown = Standard_False;
559
560       TCollection_AsciiString aS1SIBaseName("s1si_");
561       TCollection_AsciiString aS1SEBaseName("s1se_");
562       TCollection_AsciiString aS1BFBaseName("s1bf_");
563       TCollection_AsciiString aS1BVBaseName("s1bv_");
564       TCollection_AsciiString aS1BEBaseName("s1be_");
565       TCollection_AsciiString aS1C0BaseName("s1C0_");
566       TCollection_AsciiString aS1COnSBaseName("s1COnS_");
567       TCollection_AsciiString aS2SIBaseName("s2si_");
568       TCollection_AsciiString aS2SEBaseName("s2se_");
569       TCollection_AsciiString aS2BFBaseName("s2bf_");
570       TCollection_AsciiString aS2BVBaseName("s2bv_");
571       TCollection_AsciiString aS2BEBaseName("s2be_");
572       TCollection_AsciiString aS2C0BaseName("s2C0_");
573       TCollection_AsciiString aS2COnSBaseName("s2COnS_");
574
575       for(; anIt.More(); anIt.Next()) {
576         const BOPAlgo_CheckResult& aResult = anIt.Value();
577         const TopoDS_Shape & aSS1 = aResult.GetShape1();
578         const TopoDS_Shape & aSS2 = aResult.GetShape2();
579         const BOPCol_ListOfShape & aLS1 = aResult.GetFaultyShapes1();
580         const BOPCol_ListOfShape & aLS2 = aResult.GetFaultyShapes2();
581         Standard_Boolean isL1 = !aLS1.IsEmpty();
582         Standard_Boolean isL2 = !aLS2.IsEmpty();
583
584         switch(aResult.GetCheckStatus()) {
585         case BOPAlgo_BadType: {
586           if(!aSS1.IsNull()) S1_BadType++;
587           if(!aSS2.IsNull()) S2_BadType++;
588         }
589           break;
590         case BOPAlgo_SelfIntersect: {
591           if(!aSS1.IsNull()) {
592             S1_SelfInt++;
593             if(isL1)
594               MakeShapeForFullOutput(aS1SIBaseName, S1_SelfInt, aLS1, S1_SelfIntAll, di);
595           }
596           if(!aSS2.IsNull()) {
597             S2_SelfInt++;
598             if(isL2)
599               MakeShapeForFullOutput(aS2SIBaseName, S2_SelfInt, aLS2, S2_SelfIntAll, di);
600           }
601         }
602           break;
603         case BOPAlgo_TooSmallEdge: {
604           if(!aSS1.IsNull()) {
605             S1_SmalE++;
606             if(isL1)
607               MakeShapeForFullOutput(aS1SEBaseName, S1_SmalE, aLS1, S1_SmalEAll, di);
608           }
609           if(!aSS2.IsNull()) {
610             S2_SmalE++;
611             if(isL2)
612               MakeShapeForFullOutput(aS2SEBaseName, S2_SmalE, aLS2, S2_SmalEAll, di);
613           }
614         }
615           break;
616         case BOPAlgo_NonRecoverableFace: {
617           if(!aSS1.IsNull()) {
618             S1_BadF++;
619             if(isL1)
620               MakeShapeForFullOutput(aS1BFBaseName, S1_BadF, aLS1, S1_BadFAll, di);
621           }
622           if(!aSS2.IsNull()) {
623             S2_BadF++;
624             if(isL2)
625               MakeShapeForFullOutput(aS2BFBaseName, S2_BadF, aLS2, S2_BadFAll, di);
626           }
627         }
628           break;
629         case BOPAlgo_IncompatibilityOfVertex: {
630           if(!aSS1.IsNull()) {
631             S1_BadV++;
632             if(isL1) {
633               MakeShapeForFullOutput(aS1BVBaseName, S1_BadV, aLS1, S1_BadVAll, di);
634             }
635           }
636           if(!aSS2.IsNull()) {
637             S2_BadV++;
638             if(isL2){
639               MakeShapeForFullOutput(aS2BVBaseName, S2_BadV, aLS2, S2_BadVAll, di);
640             }
641           }
642         }
643           break;
644         case BOPAlgo_IncompatibilityOfEdge: {
645           if(!aSS1.IsNull()) {
646             S1_BadE++;
647             if(isL1) {
648               MakeShapeForFullOutput(aS1BEBaseName, S1_BadE, aLS1, S1_BadEAll, di);
649             }
650           }
651           if(!aSS2.IsNull()) {
652             S2_BadE++;
653             if(isL2) {
654               MakeShapeForFullOutput(aS2BEBaseName, S2_BadE, aLS2, S2_BadEAll, di);
655             }
656           }
657         }
658           break;
659         case BOPAlgo_IncompatibilityOfFace: {
660           // not yet implemented
661         }
662           break;
663         case BOPAlgo_GeomAbs_C0: {
664           if(!aSS1.IsNull()) {
665             S1_C0++;
666             if(isL1) {
667               MakeShapeForFullOutput(aS1C0BaseName, S1_C0, aLS1, S1_C0All, di);
668             }
669           }
670           if(!aSS2.IsNull()) {
671             S2_C0++;
672             if(isL2) {
673               MakeShapeForFullOutput(aS2C0BaseName, S2_C0, aLS2, S2_C0All, di);
674             }
675           }
676         }
677           break;
678         case BOPAlgo_InvalidCurveOnSurface: {
679           if(!aSS1.IsNull()) {
680             S1_COnS++;
681             if(isL1) {
682               Standard_Real aMaxDist = aResult.GetMaxDistance1();
683               Standard_Real aMaxParameter = aResult.GetMaxParameter1();
684               MakeShapeForFullOutput(aS1COnSBaseName, S1_COnS, aLS1, S1_COnSAll, di,
685                                      Standard_True, aMaxDist, aMaxParameter);
686             }
687           }
688           if(!aSS2.IsNull()) {
689             S2_COnS++;
690             if(isL2) {
691               Standard_Real aMaxDist = aResult.GetMaxDistance2();
692               Standard_Real aMaxParameter = aResult.GetMaxParameter2();
693               MakeShapeForFullOutput(aS2COnSBaseName, S2_COnS, aLS2, S2_COnSAll, di,
694                                      Standard_True, aMaxDist, aMaxParameter);
695             }
696           }
697         }
698           break;
699         case BOPAlgo_OperationAborted: {
700           if(!aSS1.IsNull()) S1_OpAb++;
701           if(!aSS2.IsNull()) S2_OpAb++;
702         }
703           break;
704         case BOPAlgo_CheckUnknown:
705         default: {
706           hasUnknown = Standard_True;
707         }
708           break;
709         } // switch
710       }// faulties
711
712       Standard_Integer FS1 = S1_SelfInt + S1_SmalE + S1_BadF + S1_BadV + S1_BadE + S1_OpAb + S1_C0 + S1_COnS;
713       FS1 += (S1_BadType != 0) ? 1 : 0;
714       Standard_Integer FS2 = S2_SelfInt + S2_SmalE + S2_BadF + S2_BadV + S2_BadE + S2_OpAb + S2_C0 + S2_COnS;
715       FS2 += (S2_BadType != 0) ? 1 : 0;
716       
717       // output for first shape
718       di << "Faulties for FIRST  shape found : " << FS1 << "\n";
719       if(FS1 != 0) {
720         di << "---------------------------------" << "\n";
721         Standard_CString CString1;
722         if (S1_BadType != 0)
723           CString1="YES";
724         else
725           CString1=aChecker.ArgumentTypeMode() ? "NO" : "DISABLED";
726         di << "Shapes are not suppotrted by BOP: " << CString1 << "\n";
727         Standard_CString CString2;
728         if (S1_SelfInt != 0)
729           CString2="YES";
730         else
731           CString2=aChecker.SelfInterMode() ? "NO" : "DISABLED";
732         di << "Self-Intersections              : " << CString2;
733         if(S1_SelfInt != 0)
734           di << "  Cases(" << S1_SelfInt << ")  Total shapes(" << S1_SelfIntAll << ")" << "\n";
735         else
736           di << "\n";
737         Standard_CString CString13;
738         if (S1_OpAb != 0)
739           CString13="YES";
740         else
741           CString13=aChecker.SelfInterMode() ? "NO" : "DISABLED";
742         di << "Check for SI has been aborted   : " << CString13 << "\n";
743         Standard_CString CString3;
744         if (S1_SmalE != 0)
745           CString3="YES";
746         else
747           CString3=aChecker.SmallEdgeMode() ? "NO" : "DISABLED";
748         di << "Too small edges                 : " << CString3;
749         if(S1_SmalE != 0)
750           di << "  Cases(" << S1_SmalE << ")  Total shapes(" << S1_SmalEAll << ")" << "\n";
751         else
752           di << "\n";
753         Standard_CString CString4;
754         if (S1_BadF != 0)
755           CString4="YES";
756         else
757           CString4=aChecker.RebuildFaceMode() ? "NO" : "DISABLED";
758         di << "Bad faces                       : " << CString4;
759         if(S1_BadF != 0)
760           di << "  Cases(" << S1_BadF << ")  Total shapes(" << S1_BadFAll << ")" << "\n";
761         else
762           di << "\n";
763         Standard_CString CString5;
764         if (S1_BadV != 0)
765           CString5="YES";
766         else
767           CString5=aChecker.MergeVertexMode() ? "NO" : "DISABLED";
768         di << "Too close vertices              : " << CString5;
769         if(S1_BadV != 0)
770           di << "  Cases(" << S1_BadV << ")  Total shapes(" << S1_BadVAll << ")" << "\n";
771         else
772           di << "\n";
773         Standard_CString CString6;
774         if (S1_BadE != 0)
775           CString6="YES";
776         else
777           CString6=aChecker.MergeEdgeMode() ? "NO" : "DISABLED";
778         di << "Too close edges                 : " << CString6;
779         if(S1_BadE != 0)
780           di << "  Cases(" << S1_BadE << ")  Total shapes(" << S1_BadEAll << ")" << "\n";
781         else
782           di << "\n";
783         Standard_CString CString15;
784         if (S1_C0 != 0)
785           CString15="YES";
786         else
787           CString15=aChecker.ContinuityMode() ? "NO" : "DISABLED";
788         di << "Shapes with Continuity C0       : " << CString15;
789         if(S1_C0 != 0)
790           di << "  Cases(" << S1_C0 << ")  Total shapes(" << S1_C0All << ")" << "\n";
791         else
792           di << "\n";
793
794         Standard_CString CString17;
795         if (S1_COnS != 0)
796           CString17="YES";
797         else
798           CString17=aChecker.CurveOnSurfaceMode() ? "NO" : "DISABLED";
799         di << "Invalid Curve on Surface        : " << CString17;
800         if(S1_COnS != 0)
801           di << "  Cases(" << S1_COnS << ")  Total shapes(" << S1_COnSAll << ")" << "\n";
802         else
803           di << "\n";
804       }
805
806       // output for second shape
807       di << "\n";
808       di << "Faulties for SECOND  shape found : " << FS2 << "\n";
809       if(FS2 != 0) {
810         di << "---------------------------------" << "\n";
811         Standard_CString CString7;
812         if (S2_BadType != 0)
813           CString7="YES";
814         else
815           CString7=aChecker.ArgumentTypeMode() ? "NO" : "DISABLED";
816         di << "Shapes are not suppotrted by BOP: " << CString7 << "\n";
817         Standard_CString CString8;
818         if (S2_SelfInt != 0)
819           CString8="YES";
820         else
821           CString8=aChecker.SelfInterMode() ? "NO" : "DISABLED";
822         di << "Self-Intersections              : " << CString8;
823         if(S2_SelfInt != 0)
824           di << "  Cases(" << S2_SelfInt << ")  Total shapes(" << S2_SelfIntAll << ")" << "\n";
825         else
826           di << "\n";
827
828         Standard_CString CString14;
829         if (S2_OpAb != 0)
830           CString14="YES";
831         else
832           CString14=aChecker.SelfInterMode() ? "NO" : "DISABLED";
833         di << "Check for SI has been aborted   : " << CString14 << "\n";
834         Standard_CString CString9;
835         if (S2_SmalE != 0)
836           CString9="YES";
837         else
838           CString9=aChecker.SmallEdgeMode() ? "NO" : "DISABLED";
839         di << "Too small edges                 : " << CString9;
840         if(S2_SmalE != 0)
841           di << "  Cases(" << S2_SmalE << ")  Total shapes(" << S2_SmalEAll << ")" << "\n";
842         else
843           di << "\n";
844         Standard_CString CString10;
845         if (S2_BadF != 0)
846           CString10="YES";
847         else
848           CString10=aChecker.RebuildFaceMode() ? "NO" : "DISABLED";
849         di << "Bad faces                       : " << CString10;
850         if(S2_BadF != 0)
851           di << "  Cases(" << S2_BadF << ")  Total shapes(" << S2_BadFAll << ")" << "\n";
852         else
853           di << "\n";
854         Standard_CString CString11;
855         if (S2_BadV != 0)
856           CString11="YES";
857         else
858           CString11=aChecker.MergeVertexMode() ? "NO" : "DISABLED";
859         di << "Too close vertices              : " << CString11;
860         if(S2_BadV != 0)
861           di << "  Cases(" << S2_BadV << ")  Total shapes(" << S2_BadVAll << ")" << "\n";
862         else
863           di << "\n";
864         Standard_CString CString12;
865         if (S2_BadE != 0)
866           CString12="YES";
867         else
868           CString12=aChecker.MergeEdgeMode() ? "NO" : "DISABLED";
869         di << "Too close edges                 : " << CString12;
870         if(S2_BadE != 0)
871           di << "  Cases(" << S2_BadE << ")  Total shapes(" << S2_BadEAll << ")" << "\n";
872         else
873           di << "\n";
874         Standard_CString CString16;
875         if (S2_C0 != 0)
876           CString16="YES";
877         else
878           CString16=aChecker.ContinuityMode() ? "NO" : "DISABLED";
879         di << "Shapes with Continuity C0       : " << CString16;
880         if(S2_C0 != 0)
881           di << "  Cases(" << S2_C0 << ")  Total shapes(" << S2_C0All << ")" << "\n";
882         else
883           di << "\n";
884
885         Standard_CString CString18;
886         if (S2_COnS != 0)
887           CString18="YES";
888         else
889           CString18=aChecker.CurveOnSurfaceMode() ? "NO" : "DISABLED";
890         di << "Invalid Curve on Surface        : " << CString18;
891         if(S2_COnS != 0)
892           di << "  Cases(" << S2_COnS << ")  Total shapes(" << S2_COnSAll << ")" << "\n";
893         else
894           di << "\n";
895       }
896       // warning
897       if(hasUnknown) {
898         di << "\n";
899         di << "WARNING: The unexpected test break occurs!" << "\n";
900       }
901     } // full output
902   } // has faulties
903
904   return 0;
905 }
906
907 //=======================================================================
908 //function : xdistef
909 //purpose  : 
910 //=======================================================================
911 Standard_Integer xdistef(Draw_Interpretor& di,
912                          Standard_Integer n,
913                          const char** a)
914 {
915   if(n < 3) {
916     di << "use xdistef edge face\n";
917     return 1;
918   }
919   //
920   const TopoDS_Shape aS1 = DBRep::Get(a[1]);
921   const TopoDS_Shape aS2 = DBRep::Get(a[2]);
922   //
923   if (aS1.IsNull() || aS2.IsNull()) {
924     di << "null shapes\n";
925     return 1;
926   }
927   //
928   if (aS1.ShapeType() != TopAbs_EDGE || 
929       aS2.ShapeType() != TopAbs_FACE) {
930     di << "type mismatch\n";
931     return 1;
932   }
933   //
934   Standard_Real aMaxDist = 0.0, aMaxPar = 0.0;
935   //
936   const TopoDS_Edge& anEdge = *(TopoDS_Edge*)&aS1;
937   const TopoDS_Face& aFace  = *(TopoDS_Face*)&aS2;
938   //
939   if(!BOPTools_AlgoTools::ComputeTolerance
940      (aFace, anEdge, aMaxDist, aMaxPar)) {
941     di << "Tolerance cannot be computed\n";
942     return 1;
943   }
944   //
945   di << "Max Distance = " << aMaxDist 
946      << "; Parameter on curve = " << aMaxPar << "\n";
947   //
948   return 0;
949 }
950
951 //=======================================================================
952 //function : checkcurveonsurf
953 //purpose  : 
954 //=======================================================================
955 Standard_Integer checkcurveonsurf(Draw_Interpretor& di,
956                                   Standard_Integer n, 
957                                   const char** a)
958 {
959   if (n != 2) {
960     di << "use checkcurveonsurf shape\n";
961     return 1;
962   }
963   //
964   TopoDS_Shape aS =  DBRep::Get(a[1]);
965   if (aS.IsNull()) {
966     di << "null shape\n";
967     return 1;
968   }
969   //
970   Standard_Integer nE, nF, anECounter, aFCounter;
971   Standard_Real aT, aTolE, aDMax;
972   TopExp_Explorer aExpF, aExpE;
973   char buf[200], aFName[10], anEName[10];
974   NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher> aDMETol;
975   BOPCol_DataMapOfShapeInteger aMSI;
976   //
977   anECounter = 0;
978   aFCounter  = 0;
979   //
980   aExpF.Init(aS, TopAbs_FACE);
981   for (; aExpF.More(); aExpF.Next()) {
982     const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
983     //
984     aExpE.Init(aF, TopAbs_EDGE);
985     for (; aExpE.More(); aExpE.Next()) {
986       const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
987       //
988       if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) {
989         continue;
990       }
991       //
992       aTolE = BRep_Tool::Tolerance(aE);
993       if (!(aDMax > aTolE)) {
994         continue;
995       }
996       //
997       if (aDMETol.IsBound(aE)) {
998         Standard_Real& aD = aDMETol.ChangeFind(aE);
999         if (aDMax > aD) {
1000           aD = aDMax;
1001         }
1002       }
1003       else {
1004         aDMETol.Bind(aE, aDMax);
1005       }
1006       //
1007       if (anECounter == 0) {
1008         di << "Invalid curves on surface:\n";
1009       }
1010       //
1011       if (aMSI.IsBound(aE)) {
1012         nE = aMSI.Find(aE);
1013       }
1014       else {
1015         nE = anECounter;
1016         aMSI.Bind(aE, nE);
1017         ++anECounter;
1018       }
1019       //
1020       if (aMSI.IsBound(aF)) {
1021         nF = aMSI.Find(aF);
1022       } else {
1023         nF = aFCounter;
1024         aMSI.Bind(aF, nF);
1025         ++aFCounter;
1026       }
1027       //
1028       sprintf(anEName, "e_%d", nE);
1029       sprintf(aFName , "f_%d", nF);
1030       sprintf(buf, "edge %s on face %s (max dist: %3.16f, parameter on curve: %3.16f)\n",
1031               anEName, aFName, aDMax, aT);
1032       di << buf;
1033       //
1034       DBRep::Set(anEName, aE);
1035       DBRep::Set(aFName , aF);
1036     }
1037   }
1038   //
1039   if (anECounter > 0) {
1040     di << "\n\nSugestions to fix the shape:\n";
1041     di << "explode " << a[1] << " e;\n";
1042     //
1043     TopTools_MapOfShape M;
1044     aExpE.Init(aS, TopAbs_EDGE);
1045     for (anECounter = 0; aExpE.More(); aExpE.Next()) {
1046       const TopoDS_Shape& aE = aExpE.Current();
1047       if (!M.Add(aE)) {
1048         continue;
1049       }
1050       ++anECounter;
1051       //
1052       if (!aDMETol.IsBound(aE)) {
1053         continue;
1054       }
1055       //
1056       aTolE = aDMETol.Find(aE);
1057       aTolE *= 1.001;
1058       sprintf(buf, "settolerance %s_%d %3.16f;\n", a[1], anECounter, aTolE);
1059       di << buf;
1060     }
1061   }
1062   else {
1063     di << "This shape seems to be OK.\n";
1064   }
1065   //
1066   return 0;
1067 }
1068
1069 //=======================================================================
1070 //function : MakeShapeForFullOutput
1071 //purpose  : 
1072 //=======================================================================
1073 void MakeShapeForFullOutput (const TCollection_AsciiString & aBaseName,
1074                              const Standard_Integer          aIndex,
1075                              const BOPCol_ListOfShape &      aList,
1076                              Standard_Integer&               aCount,
1077                              Draw_Interpretor&               di,
1078                              Standard_Boolean                bCurveOnSurf,
1079                              Standard_Real                   aMaxDist,
1080                              Standard_Real                   aMaxParameter)
1081 {
1082   TCollection_AsciiString aNum(aIndex);
1083   TCollection_AsciiString aName = aBaseName + aNum;
1084   Standard_CString name = aName.ToCString();
1085
1086   TopoDS_Compound cmp;
1087   BRep_Builder BB;
1088   BB.MakeCompound(cmp);
1089
1090   BOPCol_ListIteratorOfListOfShape anIt(aList);
1091   for(; anIt.More(); anIt.Next()) {
1092     const TopoDS_Shape & aS = anIt.Value();
1093     BB.Add(cmp, aS);
1094     aCount++;
1095   }
1096   di << "Made faulty shape: " << name;
1097   //
1098   if (bCurveOnSurf) {
1099     di << " (MaxDist = " << aMaxDist 
1100        << ", MaxPar = " << aMaxParameter << ")";
1101   }
1102   //
1103   di << "\n";
1104   //
1105   DBRep::Set(name, cmp);
1106 }