0029234: BRepOffsetAPI_NormalProjection produces INTERNAL edges and vertices
[occt.git] / src / BOPAlgo / BOPAlgo_MakerVolume.cxx
1 // Created by: Eugeny MALTCHIKOV
2 // Copyright (c) 2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <Bnd_Box.hxx>
16 #include <BOPAlgo_BuilderSolid.hxx>
17 #include <BOPAlgo_MakerVolume.hxx>
18 #include <BOPAlgo_PaveFiller.hxx>
19 #include <BOPAlgo_Tools.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPCol_DataMapOfShapeListOfShape.hxx>
22 #include <BOPCol_ListOfShape.hxx>
23 #include <BOPDS_DS.hxx>
24 #include <BOPTools.hxx>
25 #include <BOPTools_AlgoTools.hxx>
26 #include <BRepPrimAPI_MakeBox.hxx>
27 #include <TopExp_Explorer.hxx>
28 #include <TopoDS_Solid.hxx>
29
30 static
31   void AddFace(const TopoDS_Shape& theF,
32                BOPCol_ListOfShape& theLF);
33
34 //=======================================================================
35 //function : CheckData
36 //purpose  : 
37 //=======================================================================
38 void BOPAlgo_MakerVolume::CheckData()
39 {
40   if (myArguments.IsEmpty()) {
41     AddError (new BOPAlgo_AlertTooFewArguments); // no arguments to process
42     return;
43   }
44   //
45   CheckFiller();
46 }
47
48 //=======================================================================
49 //function : Perform
50 //purpose  : 
51 //=======================================================================
52 void BOPAlgo_MakerVolume::Perform()
53 {
54   GetReport()->Clear();
55   //
56   if (myEntryPoint == 1) {
57     if (myPaveFiller) {
58       delete myPaveFiller;
59       myPaveFiller = NULL;
60     }
61   }
62   //
63   Handle(NCollection_BaseAllocator) aAllocator = 
64     NCollection_BaseAllocator::CommonBaseAllocator();
65   BOPAlgo_PaveFiller* pPF = new BOPAlgo_PaveFiller(aAllocator);
66   //
67   if (!myIntersect) {
68     //if there is no need to intersect the arguments, then it is necessary
69     //to create the compound of them and use it as one argument
70     TopoDS_Compound anArgs;
71     BRep_Builder aBB;
72     BOPCol_ListIteratorOfListOfShape aIt;
73     BOPCol_ListOfShape aLS;
74     //
75     aBB.MakeCompound(anArgs);
76     aIt.Initialize(myArguments);
77     for (; aIt.More(); aIt.Next()) {
78       const TopoDS_Shape& aS = aIt.Value();
79       aBB.Add(anArgs, aS);
80     }
81     aLS.Append(anArgs);
82     //
83     pPF->SetArguments(aLS);
84   }
85   else {
86     pPF->SetArguments(myArguments);
87   }
88   //
89   pPF->SetRunParallel(myRunParallel);
90   pPF->SetProgressIndicator(myProgressIndicator);
91   pPF->SetFuzzyValue(myFuzzyValue);
92   pPF->SetNonDestructive(myNonDestructive);
93   pPF->SetGlue(myGlue);
94   pPF->Perform();
95   //
96   myEntryPoint = 1;
97   PerformInternal(*pPF);
98 }
99
100 //=======================================================================
101 //function : PerformInternal1
102 //purpose  : 
103 //=======================================================================
104 void BOPAlgo_MakerVolume::PerformInternal1
105   (const BOPAlgo_PaveFiller& theFiller)
106 {
107   myPaveFiller = (BOPAlgo_PaveFiller*)&theFiller;
108   myDS = myPaveFiller->PDS();
109   myContext = myPaveFiller->Context();
110   //
111   // 1. CheckData
112   CheckData();
113   if (HasErrors()) {
114     return;
115   }
116   //
117   // 2. Prepare
118   Prepare();
119   if (HasErrors()) {
120     return;
121   }
122   //
123   // 3. Fill Images
124   // 3.1. Vertice
125   if (myIntersect) {
126     FillImagesVertices();
127     if (HasErrors()) {
128       return;
129     }
130     // 3.2. Edges
131     FillImagesEdges();
132     if (HasErrors()) {
133       return;
134     }
135     // 3.3. Wires
136     FillImagesContainers(TopAbs_WIRE);
137     if (HasErrors()) {
138       return;
139     }
140     // 3.4. Faces
141     FillImagesFaces();
142     if (HasErrors()) {
143       return;
144     }
145   }
146   //
147   // 4. Collect faces
148   CollectFaces();
149   if (HasErrors()) {
150     return;
151   }
152   //
153   BOPCol_MapOfShape aBoxFaces;
154   BOPCol_ListOfShape aLSR;
155   //
156   // 5. Create bounding box
157   MakeBox(aBoxFaces);
158   //
159   // 6. Make volumes
160   BuildSolids(aLSR);
161   if (HasErrors()) {
162     return;
163   }
164   //
165   // 7. Treat the result
166   RemoveBox(aLSR, aBoxFaces);
167   //
168   // 8. Fill internal shapes
169   FillInternalShapes(aLSR);
170   //
171   // 9. Build Result
172   BuildShape(aLSR);
173   //
174   // 10. History
175   PrepareHistory();
176   //
177   // 11. Post-treatment 
178   PostTreat();  
179 }
180
181 //=======================================================================
182 //function : CollectFaces
183 //purpose  : 
184 //=======================================================================
185 void BOPAlgo_MakerVolume::CollectFaces()
186 {
187   UserBreak();
188   //
189   Standard_Integer i, aNbShapes;
190   BOPCol_ListIteratorOfListOfShape aIt;
191   BOPCol_MapOfShape aMFence;
192   //
193   aNbShapes = myDS->NbSourceShapes();
194   for (i = 0; i < aNbShapes; ++i) {
195     const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
196     if (aSI.ShapeType() != TopAbs_FACE) {
197       continue;
198     }
199     //
200     const Bnd_Box& aB = aSI.Box();
201     myBBox.Add(aB);
202     //
203     const TopoDS_Shape& aF = aSI.Shape();
204     if (myImages.IsBound(aF)) {
205       const BOPCol_ListOfShape& aLFIm = myImages.Find(aF);
206       aIt.Initialize(aLFIm);
207       for (; aIt.More(); aIt.Next()) {
208         const TopoDS_Shape& aFIm = aIt.Value();
209         if (aMFence.Add(aFIm)) {
210           AddFace(aFIm, myFaces);
211         }
212       }
213     }
214     else {
215       AddFace(aF, myFaces);
216     }
217   }
218 }
219
220 //=======================================================================
221 //function : MakeBox
222 //purpose  : 
223 //=======================================================================
224 void BOPAlgo_MakerVolume::MakeBox(BOPCol_MapOfShape& theBoxFaces)
225 {
226   UserBreak();
227   //
228   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, anExt;
229   //
230   anExt = sqrt(myBBox.SquareExtent()) * 0.5;
231   myBBox.Enlarge(anExt);
232   myBBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
233   //
234   gp_Pnt aPMin(aXmin, aYmin, aZmin), 
235          aPMax(aXmax, aYmax, aZmax);
236   //
237   mySBox = BRepPrimAPI_MakeBox(aPMin, aPMax).Solid();
238   //
239   TopExp_Explorer aExp(mySBox, TopAbs_FACE);
240   for (; aExp.More(); aExp.Next()) {
241     const TopoDS_Shape& aF = aExp.Current();
242     myFaces.Append(aF);
243     theBoxFaces.Add(aF);
244   }
245 }
246
247 //=======================================================================
248 //function : BuildSolids
249 //purpose  : 
250 //=======================================================================
251 void BOPAlgo_MakerVolume::BuildSolids(BOPCol_ListOfShape& theLSR)
252 {
253   UserBreak();
254   //
255   BOPAlgo_BuilderSolid aBS;
256   //
257   aBS.SetSolid(mySBox);
258   aBS.SetShapes(myFaces);
259   aBS.SetRunParallel(myRunParallel);
260   aBS.SetAvoidInternalShapes(myAvoidInternalShapes);
261   aBS.Perform();
262   if (aBS.HasErrors())
263   {
264     AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
265     return;
266   }
267   //
268   theLSR = aBS.Areas();
269 }
270
271 //=======================================================================
272 //function : TreatResult
273 //purpose  : 
274 //=======================================================================
275 void BOPAlgo_MakerVolume::RemoveBox(BOPCol_ListOfShape&      theLSR,
276                                     const BOPCol_MapOfShape& theBoxFaces)
277 {
278   UserBreak();
279   //
280   BOPCol_ListIteratorOfListOfShape aIt;
281   TopExp_Explorer aExp;
282   Standard_Boolean bFound;
283   //
284   bFound = Standard_False;
285   aIt.Initialize(theLSR);
286   for (; aIt.More(); aIt.Next()) {
287     const TopoDS_Shape& aSR = aIt.Value();
288     //
289     aExp.Init(aSR, TopAbs_FACE);
290     for (; aExp.More(); aExp.Next()) {
291       const TopoDS_Shape& aF = aExp.Current();
292       if (theBoxFaces.Contains(aF)) {
293         bFound = Standard_True;
294         theLSR.Remove(aIt);
295         break;
296       }
297     }
298     if (bFound) {
299       break;
300     }
301   }
302 }
303
304 //=======================================================================
305 //function : BuildShape
306 //purpose  : 
307 //=======================================================================
308 void BOPAlgo_MakerVolume::BuildShape(const BOPCol_ListOfShape& theLSR)
309
310   if (theLSR.Extent() == 1) {
311     myShape = theLSR.First();
312   }
313   else {
314     BRep_Builder aBB;
315     BOPCol_ListIteratorOfListOfShape aIt;
316     //
317     aIt.Initialize(theLSR);
318     for (; aIt.More(); aIt.Next()) {
319       const TopoDS_Shape& aSol = aIt.Value();
320       aBB.Add(myShape, aSol);
321     }
322   }
323 }
324
325 //=======================================================================
326 //function : FillInternalShapes 
327 //purpose  : 
328 //=======================================================================
329 void BOPAlgo_MakerVolume::FillInternalShapes(const BOPCol_ListOfShape& theLSR)
330 {
331   if (myAvoidInternalShapes) {
332     return;
333   }
334   //
335   UserBreak();
336   //
337   Standard_Integer aNbSI;
338   TopAbs_ShapeEnum aType;
339   TopAbs_State aState; 
340   TopoDS_Iterator aItS;
341   BRep_Builder aBB;
342   BOPCol_MapOfShape aMFence;
343   BOPCol_IndexedMapOfShape aMSS;
344   BOPCol_ListOfShape aLVE, aLSC, aLSIn;
345   BOPCol_ListIteratorOfListOfShape aIt, aIt1;
346   //
347   // 1. Collect shapes to process: vertices, edges, wires
348   const BOPCol_ListOfShape& anArguments = myDS->Arguments();
349   aIt.Initialize(anArguments);
350   for (; aIt.More(); aIt.Next()) {
351     const TopoDS_Shape& aS = aIt.Value();
352     BOPAlgo_Tools::TreatCompound(aS, aMFence, aLSC);
353   }
354   //
355   aIt.Initialize(aLSC);
356   for (; aIt.More(); aIt.Next()) {
357     const TopoDS_Shape& aS = aIt.Value();
358     aType = aS.ShapeType();
359     if (aType == TopAbs_WIRE) {
360       aItS.Initialize(aS);
361       for(; aItS.More(); aItS.Next()) {
362         const TopoDS_Shape& aE = aItS.Value();
363         if (aMFence.Add(aE)) {
364           aLVE.Append(aE);
365         }
366       }
367     }
368     else if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
369       aLVE.Append(aS);
370     } 
371   }
372   //
373   aIt.Initialize(theLSR);
374   for (; aIt.More(); aIt.Next()) {
375     const TopoDS_Shape& aS = aIt.Value();
376     BOPTools::MapShapes(aS, TopAbs_EDGE, aMSS);
377     BOPTools::MapShapes(aS, TopAbs_VERTEX, aMSS);
378   }
379   //
380   aIt.Initialize(aLVE);
381   for (; aIt.More(); aIt.Next()) {
382     const TopoDS_Shape& aS = aIt.Value();
383     if (myImages.IsBound(aS)) {
384       const BOPCol_ListOfShape &aLSp = myImages.Find(aS);
385       aIt1.Initialize(aLSp);
386       for (; aIt1.More(); aIt1.Next()) {
387         const TopoDS_Shape& aSp = aIt1.Value();
388         if (aMSS.Add(aSp)) {
389           aLSIn.Append(aSp);
390         }
391       }
392     }
393     else {
394       if (aMSS.Add(aS)) {
395         aLSIn.Append(aS);
396       }
397     }
398   }
399   //
400   aNbSI = aLSIn.Extent();
401   if (!aNbSI) {
402     return;
403   }
404   //
405   // 2. Settle internal vertices and edges into solids
406   aIt.Initialize(theLSR);
407   for (; aIt.More(); aIt.Next()) {
408     TopoDS_Solid aSd = *(TopoDS_Solid*)&aIt.Value();
409     //
410     aIt1.Initialize(aLSIn);
411     for (; aIt1.More(); ) {
412       TopoDS_Shape aSI = aIt1.Value();
413       aSI.Orientation(TopAbs_INTERNAL);
414       //
415       aState = BOPTools_AlgoTools::ComputeStateByOnePoint(aSI, aSd, 1.e-11, myContext);
416       if (aState == TopAbs_IN) {
417         aBB.Add(aSd, aSI);
418         aLSIn.Remove(aIt1);
419       }
420       else {
421         aIt1.Next();
422       }
423     }
424   }
425 }
426
427 //=======================================================================
428 //function : AddFace
429 //purpose  : 
430 //=======================================================================
431 void AddFace(const TopoDS_Shape& theF,
432              BOPCol_ListOfShape& theLF)
433 {
434   TopoDS_Shape aFF = theF;
435   aFF.Orientation(TopAbs_FORWARD);
436   theLF.Append(aFF);
437   aFF.Orientation(TopAbs_REVERSED);
438   theLF.Append(aFF);
439 }