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