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