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