0029237: Improve performance of Boolean Operations
[occt.git] / src / BRepAlgoAPI / BRepAlgoAPI_BooleanOperation.cxx
1 // Created on: 1993-10-15
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <BOPAlgo_BOP.hxx>
19 #include <BOPAlgo_PaveFiller.hxx>
20 #include <BOPAlgo_Section.hxx>
21 #include <BOPAlgo_Alerts.hxx>
22 #include <BOPDS_Curve.hxx>
23 #include <BOPDS_DS.hxx>
24 #include <BOPDS_Interf.hxx>
25 #include <BOPDS_ListOfPaveBlock.hxx>
26 #include <BOPDS_PDS.hxx>
27 #include <BOPDS_VectorOfCurve.hxx>
28 #include <BRepAlgoAPI_BooleanOperation.hxx>
29 #include <BRepAlgoAPI_Check.hxx>
30 #include <BRepLib_FuseEdges.hxx>
31 #include <BRepTools.hxx>
32 #include <OSD_Environment.hxx>
33 #include <OSD_File.hxx>
34 #include <TCollection_AsciiString.hxx>
35 #include <TopExp.hxx>
36 #include <TopoDS_Shape.hxx>
37 #include <TopTools_DataMapOfIntegerListOfShape.hxx>
38 #include <TopTools_DataMapOfIntegerShape.hxx>
39 #include <TopTools_IndexedMapOfShape.hxx>
40 #include <TopTools_ListIteratorOfListOfShape.hxx>
41 #include <TopTools_ListOfShape.hxx>
42 #include <TopTools_MapOfShape.hxx>
43
44 #include <stdio.h>
45 ///XXXXXXXXXX
46 //XXXXXXXXXX
47 //XXXX
48 //=======================================================================
49 //class : BRepAlgoAPI_DumpOper
50 //purpose  : 
51 //=======================================================================
52 class BRepAlgoAPI_DumpOper {
53  public:
54   BRepAlgoAPI_DumpOper() :
55     myIsDump(Standard_False),
56     myIsDumpArgs(Standard_False),
57     myIsDumpRes(Standard_False)  {
58       OSD_Environment env("CSF_DEBUG_BOP");
59       TCollection_AsciiString pathdump = env.Value();
60       myIsDump = (!pathdump.IsEmpty() ? Standard_True: Standard_False);
61       myPath=pathdump.ToCString();
62   };
63   //
64   virtual ~BRepAlgoAPI_DumpOper() {
65   };
66   //
67   Standard_Boolean IsDump()const {
68     return myIsDump;
69   };
70   //
71   void SetIsDumpArgs(const Standard_Boolean bFlag) {
72     myIsDumpArgs=bFlag;
73   }
74   //
75   Standard_Boolean IsDumpArgs()const {
76     return myIsDumpArgs;
77   };
78   //
79   void SetIsDumpRes(const Standard_Boolean bFlag) {
80     myIsDumpRes=bFlag;
81   };
82   //
83   Standard_Boolean IsDumpRes()const {
84     return myIsDumpRes;
85   };
86   //
87   void Dump(
88             const TopoDS_Shape& theShape1,
89             const TopoDS_Shape& theShape2,
90             const TopoDS_Shape& theResult,
91             BOPAlgo_Operation theOperation);
92   //
93  protected:
94   Standard_Boolean myIsDump;
95   Standard_Boolean myIsDumpArgs;
96   Standard_Boolean myIsDumpRes;
97   Standard_CString myPath;
98 };
99 //XXXX
100 //=======================================================================
101 //function : BRepAlgoAPI_BooleanOperation
102 //purpose  : 
103 //=======================================================================
104 BRepAlgoAPI_BooleanOperation::BRepAlgoAPI_BooleanOperation()
105 :
106   BRepAlgoAPI_BuilderAlgo(),  
107   myOperation(BOPAlgo_UNKNOWN),
108   myBuilderCanWork(Standard_False),
109   myFuseEdges(Standard_False)
110
111   myEntryType=1;
112 }
113 //=======================================================================
114 //function : BRepAlgoAPI_BooleanOperation
115 //purpose  : 
116 //=======================================================================
117 BRepAlgoAPI_BooleanOperation::BRepAlgoAPI_BooleanOperation
118   (const BOPAlgo_PaveFiller& aPF)
119 :
120   BRepAlgoAPI_BuilderAlgo(aPF),  
121   myOperation(BOPAlgo_UNKNOWN),
122   myBuilderCanWork(Standard_False),
123   myFuseEdges(Standard_False)
124
125   myEntryType=0;
126 }
127 //=======================================================================
128 //function : BRepAlgoAPI_BooleanOperation
129 //purpose  : 
130 //=======================================================================
131 BRepAlgoAPI_BooleanOperation::BRepAlgoAPI_BooleanOperation
132   (const TopoDS_Shape& aS1, 
133    const TopoDS_Shape& aS2,
134    const BOPAlgo_Operation anOp)
135
136   BRepAlgoAPI_BuilderAlgo(),
137   myOperation(anOp),
138   myBuilderCanWork(Standard_False),
139   myFuseEdges(Standard_False)
140 {
141   myEntryType=1;
142   //
143   myArguments.Append(aS1);
144   myTools.Append(aS2);
145 }
146 //=======================================================================
147 //function : BRepAlgoAPI_BooleanOperation
148 //purpose  : 
149 //=======================================================================
150 BRepAlgoAPI_BooleanOperation::BRepAlgoAPI_BooleanOperation
151   (const TopoDS_Shape& aS1, 
152    const TopoDS_Shape& aS2,
153    const BOPAlgo_PaveFiller& aPF,
154    const BOPAlgo_Operation anOp)
155
156   BRepAlgoAPI_BuilderAlgo(aPF),
157   myOperation(anOp),
158   myBuilderCanWork(Standard_False),
159   myFuseEdges(Standard_False)
160
161   myEntryType=0;
162   //
163   myArguments.Append(aS1);
164   myTools.Append(aS2);
165   //
166   myDSFiller=(BOPAlgo_PaveFiller*)&aPF;
167 }
168 //=======================================================================
169 //function : ~
170 //purpose  : 
171 //=======================================================================
172 BRepAlgoAPI_BooleanOperation::~BRepAlgoAPI_BooleanOperation()
173 {
174   Clear();
175 }
176 //=======================================================================
177 //function : Clear
178 //purpose  : 
179 //=======================================================================
180 void BRepAlgoAPI_BooleanOperation::Clear()
181 {
182   BRepAlgoAPI_BuilderAlgo::Clear();
183   //
184   myModifFaces.Clear();
185   myEdgeMap.Clear();
186 }
187 //=======================================================================
188 //function : SetTools
189 //purpose  : 
190 //=======================================================================
191 void BRepAlgoAPI_BooleanOperation::SetTools
192   (const TopTools_ListOfShape& theLS)
193 {
194   myTools=theLS;
195 }
196 //=======================================================================
197 //function : Tools
198 //purpose  : 
199 //=======================================================================
200 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::Tools()const
201 {
202   return myTools;
203 }
204 //=======================================================================
205 //function : SetOperation
206 //purpose  : 
207 //=======================================================================
208 void BRepAlgoAPI_BooleanOperation::SetOperation 
209   (const BOPAlgo_Operation anOp)
210 {
211   myOperation=anOp;
212 }
213 //=======================================================================
214 //function : Operation
215 //purpose  : 
216 //=======================================================================
217 BOPAlgo_Operation BRepAlgoAPI_BooleanOperation::Operation()const
218 {
219   return myOperation;
220 }
221 //=======================================================================
222 //function : Shape1
223 //purpose  : 
224 //=======================================================================
225 const TopoDS_Shape& BRepAlgoAPI_BooleanOperation::Shape1() const 
226 {
227   return myArguments.First();
228 }
229 //=======================================================================
230 //function : Shape2
231 //purpose  : 
232 //=======================================================================
233 const TopoDS_Shape& BRepAlgoAPI_BooleanOperation::Shape2() const 
234 {
235   return myTools.First();
236 }
237 //=======================================================================
238 //function : BuilderCanWork
239 //purpose  : 
240 //=======================================================================
241 Standard_Boolean BRepAlgoAPI_BooleanOperation::BuilderCanWork() const
242 {
243   return myBuilderCanWork;
244 }
245 //=======================================================================
246 //function : FuseEdges
247 //purpose  : 
248 //=======================================================================
249 Standard_Boolean BRepAlgoAPI_BooleanOperation::FuseEdges ()const
250 {
251   return myFuseEdges;
252 }
253 //=======================================================================
254 //function : SetAttributes
255 //purpose  : 
256 //=======================================================================
257 void BRepAlgoAPI_BooleanOperation::SetAttributes()
258 {
259 }
260 //=======================================================================
261 //function : Build2
262 //purpose  : 
263 //=======================================================================
264 void BRepAlgoAPI_BooleanOperation::Build()
265 {
266   GetReport()->Clear();
267
268   Standard_Integer aNbArgs, aNbTools;
269   BRepAlgoAPI_DumpOper aDumpOper;
270   //
271   myBuilderCanWork=Standard_False;
272   NotDone();
273   //
274   aNbArgs=myArguments.Extent();
275   aNbTools=myTools.Extent();
276   if (aNbArgs<1 && aNbTools<1) {
277     AddError (new BOPAlgo_AlertTooFewArguments);
278     return;
279   }
280   if (myOperation==BOPAlgo_UNKNOWN) {
281     AddError (new BOPAlgo_AlertBOPNotSet);
282     return;
283   }
284   //
285   //-----------------------------------------------
286   TopTools_ListOfShape aLS;
287   TopTools_ListIteratorOfListOfShape aIt;
288   //
289   aIt.Initialize(myArguments);
290   for (; aIt.More(); aIt.Next()) {
291     const TopoDS_Shape& aS = aIt.Value();
292     aLS.Append(aS);
293   }
294   aIt.Initialize(myTools);
295   for (; aIt.More(); aIt.Next()) {
296     const TopoDS_Shape& aS = aIt.Value();
297     aLS.Append(aS);
298   }
299   //-----------------------------------------------
300   //
301   if (myEntryType) {
302     if (myDSFiller) {
303       delete myDSFiller;
304     }
305     myDSFiller=new BOPAlgo_PaveFiller(myAllocator);
306     //
307     myDSFiller->SetArguments(aLS);
308     //
309     myDSFiller->SetRunParallel(myRunParallel);
310     myDSFiller->SetProgressIndicator(myProgressIndicator);
311     myDSFiller->SetFuzzyValue(myFuzzyValue);
312     myDSFiller->SetNonDestructive(myNonDestructive);
313     myDSFiller->SetGlue(myGlue);
314     //
315     SetAttributes();
316     //
317     myDSFiller->Perform(); 
318     //
319     GetReport()->Merge (myDSFiller->GetReport());
320     if (HasErrors())
321     {
322       return;
323     }
324   }// if (myEntryType) {
325   //
326   //XXXX
327   const TopoDS_Shape& aS1 = myArguments.First();
328   const TopoDS_Shape& aS2 = myTools.First();
329   if (aDumpOper.IsDump()) {
330     BRepAlgoAPI_Check aChekArgs(aS1, aS2, myOperation);
331     aDumpOper.SetIsDumpArgs(!aChekArgs.IsValid());
332   }
333   //XXXX
334   // 
335   if (myBuilder) {
336     delete myBuilder;
337     myBuilder = NULL;
338   }
339   //
340   BOPAlgo_BOP *pBOP;
341   //
342   if(myOperation==BOPAlgo_SECTION) {
343     myBuilder=new BOPAlgo_Section(myAllocator);
344     myBuilder->SetArguments(aLS);
345   }
346   else{
347     pBOP=new BOPAlgo_BOP(myAllocator); 
348     pBOP->SetArguments(myArguments);
349     pBOP->SetTools(myTools); 
350     pBOP->SetOperation(myOperation);
351     myBuilder=pBOP;
352   }
353   //
354   myBuilder->SetRunParallel(myRunParallel);
355   myBuilder->SetProgressIndicator(myProgressIndicator);
356   myBuilder->SetCheckInverted(myCheckInverted);
357   //
358   myBuilder->PerformWithFiller(*myDSFiller);
359   //
360   GetReport()->Merge (myBuilder->GetReport());
361   if (HasErrors())
362   {
363     return;
364   }
365   //
366   myShape=myBuilder->Shape();
367   //
368   myBuilderCanWork=Standard_True;
369   Done(); 
370   //
371   //XXXX
372   if (aDumpOper.IsDump()) {
373     BRepAlgoAPI_Check aCheckRes(myShape);
374     aDumpOper.SetIsDumpRes(!aCheckRes.IsValid());
375     aDumpOper.Dump(aS1, aS2, myShape,myOperation);
376   }
377   //XXXX
378 }
379 //=======================================================================
380 //function : RefineEdges
381 //purpose  : 
382 //=======================================================================
383 void BRepAlgoAPI_BooleanOperation::RefineEdges ()
384 {
385   if(myFuseEdges) { 
386     return; //Edges have been refined
387   }
388   //
389   TopTools_IndexedMapOfShape mapOldEdges;
390   TopTools_ListOfShape aLS;
391   TopTools_ListIteratorOfListOfShape aIt;
392   //
393   aIt.Initialize(myArguments);
394   for (; aIt.More(); aIt.Next()) {
395     const TopoDS_Shape& aS = aIt.Value();
396     aLS.Append(aS);
397   }
398   aIt.Initialize(myTools);
399   for (; aIt.More(); aIt.Next()) {
400     const TopoDS_Shape& aS = aIt.Value();
401     aLS.Append(aS);
402   }
403   //
404   aIt.Initialize(aLS);
405   for (; aIt.More(); aIt.Next()) {
406     const TopoDS_Shape& aS = aIt.Value();
407     TopExp::MapShapes (aS, TopAbs_EDGE, mapOldEdges);
408   }
409   //----------------------------------------------
410   BRepLib_FuseEdges FE(myShape);
411   FE.SetConcatBSpl(Standard_True);
412   FE.AvoidEdges (mapOldEdges);
413   //
414   // Get List of edges that have been fused
415   myFuseEdges = Standard_False;
416   myModifFaces.Clear();
417   myEdgeMap.Clear();
418   TopTools_DataMapOfIntegerListOfShape aFusedEdges;
419
420   FE.Edges(aFusedEdges);
421   Standard_Integer nle = aFusedEdges.Extent();
422   if (nle != 0) {
423     FE.Perform();
424     myShape = FE.Shape();
425
426     TopTools_DataMapOfIntegerShape aResultEdges;
427
428     FE.ResultEdges(aResultEdges);
429     FE.Faces(myModifFaces);
430     myFuseEdges = Standard_True;
431     
432     Standard_Integer i;
433     for(i = 1; i <= nle; ++i) {
434       const TopoDS_Shape& aNewE = aResultEdges(i);
435       const TopTools_ListOfShape& aListOfOldEdges = aFusedEdges(i);
436       TopTools_ListIteratorOfListOfShape anIter(aListOfOldEdges);
437       for(; anIter.More(); anIter.Next()) {
438         myEdgeMap.Bind(anIter.Value(), aNewE);
439       }
440     }
441   }
442 }
443 //=======================================================================
444 //function : RefinedList
445 //purpose  : 
446 //=======================================================================
447 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::RefinedList
448   (const TopTools_ListOfShape& theL) 
449 {
450   myGenerated.Clear();
451   TopTools_MapOfShape aMap;
452
453   TopTools_ListIteratorOfListOfShape anIter(theL);
454
455   for(; anIter.More(); anIter.Next()) {
456     const TopoDS_Shape& anS = anIter.Value();
457
458     if(anS.ShapeType() == TopAbs_EDGE) {
459       if(myEdgeMap.IsBound(anS)) {
460         const TopoDS_Shape& aNewEdge = myEdgeMap.Find(anS);
461         if(aMap.Add(aNewEdge)) {
462           myGenerated.Append(aNewEdge);
463         }
464       }
465       else {
466         myGenerated.Append(anS);
467       }
468     }
469     else if (anS.ShapeType() == TopAbs_FACE) {
470       if(myModifFaces.IsBound(anS)) {
471         myGenerated.Append(myModifFaces.Find(anS));
472       }
473       else {
474         myGenerated.Append(anS);
475       }
476     }
477     else {
478       myGenerated.Append(anS);
479     }
480   }
481
482   return myGenerated;
483
484 }
485 //=======================================================================
486 //function : SectionEdges
487 //purpose  : 
488 //=======================================================================
489 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::SectionEdges()
490 {
491   if (myBuilder==NULL) {
492     myGenerated.Clear();
493     return myGenerated;
494   }
495   //
496   Standard_Integer aNb, i, j, aNbCurves, nE;
497   BOPDS_ListIteratorOfListOfPaveBlock anIt;
498   //
499   const BOPDS_PDS& pDS = myDSFiller->PDS();
500   BOPDS_VectorOfInterfFF& aFFs=pDS->InterfFF();
501   myGenerated.Clear();
502   //
503   aNb=aFFs.Extent();
504   for (i = 0; i < aNb; i++) {
505     BOPDS_InterfFF& aFFi=aFFs(i);
506     const BOPDS_VectorOfCurve& aSeqOfCurve=aFFi.Curves();
507     //
508     aNbCurves=aSeqOfCurve.Extent();
509     for (j=0; j<aNbCurves; j++) {
510       const BOPDS_Curve& aCurve=aSeqOfCurve(j);
511       const BOPDS_ListOfPaveBlock& aSectEdges = aCurve.PaveBlocks();
512       //
513       anIt.Initialize(aSectEdges);
514       for(; anIt.More(); anIt.Next()) {
515         const Handle(BOPDS_PaveBlock)& aPB = anIt.Value();
516         nE = aPB->Edge();
517         const TopoDS_Shape& aE = pDS->Shape(nE);
518         myGenerated.Append(aE);
519       }
520     }
521   }
522   //
523   if(myFuseEdges) {
524     TopTools_ListOfShape theLS;
525     theLS.Assign(myGenerated);
526     //
527     RefinedList(theLS);
528   }
529   //
530   return myGenerated;
531 }
532 //=======================================================================
533 //function : Generated
534 //purpose  : 
535 //=======================================================================
536 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::Generated
537   (const TopoDS_Shape& S) 
538 {
539   if (myBuilder==NULL) {
540     myGenerated.Clear();
541     return myGenerated;
542   }
543   //
544   if(myFuseEdges) {
545     const TopTools_ListOfShape& aL = myBuilder->Generated(S);
546     return RefinedList(aL);
547   }
548   
549   return myBuilder->Generated(S);
550 }
551
552 //=======================================================================
553 //function : Modified
554 //purpose  : 
555 //=======================================================================
556 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::Modified
557   (const TopoDS_Shape& aS) 
558 {
559   if (myBuilder==NULL) {
560     myGenerated.Clear();
561     return myGenerated;
562   }
563   else {
564     myGenerated = myBuilder->Modified(aS);
565
566     if(myFuseEdges) {
567       TopTools_ListOfShape theLS;
568       theLS.Assign(myGenerated);
569       //
570       RefinedList(theLS);
571     }
572     return myGenerated;
573   }
574 }
575 //=======================================================================
576 //function : IsDeleted
577 //purpose  : 
578 //=======================================================================
579 Standard_Boolean BRepAlgoAPI_BooleanOperation::IsDeleted
580   (const TopoDS_Shape& aS) 
581 {
582   Standard_Boolean bDeleted = Standard_True; 
583   if (myBuilder != NULL) {
584     bDeleted=myBuilder->IsDeleted(aS);
585   }
586   return bDeleted; 
587 }
588 //=======================================================================
589 //function : HasModified
590 //purpose  : 
591 //=======================================================================
592 Standard_Boolean BRepAlgoAPI_BooleanOperation::HasModified() const
593 {
594   if (myBuilder==NULL) {
595     return Standard_False;
596   }
597   return myBuilder->HasModified();
598 }
599 //=======================================================================
600 //function : HasGenerated
601 //purpose  : 
602 //=======================================================================
603 Standard_Boolean BRepAlgoAPI_BooleanOperation::HasGenerated() const
604 {
605   if (myBuilder==NULL) {
606     return Standard_False;
607   }
608   return myBuilder->HasGenerated();
609 }
610 //=======================================================================
611 //function : HasDeleted
612 //purpose  : 
613 //=======================================================================
614 Standard_Boolean BRepAlgoAPI_BooleanOperation::HasDeleted() const
615 {
616   if (myBuilder==NULL) {
617     return Standard_False;
618   }
619   return myBuilder->HasDeleted();
620 }
621 //XXXX
622 //=======================================================================
623 //function : Dump
624 //purpose  : 
625 //=======================================================================
626 void BRepAlgoAPI_DumpOper::Dump (const TopoDS_Shape& theShape1,
627                                  const TopoDS_Shape& theShape2,
628                                  const TopoDS_Shape& theResult,
629                                  BOPAlgo_Operation theOperation)
630 {
631   if (!(myIsDumpArgs && myIsDumpRes)) {
632     return;
633   }
634   //
635   TCollection_AsciiString aPath(myPath);
636   aPath += "/";
637   Standard_Integer aNumOper = 1;
638   Standard_Boolean isExist = Standard_True;
639   TCollection_AsciiString aFileName;
640  
641   while(isExist)
642   {
643     aFileName = aPath + "BO_" + TCollection_AsciiString(aNumOper) +".tcl";
644     OSD_File aScript(aFileName);
645     isExist = aScript.Exists();
646     if(isExist)
647       aNumOper++;
648   }
649
650   FILE* afile = fopen(aFileName.ToCString(), "w+");
651   if(!afile)
652     return;
653   if(myIsDumpArgs)
654     fprintf(afile,"%s\n","# Arguments are invalid");
655
656   TCollection_AsciiString aName1;
657   TCollection_AsciiString aName2;
658   TCollection_AsciiString aNameRes;
659   if(!theShape1.IsNull())
660   {
661     aName1 = aPath +
662       "Arg1_" + TCollection_AsciiString(aNumOper) + ".brep";
663     BRepTools::Write(theShape1, aName1.ToCString());
664   }
665   else
666     fprintf(afile,"%s\n","# First argument is Null ");
667    
668   if(!theShape2.IsNull())
669   {
670     aName2 =  aPath +
671       "Arg2_"+ TCollection_AsciiString(aNumOper) + ".brep";
672
673     BRepTools::Write(theShape2, aName2.ToCString());
674   }
675   else
676     fprintf(afile,"%s\n","# Second argument is Null ");
677    
678    if(!theResult.IsNull())
679   {
680     aNameRes =  aPath +
681       "Result_"+ TCollection_AsciiString(aNumOper) + ".brep";
682
683     BRepTools::Write(theResult, aNameRes.ToCString());
684   }
685   else
686     fprintf(afile,"%s\n","# Result is Null ");
687   
688   fprintf(afile, "%s %s %s\n","restore",  aName1.ToCString(), "arg1");
689   fprintf(afile, "%s %s %s\n","restore",  aName2.ToCString(), "arg2");;
690   TCollection_AsciiString aBopString;
691   switch (theOperation)
692   {
693     case BOPAlgo_COMMON : aBopString += "bcommon Res "; break;
694     case BOPAlgo_FUSE   : aBopString += "bfuse Res "; break;
695     case BOPAlgo_CUT    : 
696     case BOPAlgo_CUT21  : aBopString += "bcut Res "; break;
697     case BOPAlgo_SECTION : aBopString += "bsection Res "; break;
698     default : break;
699   };
700   aBopString += ("arg1 arg2");
701   if(theOperation == BOPAlgo_CUT21)
702     aBopString += " 1";
703
704   fprintf(afile, "%s\n",aBopString.ToCString());
705   fclose(afile);
706 }