0023648: Add tool for checking shapes on validity for boolean operations.
[occt.git] / src / BOPTest / BOPTest_BOPCommands.cxx
1 // Created on: 2000-03-16
2 // Created by: Peter KURNEV
3 // Copyright (c) 2000-2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20
21 #include <BOPTest.ixx>
22
23 #include <stdio.h>
24
25 #include <DBRep.hxx>
26
27 #include <NCollection_BaseAllocator.hxx>
28 #include <NCollection_IncAllocator.hxx>
29
30 #include <TopoDS_Shape.hxx>
31 #include <TopoDS_Compound.hxx>
32 #include <BRep_Builder.hxx>
33
34 #include <BOPAlgo_PaveFiller.hxx>
35 #include <BOPAlgo_Operation.hxx>
36 #include <BOPAlgo_BOP.hxx>
37 #include <BOPDS_DS.hxx>
38 #include <BOPTest_DrawableShape.hxx>
39 #include <BOPCol_ListOfShape.hxx>
40
41 #include <TCollection_AsciiString.hxx>
42 #include <IntTools_FaceFace.hxx>
43 #include <IntTools_Curve.hxx>
44 #include <DrawTrSurf.hxx>
45 #include <Draw_Color.hxx>
46 #include <Draw.hxx>
47 #include <BRepAlgoAPI_BooleanOperation.hxx>
48 #include <BRepAlgoAPI_Common.hxx>
49 #include <BRepAlgoAPI_Fuse.hxx>
50 #include <BRepAlgoAPI_Cut.hxx>
51 #include <BRepAlgoAPI_Section.hxx>
52
53 //
54 static BOPAlgo_PaveFiller* pPF=NULL;
55 //
56
57 static
58   Standard_Integer bopsmt(Draw_Interpretor& di,
59                           Standard_Integer n,
60                           const char** a,
61                           const BOPAlgo_Operation aOp);
62 static
63   Standard_Integer bsmt (Draw_Interpretor& di, 
64                        Standard_Integer n, 
65                        const char** a,
66                        const BOPAlgo_Operation aOp);
67 //
68 static Standard_Integer bop       (Draw_Interpretor&, Standard_Integer, const char**);
69 static Standard_Integer bopsection(Draw_Interpretor&, Standard_Integer, const char**);
70 static Standard_Integer boptuc    (Draw_Interpretor&, Standard_Integer, const char**);
71 static Standard_Integer bopcut    (Draw_Interpretor&, Standard_Integer, const char**);
72 static Standard_Integer bopfuse   (Draw_Interpretor&, Standard_Integer, const char**);
73 static Standard_Integer bopcommon (Draw_Interpretor&, Standard_Integer, const char**);
74 //
75 static Standard_Integer bsection  (Draw_Interpretor&, Standard_Integer, const char**);
76 static Standard_Integer btuc      (Draw_Interpretor&, Standard_Integer, const char**);
77 static Standard_Integer bcut      (Draw_Interpretor&, Standard_Integer, const char**);
78 static Standard_Integer bfuse     (Draw_Interpretor&, Standard_Integer, const char**);
79 static Standard_Integer bcommon   (Draw_Interpretor&, Standard_Integer, const char**);
80 //
81 static Standard_Integer bopcurves (Draw_Interpretor&, Standard_Integer, const char**);
82 static Standard_Integer bopnews   (Draw_Interpretor&, Standard_Integer, const char**);
83
84 //=======================================================================
85 //function : BOPCommands
86 //purpose  : 
87 //=======================================================================
88   void BOPTest::BOPCommands(Draw_Interpretor& theCommands)
89 {
90   static Standard_Boolean done = Standard_False;
91   if (done) return;
92   done = Standard_True;
93   // Chapter's name
94   const char* g = "BOP commands";
95   // Commands
96   
97   theCommands.Add("bop"       , "use bop s1 s2"   , __FILE__, bop, g);
98   theCommands.Add("bopcommon" , "use bopcommon r" , __FILE__, bopcommon, g);
99   theCommands.Add("bopfuse"   , "use bopfuse r"   , __FILE__,bopfuse, g);
100   theCommands.Add("bopcut"    , "use bopcut"      , __FILE__,bopcut, g);
101   theCommands.Add("boptuc"    , "use boptuc"      , __FILE__,boptuc, g);
102   theCommands.Add("bopsection", "use bopsection"  , __FILE__,bopsection, g);
103   //
104   theCommands.Add("bcommon" , "use bcommon r s1 s2" , __FILE__,bcommon, g);
105   theCommands.Add("bfuse"   , "use bfuse r s1 s2"   , __FILE__,bfuse, g);
106   theCommands.Add("bcut"    , "use bcut r s1 s2"    , __FILE__,bcut, g);
107   theCommands.Add("btuc"    , "use btuc r s1 s2"    , __FILE__,btuc, g);
108   theCommands.Add("bsection", "Use >bsection r s1 s2 [-n2d/-n2d1/-n2d2] [-na]", 
109                                                       __FILE__, bsection, g);
110   //
111   theCommands.Add("bopcurves", "use  bopcurves F1 F2", __FILE__, bopcurves, g);
112   theCommands.Add("bopnews", "use  bopnews -v[e,f]"  , __FILE__, bopnews, g);
113 }
114
115 //=======================================================================
116 //function : bop
117 //purpose  : 
118 //=======================================================================
119 Standard_Integer bop (Draw_Interpretor& di, Standard_Integer n, const char** a)
120 {
121   char buf[32];
122   Standard_Integer iErr;
123   TopoDS_Shape aS1, aS2;
124   BOPCol_ListOfShape aLC;
125   //
126   if (n!=3) {
127     di << " use bop Shape1 Shape2\n";
128     return 1;
129   }
130   //
131   aS1=DBRep::Get(a[1]);
132   aS2=DBRep::Get(a[2]);
133   //
134   if (aS1.IsNull() || aS2.IsNull()) {
135     di << " null shapes are not allowed \n";
136     return 1;
137   }
138   //
139   aLC.Append(aS1);
140   aLC.Append(aS2);
141   //
142   if (!pPF) {
143     delete pPF;
144     Handle(NCollection_BaseAllocator)aAL=new NCollection_IncAllocator;
145     pPF=new BOPAlgo_PaveFiller(aAL);
146   }
147   //
148   pPF->SetArguments(aLC);
149   //
150   pPF->Perform();
151   iErr=pPF->ErrorStatus();
152   if (iErr) {
153     Sprintf(buf, " ErrorStatus : %d\n",  iErr);
154     di << buf;
155     return 0;
156   }
157   //
158   return 0;
159 }
160 //=======================================================================
161 //function : bopcommon
162 //purpose  : 
163 //=======================================================================
164 Standard_Integer bopcommon (Draw_Interpretor& di, Standard_Integer n, const char** a)
165 {
166   return bopsmt(di, n, a, BOPAlgo_COMMON);
167 }
168 //=======================================================================
169 //function : bopfuse
170 //purpose  : 
171 //=======================================================================
172 Standard_Integer bopfuse(Draw_Interpretor& di, Standard_Integer n, const char** a)
173 {
174   return bopsmt(di, n, a, BOPAlgo_FUSE);
175 }
176 //=======================================================================
177 //function : bopcut
178 //purpose  : 
179 //=======================================================================
180 Standard_Integer bopcut(Draw_Interpretor& di, Standard_Integer n, const char** a)
181 {
182   return bopsmt(di, n, a, BOPAlgo_CUT);
183 }
184 //=======================================================================
185 //function : boptuc
186 //purpose  : 
187 //=======================================================================
188 Standard_Integer boptuc(Draw_Interpretor& di, Standard_Integer n, const char** a)
189 {
190   return bopsmt(di, n, a, BOPAlgo_CUT21);
191 }
192 //=======================================================================
193 //function : bopsection
194 //purpose  : 
195 //=======================================================================
196 Standard_Integer bopsection(Draw_Interpretor& di, Standard_Integer n, const char** a)
197 {
198   return bopsmt(di, n, a, BOPAlgo_SECTION);
199 }
200 //=======================================================================
201 //function : bopsmt
202 //purpose  : 
203 //=======================================================================
204 Standard_Integer bopsmt(Draw_Interpretor& di,
205                         Standard_Integer n,
206                         const char** a,
207                         const BOPAlgo_Operation aOp)
208 {
209   if (n<2) {
210     di << " use bopsmt r\n";
211     return 0;
212   }
213   //
214   if (!pPF) {
215     di << " prepare PaveFiller first\n";
216     return 0;
217   }
218   //
219   if (pPF->ErrorStatus()) {
220     di << " PaveFiller has not been done\n";
221     return 0;
222   }
223   //
224   char buf[64];
225   Standard_Integer aNb, iErr;
226   BOPAlgo_BOP aBOP;
227   //
228   const BOPCol_ListOfShape& aLC=pPF->Arguments();
229   aNb=aLC.Extent();
230   if (aNb!=2) {
231     Sprintf (buf, " wrong number of arguments %s\n", aNb);
232     di << buf;
233     return 0;
234   }
235   //
236   const TopoDS_Shape& aS1=aLC.First();
237   const TopoDS_Shape& aS2=aLC.Last();
238   //
239   aBOP.AddArgument(aS1);
240   aBOP.AddTool(aS2);
241   aBOP.SetOperation(aOp);
242   //
243   aBOP.PerformWithFiller(*pPF);
244   iErr=aBOP.ErrorStatus();
245   if (iErr) {
246     Sprintf(buf, " ErrorStatus : %d\n",  iErr);
247     di << buf;
248     return 0;
249   }
250   //
251   const TopoDS_Shape& aR=aBOP.Shape();
252   if (aR.IsNull()) {
253     di << " null shape\n";
254     return 0;
255   }
256   //
257   DBRep::Set(a[1], aR);
258   return 0;
259 }
260 //=======================================================================
261 //function : bcommon
262 //purpose  : 
263 //=======================================================================
264 Standard_Integer bcommon (Draw_Interpretor& di, Standard_Integer n, const char** a)
265 {
266   return bsmt(di, n, a, BOPAlgo_COMMON);
267 }
268 //=======================================================================
269 //function : bfuse
270 //purpose  : 
271 //=======================================================================
272 Standard_Integer bfuse (Draw_Interpretor& di, Standard_Integer n, const char** a)
273 {
274   return bsmt(di, n, a, BOPAlgo_FUSE);
275 }
276 //=======================================================================
277 //function : bcut
278 //purpose  : 
279 //=======================================================================
280 Standard_Integer bcut (Draw_Interpretor& di, Standard_Integer n, const char** a)
281 {
282   return bsmt(di, n, a, BOPAlgo_CUT);
283 }
284 //=======================================================================
285 //function : btuc
286 //purpose  : 
287 //=======================================================================
288 Standard_Integer btuc (Draw_Interpretor& di, Standard_Integer n, const char** a)
289 {
290   return bsmt(di, n, a, BOPAlgo_CUT21);
291 }
292 //=======================================================================
293 //function : bsection
294 //purpose  : 
295 //=======================================================================
296 Standard_Integer  bsection(Draw_Interpretor& di, 
297                            Standard_Integer n, 
298                            const char** a)
299 {
300   const char* usage = " Usage: bsection Result s1 s2 [-n2d/-n2d1/-n2d2] [-na]\n";
301   if (n < 4) {
302     di << usage;
303     return 1;
304   }
305
306   TopoDS_Shape aS1 = DBRep::Get(a[2]);
307   TopoDS_Shape aS2 = DBRep::Get(a[3]);
308   
309   if (aS1.IsNull() || aS2.IsNull()) {
310     di << " Null shapes are not allowed \n";
311     return 1;
312   }
313
314   Standard_Boolean bApp, bPC1, bPC2;
315   //
316   bApp = Standard_True;
317   bPC1 = Standard_True;
318   bPC2 = Standard_True;
319   
320   Standard_Boolean isbadparameter = Standard_False;
321   
322   if(n > 4) {
323     const char* key1 = a[4];
324     const char* key2 = (n > 5) ? a[5] : NULL;
325     const char* pcurveconf = NULL;
326
327 #ifdef WNT
328     if (key1 && (!strcasecmp(key1,"-n2d") || !strcasecmp(key1,"-n2d1") || !strcasecmp(key1,"-n2d2"))) {
329 #else 
330     if (key1 && (!strncasecmp(key1,"-n2d", 4) || !strncasecmp(key1,"-n2d1", 5) || !strncasecmp(key1,"-n2d2", 5))) {
331 #endif
332       pcurveconf = key1;
333     }
334     else {
335 #ifdef WNT
336       if (!strcasecmp(key1,"-na")) {
337 #else 
338       if(!strncasecmp(key1,"-na", 3)) {
339 #endif
340         bApp = Standard_False;
341       }
342       else {
343         isbadparameter = Standard_True;
344       }
345     }
346     if (key2) {
347 #ifdef WNT
348       if(!strcasecmp(key2,"-na")) {
349 #else 
350       if (!strncasecmp(key2,"-na", 3)) {
351 #endif
352         bApp = Standard_False;
353       }
354       else {
355         isbadparameter = Standard_True;
356       }
357     }
358
359     if(!isbadparameter && pcurveconf) {      
360 #ifdef WNT
361       if (!strcasecmp(pcurveconf, "-n2d1")) {
362 #else 
363       if (!strncasecmp(pcurveconf, "-n2d1", 5)) {
364 #endif
365         bPC1 = Standard_False;
366       }
367       else {
368 #ifdef WNT
369         if (!strcasecmp(pcurveconf, "-n2d2")) {
370 #else 
371         if (!strncasecmp(pcurveconf, "-n2d2", 5)) {
372 #endif
373           bPC2 = Standard_False;
374         }
375         else {
376 #ifdef WNT
377           if (!strcasecmp(pcurveconf, "-n2d")) {
378 #else 
379           if (!strncasecmp(pcurveconf, "-n2d", 4)) {
380 #endif
381             bPC1 = Standard_False;
382             bPC2 = Standard_False;
383           }
384         }
385       }
386     }
387   }
388       
389   if(!isbadparameter) {
390     Standard_Integer iErr;
391     char buf[80];
392     //
393     BRepAlgoAPI_Section aSec(aS1, aS2, Standard_False);
394     aSec.Approximation(bApp);
395     aSec.ComputePCurveOn1(bPC1);
396     aSec.ComputePCurveOn2(bPC2);
397     //
398     aSec.Build();
399     iErr=aSec.ErrorStatus();
400     if (!aSec.IsDone()) {
401       Sprintf(buf, " ErrorStatus : %d\n",  iErr);
402       di << buf;
403       return 0;
404     }
405     //
406     const TopoDS_Shape& aR=aSec.Shape();
407     if (aR.IsNull()) {
408       di << " null shape\n";
409       return 0;
410     }
411     DBRep::Set(a[1], aR);
412     return 0;
413   }
414   else {
415     di << usage;
416     return 1;
417   }
418   return 0;
419 }
420 //=======================================================================
421 //function : bsmt
422 //purpose  : 
423 //=======================================================================
424 Standard_Integer bsmt (Draw_Interpretor& di, 
425                        Standard_Integer n, 
426                        const char** a,
427                        const BOPAlgo_Operation aOp)
428 {
429   char buf[32];
430   Standard_Integer iErr;
431   TopoDS_Shape aS1, aS2;
432   BOPCol_ListOfShape aLC;
433   //
434   if (n!=4) {
435     di << " use bx r s1 s2\n";
436     return 1;
437   }
438   //
439   aS1=DBRep::Get(a[2]);
440   aS2=DBRep::Get(a[3]);
441   //
442   if (aS1.IsNull() || aS2.IsNull()) {
443     di << " null shapes are not allowed \n";
444     return 1;
445   }
446   aLC.Append(aS1);
447   aLC.Append(aS2);
448   //
449   Handle(NCollection_BaseAllocator)aAL=new NCollection_IncAllocator;
450   BOPAlgo_PaveFiller aPF(aAL);
451   //
452   aPF.SetArguments(aLC);
453   //
454   aPF.Perform();
455   iErr=aPF.ErrorStatus();
456   if (iErr) {
457     Sprintf(buf, " ErrorStatus : %d\n",  iErr);
458     di << buf;
459     return 0;
460   }
461   //
462   BRepAlgoAPI_BooleanOperation* pBuilder=NULL;
463   // 
464   if (aOp==BOPAlgo_COMMON) {
465     pBuilder=new BRepAlgoAPI_Common(aS1, aS2, aPF);
466   }
467   else if (aOp==BOPAlgo_FUSE) {
468     pBuilder=new BRepAlgoAPI_Fuse(aS1, aS2, aPF);
469   }
470   else if (aOp==BOPAlgo_CUT) {
471     pBuilder=new BRepAlgoAPI_Cut (aS1, aS2, aPF);
472   }
473   else if (aOp==BOPAlgo_CUT21) {
474     pBuilder=new BRepAlgoAPI_Cut(aS1, aS2, aPF, Standard_False);
475   }
476   //
477   iErr = pBuilder->ErrorStatus();
478   if (!pBuilder->IsDone()) {
479     Sprintf(buf, " ErrorStatus : %d\n",  iErr);
480     di << buf;
481     return 0;
482   }
483   const TopoDS_Shape& aR=pBuilder->Shape();
484   if (aR.IsNull()) {
485     di << " null shape\n";
486     return 0;
487   }
488   DBRep::Set(a[1], aR);
489   return 0;
490 }
491
492 //=======================================================================
493 //function : bopnews
494 //purpose  : 
495 //=======================================================================
496 Standard_Integer bopnews (Draw_Interpretor& di, 
497                           Standard_Integer n, 
498                           const char** a)
499 {
500   if (n!=2) {
501     di << " use bopnews -v[e,f]\n";
502     return 0;
503   }
504   //
505   if (pPF==NULL) {
506     di << " Prepare BOPAlgo_PaveFiller first >bop S1 S2\n";
507     return 0;
508   }
509   //
510   char buf[32];
511   Standard_CString aText;
512   Standard_Integer i, i1, i2, iFound;
513   Draw_Color aTextColor(Draw_cyan);
514   TopAbs_ShapeEnum aT;
515   Handle(BOPTest_DrawableShape) aDShape;
516   //
517   const BOPDS_PDS& pDS=pPF->PDS();
518   //
519   aT=TopAbs_SHAPE;
520   if (!strcmp (a[1], "-f")) {
521     aT=TopAbs_FACE;
522   }
523   else if (!strcmp (a[1], "-e")){
524     aT=TopAbs_EDGE;
525   }
526   else if (!strcmp (a[1], "-v")){
527     aT=TopAbs_VERTEX;
528   }
529   else {
530     di << " use bopnews -v[e,f]\n";
531     return 0;
532   }
533   //
534   iFound=0;
535   i1=pDS->NbSourceShapes();
536   i2=pDS->NbShapes();
537   for (i=i1; i<i2; ++i) {
538     const BOPDS_ShapeInfo& aSI=pDS->ShapeInfo(i);
539     if (aSI.ShapeType()==aT) {
540       const TopoDS_Shape& aS=aSI.Shape();
541       //
542       Sprintf (buf, "z%d", i);
543       aText=buf;
544       aDShape=new BOPTest_DrawableShape (aS, aText, aTextColor);
545       Draw::Set (aText, aDShape);
546       //
547       Sprintf (buf, " z%d", i);
548       di << buf;
549       //
550       iFound=1;
551     }
552   }
553   //
554   if (iFound) {
555     di << "\n";
556   }
557   else {
558     di << " not found\n";
559   }
560   //
561   return 0;
562 }
563
564 //=======================================================================
565 //function : bopcurves
566 //purpose  : 
567 //=======================================================================
568 Standard_Integer bopcurves (Draw_Interpretor& di, 
569                             Standard_Integer n, 
570                             const char** a)
571 {
572   if (n<3) {
573     di << " use bopcurves F1 F2\n";
574     return 1;
575   }
576
577   TopoDS_Shape S1 = DBRep::Get(a[1]);
578   TopoDS_Shape S2 = DBRep::Get(a[2]);
579   TopAbs_ShapeEnum aType;
580
581   if (S1.IsNull() || S2.IsNull()) {
582     di << " Null shapes is not allowed \n";
583     return 1;
584   }
585
586   aType=S1.ShapeType();
587   if (aType != TopAbs_FACE) {
588     di << " Type mismatch F1\n";
589     return 1;
590   }
591   aType=S2.ShapeType();
592   if (aType != TopAbs_FACE) {
593     di << " Type mismatch F2\n";
594     return 1;
595   }
596
597
598   const TopoDS_Face& aF1=*(TopoDS_Face*)(&S1);
599   const TopoDS_Face& aF2=*(TopoDS_Face*)(&S2);
600
601   Standard_Boolean aToApproxC3d, aToApproxC2dOnS1, aToApproxC2dOnS2, anIsDone;
602   Standard_Integer i, aNbCurves;
603   Standard_Real anAppTol, aTolR;
604   TCollection_AsciiString aNm("c_");
605
606   aToApproxC3d=Standard_True;
607   aToApproxC2dOnS1=Standard_False;
608   aToApproxC2dOnS2=Standard_False;
609   anAppTol=0.0000001;
610
611
612   IntTools_FaceFace aFF;
613   
614   aFF.SetParameters (aToApproxC3d,
615                      aToApproxC2dOnS1,
616                      aToApproxC2dOnS2,
617                      anAppTol);
618   
619   aFF.Perform (aF1, aF2);
620   
621   anIsDone=aFF.IsDone();
622   if (!anIsDone) {
623     di << " anIsDone=" << (Standard_Integer) anIsDone << "\n";
624     return 1;
625   }
626
627   aFF.PrepareLines3D();
628   const IntTools_SequenceOfCurves& aSCs=aFF.Lines();
629
630   //
631   aTolR=aFF.TolReached3d();
632   di << "Tolerance Reached=" << aTolR << "\n";
633
634   aNbCurves=aSCs.Length();
635   if (!aNbCurves) {
636     di << " has no 3d curve\n";
637     return 1;
638   }
639
640   for (i=1; i<=aNbCurves; i++) {
641     const IntTools_Curve& anIC=aSCs(i);
642
643     Handle (Geom_Curve) aC3D=anIC.Curve();
644
645     if (aC3D.IsNull()) {
646       di << " has Null 3d curve# " << i << "%d\n";
647       continue;
648     }
649
650     TCollection_AsciiString anIndx(i), aNmx;
651     aNmx=aNm+anIndx;
652     Standard_CString name= aNmx.ToCString();
653     DrawTrSurf::Set(name, aC3D);
654     di << name << " ";
655   }
656
657   di << "\n";
658   
659   return 0;
660 }