1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2012 OPEN CASCADE SAS
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
20 #include <BOPTest.ixx>
21 #include <TCollection_AsciiString.hxx>
25 #include <TopoDS_Shape.hxx>
26 #include <TopoDS_Compound.hxx>
27 #include <BRep_Builder.hxx>
31 #include <Geom_Geometry.hxx>
32 #include <Geom_CartesianPoint.hxx>
35 #include <DrawTrSurf.hxx>
36 #include <BOPAlgo_CheckerSI.hxx>
37 #include <BOPDS_VectorOfInterfVV.hxx>
38 #include <BOPDS_VectorOfInterfVE.hxx>
39 #include <BOPDS_VectorOfInterfEE.hxx>
40 #include <BOPDS_VectorOfInterfVF.hxx>
41 #include <BOPDS_VectorOfInterfEF.hxx>
42 #include <BOPDS_VectorOfInterfFF.hxx>
43 #include <BOPDS_DS.hxx>
45 #include <BOPCol_ListOfShape.hxx>
46 #include <BOPAlgo_ArgumentAnalyzer.hxx>
47 #include <BOPAlgo_CheckResult.hxx>
48 #include <BRepBuilderAPI_Copy.hxx>
51 Standard_Integer bopcheck (Draw_Interpretor&, Standard_Integer, const char** );
54 Standard_Integer bopargcheck (Draw_Interpretor&, Standard_Integer, const char** );
57 //=======================================================================
58 //function : CheckCommands
60 //=======================================================================
61 void BOPTest::CheckCommands(Draw_Interpretor& theCommands)
63 static Standard_Boolean done = Standard_False;
69 const char* g = "CCR commands";
71 theCommands.Add("bopcheck" , "Use >bopcheck Shape", __FILE__, bopcheck, g);
72 theCommands.Add("bopargcheck" , "Use bopargcheck without parameters to get ", __FILE__, bopargcheck, g);
75 //=======================================================================
78 //=======================================================================
79 Standard_Integer bopcheck (Draw_Interpretor& di, Standard_Integer n, const char** a )
83 di << " Use >bopcheck Shape" << "\n";
87 TopoDS_Shape aS1 = DBRep::Get(a[1]);
89 di << "null shapes are not allowed here!";
92 TopoDS_Shape aS = BRepBuilderAPI_Copy(aS1).Shape();
94 Standard_Integer iErr, aTypeInt, i, ind, j;
95 Standard_Integer nI1, nI2;
96 Standard_Boolean bSelfInt, bFFInt;
99 BOPAlgo_CheckerSI aChecker;
100 BOPCol_ListOfShape anArgs;
102 aChecker.SetArguments(anArgs);
105 iErr = aChecker.ErrorStatus();
107 const BOPDS_PDS& theDS = aChecker.PDS();
108 BOPDS_VectorOfInterfVV& aVVs=theDS->InterfVV();
109 BOPDS_VectorOfInterfVE& aVEs=theDS->InterfVE();
110 BOPDS_VectorOfInterfEE& aEEs=theDS->InterfEE();
111 BOPDS_VectorOfInterfVF& aVFs=theDS->InterfVF();
112 BOPDS_VectorOfInterfEF& aEFs=theDS->InterfEF();
113 BOPDS_VectorOfInterfFF& aFFs=theDS->InterfFF();
115 Standard_Integer aNb[6] = {aVVs.Extent(), aVEs.Extent(), aEEs.Extent(),
116 aVFs.Extent(), aEFs.Extent(), aFFs.Extent()};
117 char type[6][5] = {"V/V:", "V/E:", "E/E:","V/F:", "E/F:", "F/F:"};
120 bSelfInt = Standard_False;
122 for (aTypeInt = 0; aTypeInt < 6; ++aTypeInt) {
123 for (i = 0; i < aNb[aTypeInt]; ++i) {
124 BOPDS_Interf* aInt = (aTypeInt==0) ? (BOPDS_Interf*)(&aVVs(i)) :
125 ((aTypeInt==1) ? (BOPDS_Interf*)(&aVEs(i)) :
126 ((aTypeInt==2) ? (BOPDS_Interf*)(&aEEs(i)) :
127 ((aTypeInt==3) ? (BOPDS_Interf*)(&aVFs(i)) :
128 ((aTypeInt==4) ? (BOPDS_Interf*)(&aEFs(i)) : (BOPDS_Interf*)(&aFFs(i))))));
130 nI1 = aInt->Index1();
131 nI2 = aInt->Index2();
136 const TopoDS_Shape& aS1 = theDS->Shape(nI1);
137 const TopoDS_Shape& aS2 = theDS->Shape(nI2);
140 bFFInt = Standard_False;
141 BOPDS_InterfFF& aFF = aFFs(i);
142 BOPDS_VectorOfPoint& aVP=aFF.ChangePoints();
143 Standard_Integer aNbP=aVP.Extent();
144 BOPDS_VectorOfCurve& aVC=aFF.ChangeCurves();
145 Standard_Integer aNbC=aVC.Extent();
146 if (!aNbP && !aNbC) {
149 for (j=0; j<aNbC; ++j) {
150 BOPDS_Curve& aNC=aVC(j);
151 BOPDS_ListOfPaveBlock& aLPBC=aNC.ChangePaveBlocks();
152 if (aLPBC.Extent()) {
153 bFFInt = Standard_True;
162 di << type[aTypeInt];
164 TCollection_AsciiString aBaseName("x");
165 TCollection_AsciiString anumbername(ind);
166 TCollection_AsciiString aXName = aBaseName + anumbername;
167 Standard_CString aname=aXName.ToCString();
168 DBRep::Set (aname, aS1);
170 TCollection_AsciiString anumbername1(ind);
171 TCollection_AsciiString aXName1 = aBaseName + anumbername1;
172 Standard_CString aname1=aXName1.ToCString();
173 DBRep::Set (aname1, aS2);
176 Sprintf(buf, "%s, %s \n", aname, aname1);
178 bSelfInt = Standard_True;
183 di << "There were errors during the operation, so the list may be incomplete." << "\n";
187 di << " This shape seems to be OK." << "\n";
193 static void MakeShapeForFullOutput(const TCollection_AsciiString & aBaseName,
194 const Standard_Integer aIndex,
195 const BOPCol_ListOfShape & aList,
196 Standard_Integer& aCount,
197 Draw_Interpretor& di)
199 TCollection_AsciiString aNum(aIndex);
200 TCollection_AsciiString aName = aBaseName + aNum;
201 Standard_CString name = aName.ToCString();
205 BB.MakeCompound(cmp);
207 BOPCol_ListIteratorOfListOfShape anIt(aList);
208 for(; anIt.More(); anIt.Next()) {
209 const TopoDS_Shape & aS = anIt.Value();
213 di << "Made faulty shape: " << name << "\n";
214 DBRep::Set(name, cmp);
218 Standard_Integer bopargcheck (Draw_Interpretor& di, Standard_Integer n, const char** a )
222 di << " Use >bopargcheck Shape1 [[Shape2] [-F/O/C/T/S/U] [/R|F|T|V|E|I|P]] [#BF]" << "\n" << "\n";
223 di << " -<Boolean Operation>" << "\n";
224 di << " F (fuse)" << "\n";
225 di << " O (common)" << "\n";
226 di << " C (cut)" << "\n";
227 di << " T (cut21)" << "\n";
228 di << " S (section)" << "\n";
229 di << " U (unknown)" << "\n";
230 di << " For example: \"bopargcheck s1 s2 -F\" enables checking for Fuse operation" << "\n";
231 di << " default - section" << "\n" << "\n";
232 di << " /<Test Options>" << "\n";
233 di << " R (disable small edges (shrank range) test)" << "\n";
234 di << " F (disable faces verification test)" << "\n";
235 di << " T (disable tangent faces searching test)" << "\n";
236 di << " V (disable test possibility to merge vertices)" << "\n";
237 di << " E (disable test possibility to merge edges)" << "\n";
238 di << " I (disable self-interference test)" << "\n";
239 di << " P (disable shape type test)" << "\n";
240 di << " For example: \"bopargcheck s1 s2 /RI\" disables small edge detection and self-intersection detection" << "\n";
241 di << " default - all options are enabled" << "\n" << "\n";
242 di << " #<Additional Test Options>" << "\n";
243 di << " B (stop test on first faulty found); default OFF" << "\n";
244 di << " F (full output for faulty shapes); default - output in a short format" << "\n" << "\n";
245 di << " NOTE: <Boolean Operation> and <Test Options> are used only for couple" << "\n";
246 di << " of argument shapes, except I and P options that are always used for" << "\n";
247 di << " couple of shapes as well as for single shape test." << "\n";
251 TopoDS_Shape aS11 = DBRep::Get(a[1]);
254 di << "Error: null shape not allowed!" << "\n";
255 di << "Type bopargcheck without arguments for more information" << "\n";
258 TopoDS_Shape aS1 = BRepBuilderAPI_Copy(aS11).Shape();
261 Standard_Boolean isBO = Standard_False;
262 Standard_Integer indxBO = 0;
263 Standard_Boolean isOP = Standard_False;
264 Standard_Integer indxOP = 0;
265 Standard_Boolean isAD = Standard_False;
266 Standard_Integer indxAD = 0;
267 Standard_Boolean isS2 = Standard_False;
268 Standard_Integer indxS2 = 0;
271 Standard_Integer iIndex = 0;
272 for(iIndex = 2; iIndex < n; iIndex++) {
273 if(a[iIndex][0] == '-')
275 isBO = Standard_True;
278 //else if(a[iIndex][0] == '+')
279 else if(a[iIndex][0] == '/')
281 isOP = Standard_True;
284 else if(a[iIndex][0] == '#')
286 isAD = Standard_True;
290 isS2 = Standard_True;
296 // set & test second shape
297 TopoDS_Shape aS22, aS2;
300 di << "Error: second shape should follow the first one!" << "\n";
301 di << "Type bopargcheck without arguments for more information" << "\n";
305 aS22 = DBRep::Get(a[2]);
307 di << "Error: second shape is null!" << "\n";
308 di << "Type bopargcheck without arguments for more information" << "\n";
315 BOPAlgo_ArgumentAnalyzer aChecker;
316 aChecker.SetShape1(aS1);
318 // set default options (always tested!) for single and couple shapes
319 aChecker.ArgumentTypeMode() = Standard_True;
320 aChecker.SelfInterMode() = Standard_True;
322 // test & set options and operation for two shapes
324 aS2 = BRepBuilderAPI_Copy(aS22).Shape();
325 aChecker.SetShape2(aS2);
326 // set operation (default - Section)
328 if(a[indxBO][1] == 'F' || a[indxBO][1] == 'f') {
329 aChecker.OperationType() = BOPAlgo_FUSE;
331 else if(a[indxBO][1] == 'O' || a[indxBO][1] == 'o') {
332 aChecker.OperationType() = BOPAlgo_COMMON;
334 else if(a[indxBO][1] == 'C' || a[indxBO][1] == 'c') {
335 aChecker.OperationType() = BOPAlgo_CUT;
337 else if(a[indxBO][1] == 'T' || a[indxBO][1] == 't') {
338 aChecker.OperationType() = BOPAlgo_CUT21;
340 else if(a[indxBO][1] == 'S' || a[indxBO][1] == 's') {
341 aChecker.OperationType() = BOPAlgo_SECTION;
343 else if(a[indxBO][1] == 'U' || a[indxBO][1] == 'u') {
344 aChecker.OperationType() = BOPAlgo_UNKNOWN;
347 di << "Error: invalid boolean operation type!" << "\n";
348 di << "Type bopargcheck without arguments for more information" << "\n";
353 aChecker.OperationType() = BOPAlgo_SECTION;
355 aChecker.SmallEdgeMode() = Standard_True;
356 aChecker.RebuildFaceMode() = Standard_True;
357 aChecker.TangentMode() = Standard_True;
358 aChecker.MergeVertexMode() = Standard_True;
359 aChecker.MergeEdgeMode() = Standard_True;
361 // set options (default - all ON)
363 Standard_Integer ind = 1;
364 while(a[indxOP][ind] != 0) {
365 if(a[indxOP][ind] == 'R' || a[indxOP][ind] == 'r') {
366 //aChecker.SmallEdgeMode() = Standard_True;
367 aChecker.SmallEdgeMode() = Standard_False;
369 else if(a[indxOP][ind] == 'F' || a[indxOP][ind] == 'f') {
370 //aChecker.RebuildFaceMode() = Standard_True;
371 aChecker.RebuildFaceMode() = Standard_False;
373 else if(a[indxOP][ind] == 'T' || a[indxOP][ind] == 't') {
374 //aChecker.TangentMode() = Standard_True;
375 aChecker.TangentMode() = Standard_False;
377 else if(a[indxOP][ind] == 'V' || a[indxOP][ind] == 'v') {
378 //aChecker.MergeVertexMode() = Standard_True;
379 aChecker.MergeVertexMode() = Standard_False;
381 else if(a[indxOP][ind] == 'E' || a[indxOP][ind] == 'e') {
382 //aChecker.MergeEdgeMode() = Standard_True;
383 aChecker.MergeEdgeMode() = Standard_False;
385 else if(a[indxOP][ind] == 'I' || a[indxOP][ind] == 'i') {
386 aChecker.SelfInterMode() = Standard_False;
388 else if(a[indxOP][ind] == 'P' || a[indxOP][ind] == 'p') {
389 aChecker.ArgumentTypeMode() = Standard_False;
392 di << "Error: invalid test option(s)!" << "\n";
393 di << "Type bopargcheck without arguments for more information" << "\n";
400 // default test mode (all - ON)
401 aChecker.SmallEdgeMode() = Standard_True;
402 aChecker.RebuildFaceMode() = Standard_True;
403 aChecker.TangentMode() = Standard_True;
404 aChecker.MergeVertexMode() = Standard_True;
405 aChecker.MergeEdgeMode() = Standard_True;
409 // check type and self-interference mode for single shape test
410 // also check small edges and check faces
411 aChecker.SmallEdgeMode() = Standard_True;
412 aChecker.RebuildFaceMode() = Standard_True;
415 Standard_Integer ind = 1;
416 while(a[indxOP][ind] != 0) {
417 if(a[indxOP][ind] == 'R' || a[indxOP][ind] == 'r') {
419 else if(a[indxOP][ind] == 'F' || a[indxOP][ind] == 'f') {
421 else if(a[indxOP][ind] == 'T' || a[indxOP][ind] == 't') {
423 else if(a[indxOP][ind] == 'V' || a[indxOP][ind] == 'v') {
425 else if(a[indxOP][ind] == 'E' || a[indxOP][ind] == 'e') {
427 else if(a[indxOP][ind] == 'I' || a[indxOP][ind] == 'i') {
428 aChecker.SelfInterMode() = Standard_False;
430 else if(a[indxOP][ind] == 'P' || a[indxOP][ind] == 'p') {
431 aChecker.ArgumentTypeMode() = Standard_False;
434 di << "Error: invalid test option(s)!" << "\n";
435 di << "Type bopargcheck without arguments for more information" << "\n";
443 // set additional options
444 Standard_Boolean fullOutput = Standard_False;
446 Standard_Integer ind = 1;
447 while(a[indxAD][ind] != 0) {
448 if(a[indxAD][ind] == 'B' || a[indxAD][ind] == 'b') {
449 aChecker.StopOnFirstFaulty() = Standard_True;
451 else if(a[indxAD][ind] == 'F' || a[indxAD][ind] == 'f') {
452 fullOutput = Standard_True;
455 di << "Error: invalid additional test option(s)!" << "\n";
456 di << "Type bopargcheck without arguments for more information" << "\n";
466 // process result of checking
467 if(!aChecker.HasFaulty()) {
468 di << "Shape(s) seem(s) to be valid for BOP." << "\n";
472 di << "Faulties, that can not be treated by BOP, are detected." << "\n";
475 const BOPAlgo_ListOfCheckResult& aResultList = aChecker.GetCheckResult();
476 BOPAlgo_ListIteratorOfListOfCheckResult anIt(aResultList);
478 Standard_Integer S1_BadType = 0, S1_SelfInt = 0, S1_SmalE = 0, S1_BadF = 0, S1_BadV = 0, S1_BadE = 0;
479 Standard_Integer S1_SelfIntAll = 0, S1_SmalEAll = 0, S1_BadFAll = 0, S1_BadVAll = 0, S1_BadEAll = 0;
480 Standard_Integer S2_BadType = 0, S2_SelfInt = 0, S2_SmalE = 0, S2_BadF = 0, S2_BadV = 0, S2_BadE = 0;
481 Standard_Integer S2_SelfIntAll = 0, S2_SmalEAll = 0, S2_BadFAll = 0, S2_BadVAll = 0, S2_BadEAll = 0;
482 Standard_Integer S1_OpAb = 0, S2_OpAb = 0;
483 Standard_Boolean hasUnknown = Standard_False;
485 TCollection_AsciiString aS1SIBaseName("s1si_");
486 TCollection_AsciiString aS1SEBaseName("s1se_");
487 TCollection_AsciiString aS1BFBaseName("s1bf_");
488 TCollection_AsciiString aS1BVBaseName("s1bv_");
489 TCollection_AsciiString aS1BEBaseName("s1be_");
490 TCollection_AsciiString aS2SIBaseName("s2si_");
491 TCollection_AsciiString aS2SEBaseName("s2se_");
492 TCollection_AsciiString aS2BFBaseName("s2bf_");
493 TCollection_AsciiString aS2BVBaseName("s2bv_");
494 TCollection_AsciiString aS2BEBaseName("s2be_");
496 for(; anIt.More(); anIt.Next()) {
497 const BOPAlgo_CheckResult& aResult = anIt.Value();
498 const TopoDS_Shape & aSS1 = aResult.GetShape1();
499 const TopoDS_Shape & aSS2 = aResult.GetShape2();
500 const BOPCol_ListOfShape & aLS1 = aResult.GetFaultyShapes1();
501 const BOPCol_ListOfShape & aLS2 = aResult.GetFaultyShapes2();
502 Standard_Boolean isL1 = !aLS1.IsEmpty();
503 Standard_Boolean isL2 = !aLS2.IsEmpty();
505 switch(aResult.GetCheckStatus()) {
506 case BOPAlgo_BadType: {
507 if(!aSS1.IsNull()) S1_BadType++;
508 if(!aSS2.IsNull()) S2_BadType++;
511 case BOPAlgo_SelfIntersect: {
515 MakeShapeForFullOutput(aS1SIBaseName, S1_SelfInt, aLS1, S1_SelfIntAll, di);
520 MakeShapeForFullOutput(aS2SIBaseName, S2_SelfInt, aLS2, S2_SelfIntAll, di);
524 case BOPAlgo_TooSmallEdge: {
528 MakeShapeForFullOutput(aS1SEBaseName, S1_SmalE, aLS1, S1_SmalEAll, di);
533 MakeShapeForFullOutput(aS2SEBaseName, S2_SmalE, aLS2, S2_SmalEAll, di);
537 case BOPAlgo_NonRecoverableFace: {
541 MakeShapeForFullOutput(aS1BFBaseName, S1_BadF, aLS1, S1_BadFAll, di);
546 MakeShapeForFullOutput(aS2BFBaseName, S2_BadF, aLS2, S2_BadFAll, di);
550 case BOPAlgo_IncompatibilityOfVertex: {
554 MakeShapeForFullOutput(aS1BVBaseName, S1_BadV, aLS1, S1_BadVAll, di);
560 MakeShapeForFullOutput(aS2BVBaseName, S2_BadV, aLS2, S2_BadVAll, di);
565 case BOPAlgo_IncompatibilityOfEdge: {
569 MakeShapeForFullOutput(aS1BEBaseName, S1_BadE, aLS1, S1_BadEAll, di);
575 MakeShapeForFullOutput(aS2BEBaseName, S2_BadE, aLS2, S2_BadEAll, di);
580 case BOPAlgo_IncompatibilityOfFace: {
581 // not yet implemented
584 case BOPAlgo_OperationAborted: {
585 if(!aSS1.IsNull()) S1_OpAb++;
586 if(!aSS2.IsNull()) S2_OpAb++;
589 case BOPAlgo_CheckUnknown:
591 hasUnknown = Standard_True;
597 Standard_Integer FS1 = S1_SelfInt + S1_SmalE + S1_BadF + S1_BadV + S1_BadE + S1_OpAb;
598 FS1 += (S1_BadType != 0) ? 1 : 0;
599 Standard_Integer FS2 = S2_SelfInt + S2_SmalE + S2_BadF + S2_BadV + S2_BadE + S2_OpAb;
600 FS2 += (S2_BadType != 0) ? 1 : 0;
602 // output for first shape
603 di << "Faulties for FIRST shape found : " << FS1 << "\n";
605 di << "---------------------------------" << "\n";
606 Standard_CString CString1;
611 di << "Shapes are not suppotrted by BOP: " << CString1 << "\n";
612 Standard_CString CString2;
617 di << "Self-Intersections : " << CString2;
619 di << " Cases(" << S1_SelfInt << ") Total shapes(" << S1_SelfIntAll << ")" << "\n";
622 Standard_CString CString13;
627 di << "Check for SI has been aborted : " << CString13 << "\n";
628 Standard_CString CString3;
633 di << "Too small edges : " << CString3;
635 di << " Cases(" << S1_SmalE << ") Total shapes(" << S1_SmalEAll << ")" << "\n";
638 Standard_CString CString4;
643 di << "Bad faces : " << CString4;
645 di << " Cases(" << S1_BadF << ") Total shapes(" << S1_BadFAll << ")" << "\n";
648 Standard_CString CString5;
653 di << "Too close vertices : " << CString5;
655 di << " Cases(" << S1_BadV << ") Total shapes(" << S1_BadVAll << ")" << "\n";
658 Standard_CString CString6;
663 di << "Too close edges : " << CString6;
665 di << " Cases(" << S1_BadE << ") Total shapes(" << S1_BadEAll << ")" << "\n";
670 // output for second shape
672 di << "Faulties for SECOND shape found : " << FS2 << "\n";
674 di << "---------------------------------" << "\n";
675 Standard_CString CString7;
680 di << "Shapes are not suppotrted by BOP: " << CString7 << "\n";
681 Standard_CString CString8;
686 di << "Self-Intersections : " << CString8;
688 di << " Cases(" << S2_SelfInt << ") Total shapes(" << S2_SelfIntAll << ")" << "\n";
692 Standard_CString CString14;
697 di << "Check for SI has been aborted : " << CString14 << "\n";
698 Standard_CString CString9;
703 di << "Too small edges : " << CString9;
705 di << " Cases(" << S2_SmalE << ") Total shapes(" << S2_SmalEAll << ")" << "\n";
708 Standard_CString CString10;
713 di << "Bad faces : " << CString10;
715 di << " Cases(" << S2_BadF << ") Total shapes(" << S2_BadFAll << ")" << "\n";
718 Standard_CString CString11;
723 di << "Too close vertices : " << CString11;
725 di << " Cases(" << S2_BadV << ") Total shapes(" << S2_BadVAll << ")" << "\n";
728 Standard_CString CString12;
733 di << "Too close edges : " << CString12;
735 di << " Cases(" << S2_BadE << ") Total shapes(" << S2_BadEAll << ")" << "\n";
742 di << "WARNING: The unexpected test break occurs!" << "\n";