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