0023471: Intersection algorithm produces overlapping intersection curves
[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-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21 #include <BRepAlgoAPI_BooleanOperation.ixx>
22
23 #include <BRepLib_FuseEdges.hxx>
24 #include <TopExp.hxx>
25 #include <TopTools_MapOfShape.hxx>
26 #include <TopTools_ListIteratorOfListOfShape.hxx>
27
28 #include <BOPAlgo_PaveFiller.hxx>
29 #include <BOPAlgo_BOP.hxx>
30 #include <BOPDS_DS.hxx>
31
32 //=======================================================================
33 //function : BRepAlgoAPI_BooleanOperation
34 //purpose  : 
35 //=======================================================================
36   BRepAlgoAPI_BooleanOperation::BRepAlgoAPI_BooleanOperation(const TopoDS_Shape& aS1, 
37                                                              const TopoDS_Shape& aS2,
38                                                              const BOPAlgo_Operation anOp)
39
40   myS1(aS1),
41   myS2(aS2),
42   myBuilderCanWork(Standard_False),
43   myOperation(anOp),
44   myErrorStatus(1),
45   myDSFiller(NULL),
46   myBuilder(NULL),
47   myEntryType(1),
48   myFuseEdges(Standard_False)
49 {
50 }
51 //=======================================================================
52 //function : BRepAlgoAPI_BooleanOperation
53 //purpose  : 
54 //=======================================================================
55   BRepAlgoAPI_BooleanOperation::BRepAlgoAPI_BooleanOperation(const TopoDS_Shape& aS1, 
56                                                              const TopoDS_Shape& aS2,
57                                                              const BOPAlgo_PaveFiller& aDSFiller,
58                                                              const BOPAlgo_Operation anOp)
59
60   myS1(aS1),
61   myS2(aS2),
62   myBuilderCanWork(Standard_False),
63   myOperation(anOp),
64   myErrorStatus(1),
65   myDSFiller(NULL),
66   myBuilder(NULL),
67   myEntryType(0),
68   myFuseEdges(Standard_False)
69 {
70   if ((Standard_Address) &aDSFiller!=NULL) {
71     myDSFiller=(BOPAlgo_PaveFiller*)&aDSFiller;
72   }
73 }
74 //=======================================================================
75 //function : Destroy
76 //purpose  : 
77 //=======================================================================
78   void BRepAlgoAPI_BooleanOperation::Destroy()
79 {
80   if (myBuilder!=NULL) {
81     delete myBuilder;
82     myBuilder=NULL;
83   }
84   if (myDSFiller!=NULL && myEntryType) {
85     delete myDSFiller;
86     myDSFiller=NULL;
87   }
88
89   //
90   myModifFaces.Clear();
91   myEdgeMap.Clear();
92 }
93 //=======================================================================
94 //function : SetOperation
95 //purpose  : 
96 //=======================================================================
97   void BRepAlgoAPI_BooleanOperation::SetOperation (const BOPAlgo_Operation anOp)
98 {
99   myOperation=anOp;
100 }
101 //=======================================================================
102 //function : Operation
103 //purpose  : 
104 //=======================================================================
105   BOPAlgo_Operation BRepAlgoAPI_BooleanOperation::Operation ()const
106 {
107   return myOperation;
108 }
109
110 //=======================================================================
111 //function : FuseEdges
112 //purpose  : 
113 //=======================================================================
114   Standard_Boolean BRepAlgoAPI_BooleanOperation::FuseEdges ()const
115 {
116   return myFuseEdges;
117 }
118
119 //=======================================================================
120 //function : Shape1
121 //purpose  : 
122 //=======================================================================
123   const TopoDS_Shape& BRepAlgoAPI_BooleanOperation::Shape1() const 
124 {
125   return myS1;
126 }
127
128 //=======================================================================
129 //function : Shape2
130 //purpose  : 
131 //=======================================================================
132   const TopoDS_Shape& BRepAlgoAPI_BooleanOperation::Shape2() const 
133 {
134   return myS2;
135 }
136
137 //=======================================================================
138 //function : BuilderCanWork
139 //purpose  : 
140 //=======================================================================
141   Standard_Boolean BRepAlgoAPI_BooleanOperation::BuilderCanWork() const
142 {
143   return myBuilderCanWork;
144 }
145 //=======================================================================
146 //function : ErrorStatus
147 //purpose  : 
148 //=======================================================================
149   Standard_Integer BRepAlgoAPI_BooleanOperation::ErrorStatus()const
150 {
151   return myErrorStatus;    
152 }
153 //=======================================================================
154 //function : Modified
155 //purpose  : 
156 //=======================================================================
157 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::Modified(const TopoDS_Shape& aS) 
158 {
159   if (myBuilder==NULL) {
160     myGenerated.Clear();
161     return myGenerated;
162   }
163   else {
164     myGenerated = myBuilder->Modified(aS);
165
166     if(myFuseEdges) {
167       TopTools_ListOfShape theLS;
168       theLS.Assign(myGenerated);
169       //
170       RefinedList(theLS);
171     }
172     return myGenerated;
173   }
174 }
175
176 //=======================================================================
177 //function : IsDeleted
178 //purpose  : 
179 //=======================================================================
180   Standard_Boolean BRepAlgoAPI_BooleanOperation::IsDeleted(const TopoDS_Shape& aS) 
181 {
182   Standard_Boolean bDeleted = Standard_True; 
183   if (myBuilder != NULL) {
184     bDeleted=myBuilder->IsDeleted(aS);
185   }
186   return bDeleted; 
187 }
188
189 //=======================================================================
190 //function : PrepareFiller
191 //purpose  : 
192 //=======================================================================
193   Standard_Boolean BRepAlgoAPI_BooleanOperation::PrepareFiller()
194 {
195   Standard_Boolean bIsNewFiller=Standard_False;
196   myErrorStatus=1;
197   //
198   if (myS1.IsNull() || myS2.IsNull()) {
199     myErrorStatus=2;
200     return bIsNewFiller;
201   }
202   //
203   if (myOperation==BOPAlgo_UNKNOWN) {
204     myErrorStatus=6;
205     return bIsNewFiller;
206   }
207   //
208   if (myDSFiller==NULL) {
209     bIsNewFiller=!bIsNewFiller;
210
211     myDSFiller=new BOPAlgo_PaveFiller;
212     //
213     if (myDSFiller==NULL) {
214       myErrorStatus=4;
215       return bIsNewFiller;
216     }
217     //
218     BOPCol_ListOfShape aLS;
219     aLS.Append(myS1);
220     aLS.Append(myS2);
221     //
222     myDSFiller->SetArguments(aLS);
223   }
224
225   return bIsNewFiller;
226 }
227 //=======================================================================
228 //function : Build
229 //purpose  : 
230 //=======================================================================
231   void BRepAlgoAPI_BooleanOperation::Build()
232 {
233   Standard_Boolean bIsNewFiller;
234   Standard_Integer iErr;
235   //
236   myBuilderCanWork=Standard_False;
237   NotDone();
238   //
239   bIsNewFiller=PrepareFiller();
240   //
241   if (myErrorStatus!=1) {
242     // there was errors during the preparation 
243     return;
244   }
245   //
246   if (bIsNewFiller) {
247     //Prepare the DS
248     myDSFiller->Perform();
249   }
250   //
251   if (myBuilder!=NULL) {
252     delete myBuilder;
253     myBuilder=NULL;
254   }
255   //
256   const TopoDS_Shape& aS1 = myS1;
257   const TopoDS_Shape& aS2 = myS2;
258   //
259   myShape.Nullify();
260
261   myBuilder=new BOPAlgo_BOP;
262   myBuilder->AddArgument(aS1);
263   myBuilder->AddTool(aS2);
264   myBuilder->SetOperation(myOperation);
265   //
266   myBuilder->PerformWithFiller(*myDSFiller);
267   iErr = myBuilder->ErrorStatus();
268   if (!iErr) {
269     myErrorStatus=0;
270     myBuilderCanWork=Standard_True;
271     myShape=myBuilder->Shape();
272     Done(); 
273   } 
274   else {
275     myErrorStatus=100+iErr;
276     NotDone();
277   }
278 }
279
280 //
281 //=======================================================================
282 //function : SectionEdges
283 //purpose  : 
284 //=======================================================================
285 const  TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::SectionEdges()
286 {
287   if (myBuilder==NULL) {
288     myGenerated.Clear();
289     return myGenerated;
290   }
291   //
292   Standard_Integer aNb, i, j, aNbCurves, nE;
293   BOPDS_ListIteratorOfListOfPaveBlock anIt;
294   //
295   const BOPDS_PDS& pDS = myDSFiller->PDS();
296   BOPDS_VectorOfInterfFF& aFFs=pDS->InterfFF();
297   myGenerated.Clear();
298   //
299   aNb=aFFs.Extent();
300   for (i = 0; i < aNb; i++) {
301     BOPDS_InterfFF& aFFi=aFFs(i);
302     const BOPDS_VectorOfCurve& aSeqOfCurve=aFFi.Curves();
303     //
304     aNbCurves=aSeqOfCurve.Extent();
305     for (j=0; j<aNbCurves; j++) {
306       const BOPDS_Curve& aCurve=aSeqOfCurve(j);
307       const BOPDS_ListOfPaveBlock& aSectEdges = aCurve.PaveBlocks();
308       //
309       anIt.Initialize(aSectEdges);
310       for(; anIt.More(); anIt.Next()) {
311         const Handle(BOPDS_PaveBlock)& aPB = anIt.Value();
312         nE = aPB->Edge();
313         const TopoDS_Shape& aE = pDS->Shape(nE);
314         myGenerated.Append(aE);
315       }
316     }
317   }
318   //
319   if(myFuseEdges) {
320     TopTools_ListOfShape theLS;
321     theLS.Assign(myGenerated);
322     //
323     RefinedList(theLS);
324   }
325   //
326   return myGenerated;
327 }
328
329 // ================================================================================================
330 // function: Modified2
331 // purpose:
332 // ================================================================================================
333 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::Modified2(const TopoDS_Shape& aS) 
334 {
335   if (myBuilder==NULL) {
336     myGenerated.Clear();
337     return myGenerated;
338   }
339   //
340   BOPCol_ListOfShape aLS;
341   BOPCol_ListIteratorOfListOfShape aIt;
342   myGenerated.Clear();
343   //
344   const BOPCol_DataMapOfShapeListOfShape& aImages = myBuilder->Images();
345   if (aImages.IsBound(aS)) {
346     aLS = aImages.Find(aS);
347   } else {
348     myGenerated.Append(aS);
349   }
350   //
351   aIt.Initialize(aLS);
352   for (;aIt.More(); aIt.Next()) {
353     myGenerated.Append(aIt.Value());
354   }
355   //
356   if (myFuseEdges) {
357     TopTools_ListOfShape theLS;
358     theLS.Assign(myGenerated);
359     //
360     RefinedList(theLS);
361   }
362   return myGenerated;
363 }
364
365 // ================================================================================================
366 // function: Generated
367 // purpose:
368 // ================================================================================================
369 const TopTools_ListOfShape& BRepAlgoAPI_BooleanOperation::Generated(const TopoDS_Shape& S) 
370 {
371   if (myBuilder==NULL) {
372     myGenerated.Clear();
373     return myGenerated;
374   }
375   //
376   if(myFuseEdges) {
377     const TopTools_ListOfShape& aL = myBuilder->Generated(S);
378     return RefinedList(aL);
379   }
380   
381   return myBuilder->Generated(S);
382 }
383
384 // ================================================================================================
385 // function: HasModified
386 // purpose:
387 // ================================================================================================
388 Standard_Boolean BRepAlgoAPI_BooleanOperation::HasModified() const
389 {
390   if (myBuilder==NULL) {
391     return Standard_False;
392   }
393   return myBuilder->HasModified();
394 }
395
396 // ================================================================================================
397 // function: HasGenerated
398 // purpose:
399 // ================================================================================================
400 Standard_Boolean BRepAlgoAPI_BooleanOperation::HasGenerated() const
401 {
402   if (myBuilder==NULL) {
403     return Standard_False;
404   }
405   return myBuilder->HasGenerated();
406 }
407
408 // ================================================================================================
409 // function: HasDeleted
410 // purpose:
411 // ================================================================================================
412 Standard_Boolean BRepAlgoAPI_BooleanOperation::HasDeleted() const
413 {
414   if (myBuilder==NULL) {
415     return Standard_False;
416   }
417   return myBuilder->HasDeleted();
418 }
419 //=======================================================================
420 //function : RefineEdges
421 //purpose  : 
422 //=======================================================================
423
424   void BRepAlgoAPI_BooleanOperation::RefineEdges ()
425 {
426   if(myFuseEdges) return; //Edges have been refined yet
427
428   BRepLib_FuseEdges FE(myShape);
429   FE.SetConcatBSpl(Standard_True);
430
431   // avoid fusing old edges
432   TopTools_IndexedMapOfShape mapOldEdges;
433   TopExp::MapShapes (myS1, TopAbs_EDGE, mapOldEdges);
434   TopExp::MapShapes (myS2, TopAbs_EDGE, mapOldEdges);
435   FE.AvoidEdges (mapOldEdges);
436
437   // Get List of edges that have been fused
438   myFuseEdges = Standard_False;
439   myModifFaces.Clear();
440   myEdgeMap.Clear();
441   TopTools_DataMapOfIntegerListOfShape aFusedEdges;
442
443   FE.Edges(aFusedEdges);
444   Standard_Integer nle = aFusedEdges.Extent();
445   if (nle != 0) {
446     FE.Perform();
447     myShape = FE.Shape();
448
449     TopTools_DataMapOfIntegerShape aResultEdges;
450
451     FE.ResultEdges(aResultEdges);
452     FE.Faces(myModifFaces);
453     myFuseEdges = Standard_True;
454     
455     Standard_Integer i;
456     for(i = 1; i <= nle; ++i) {
457       const TopoDS_Shape& aNewE = aResultEdges(i);
458       const TopTools_ListOfShape& aListOfOldEdges = aFusedEdges(i);
459       TopTools_ListIteratorOfListOfShape anIter(aListOfOldEdges);
460       for(; anIter.More(); anIter.Next()) {
461         myEdgeMap.Bind(anIter.Value(), aNewE);
462       }
463     }
464   }
465 }
466
467 //=======================================================================
468 //function : RefinedList
469 //purpose  : 
470 //=======================================================================
471 const TopTools_ListOfShape& 
472   BRepAlgoAPI_BooleanOperation::RefinedList(const TopTools_ListOfShape& theL) 
473 {
474   myGenerated.Clear();
475   TopTools_MapOfShape aMap;
476
477   TopTools_ListIteratorOfListOfShape anIter(theL);
478
479   for(; anIter.More(); anIter.Next()) {
480     const TopoDS_Shape& anS = anIter.Value();
481
482     if(anS.ShapeType() == TopAbs_EDGE) {
483       if(myEdgeMap.IsBound(anS)) {
484         const TopoDS_Shape& aNewEdge = myEdgeMap.Find(anS);
485         if(aMap.Add(aNewEdge)) {
486           myGenerated.Append(aNewEdge);
487         }
488       }
489       else {
490         myGenerated.Append(anS);
491       }
492     }
493     else if (anS.ShapeType() == TopAbs_FACE) {
494       if(myModifFaces.IsBound(anS)) {
495         myGenerated.Append(myModifFaces.Find(anS));
496       }
497       else {
498         myGenerated.Append(anS);
499       }
500     }
501     else {
502       myGenerated.Append(anS);
503     }
504   }
505
506   return myGenerated;
507
508 }