0022627: Change OCCT memory management defaults
[occt.git] / src / BRepTools / BRepTools_Quilt.cxx
1 // File:        BRepTools_Quilt.cxx
2 // Created:     Fri Dec 23 10:37:05 1994
3 // Author:      Remi LEQUETTE
4 //              <rle@bravox>
5
6
7 #include <BRepTools_Quilt.ixx>
8
9 #include <TopoDS.hxx>
10 #include <TopoDS_Face.hxx>
11 #include <TopoDS_Wire.hxx>
12 #include <TopoDS_Shape.hxx>
13 #include <TopoDS_Shell.hxx>
14 #include <TopoDS_Compound.hxx>
15 #include <TopoDS_Iterator.hxx>
16
17 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
18 #include <TopTools_DataMapOfShapeShape.hxx>
19 #include <TopExp_Explorer.hxx>
20
21 #include <Geom2d_Curve.hxx>
22
23 #include <BRep_Builder.hxx>
24 #include <BRep_Tool.hxx>
25 #include <TopTools_MapOfShape.hxx>
26 #include <TopoDS_Shape.hxx>
27 #include <TopTools_MapIteratorOfMapOfShape.hxx>
28 #include <TopTools_ListOfShape.hxx>
29 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
30
31 //=======================================================================
32 //function : BRepTools_Quilt
33 //purpose  : 
34 //=======================================================================
35
36 BRepTools_Quilt::BRepTools_Quilt() : hasCopy(Standard_False)
37 {
38 }
39
40 //=======================================================================
41 //function : Add
42 //purpose  : 
43 //=======================================================================
44 static Standard_Boolean NeedCopied(const TopoDS_Shape& theShape,const TopTools_IndexedDataMapOfShapeShape& myBounds)
45 {
46     // test if the shape must be copied
47     // i.e. it contains a bound subshape
48   Standard_Boolean IsCopied = Standard_False;
49   TopoDS_Iterator itv(theShape) ;
50   for ( ; itv.More(); itv.Next()) {
51     if (myBounds.Contains(itv.Value())) {
52       IsCopied = Standard_True;
53       break;
54     }
55   }
56   return IsCopied;
57 }
58 static void CopyShape(const TopoDS_Edge& E,TopTools_IndexedDataMapOfShapeShape& myBounds)
59 {
60   TopoDS_Edge NE = E;
61   NE.EmptyCopy();
62   NE.Orientation(TopAbs_FORWARD);
63   BRep_Builder B;
64   // add the edges
65   TopoDS_Iterator itv;
66   itv.Initialize(E,Standard_False) ; //TCollection_DataMap
67   for ( ; itv.More(); itv.Next()) {
68     const TopoDS_Shape& V = itv.Value();
69     if (myBounds.Contains(V)) {
70       B.Add(NE,myBounds.FindFromKey(V).Oriented(V.Orientation()));
71     }
72     else {
73       B.Add(NE,V);
74     }
75   }
76   // set the 3d range
77   Standard_Real f,l;
78   BRep_Tool::Range(E,f,l);
79   B.Range(NE,f,l);
80   myBounds.Add(E,NE.Oriented(TopAbs_FORWARD));
81 }
82 /*static void CopyShape(const TopoDS_Wire& W,TopTools_DataMapOfShapeShape& myBounds)
83 {
84   TopoDS_Wire NW;
85   B.MakeWire(NW);
86   TopoDS_Iterator ite(W,Standard_False);
87   for ( ; ite.More(); ite.Next()){
88     const TopoDS_Edge& E = TopoDS::Edge(ite.Value());
89     TopAbs_Orientation OE = E.Orientation();
90     if (myBounds.IsBound(E)) {
91       TopoDS_Edge& NE = TopoDS::Edge(myBounds(E));
92       B.Add(NW,NE.Oriented(OE));
93     }
94     else
95       B.Add(NW,E);
96   }
97   NW.Orientation(W.Orientation());
98   myBounds.Bind(W,NW);
99 }*/
100 void BRepTools_Quilt::Add(const TopoDS_Shape& S)
101 {
102   //cout <<" Version of sewing with free edges"<<endl;
103   // Binds all the faces of S
104   //  - to the face itself if it is not copied
105   //  - to the copy if it is copied
106   if(myBounds.Contains(S)) return;
107   BRep_Builder B;
108   for (TopExp_Explorer wex(S,TopAbs_WIRE,TopAbs_FACE); wex.More(); wex.Next()) 
109      myBounds.Add(wex.Current(),wex.Current());
110   
111   for (TopExp_Explorer eex(S,TopAbs_EDGE,TopAbs_WIRE); eex.More(); eex.Next())
112     myBounds.Add(eex.Current(),eex.Current());
113   
114   for (TopExp_Explorer vex(S,TopAbs_VERTEX,TopAbs_EDGE); vex.More(); vex.Next())
115     myBounds.Add(vex.Current(),vex.Current());
116   
117     // explore the faces
118     for (TopExp_Explorer fex(S,TopAbs_FACE); fex.More(); fex.Next()) {
119       
120       // explore the edges of the face and try to copy them
121       // if one edge is bound the face must be copied
122       
123       Standard_Boolean copyFace = Standard_False;
124       const TopoDS_Face& F = TopoDS::Face(fex.Current());
125       
126       if (hasCopy) { // if their is no binding, do not test for copy
127         
128         for (TopExp_Explorer fed(F,TopAbs_EDGE); fed.More(); fed.Next()) {
129           
130           if (myBounds.Contains(fed.Current())) {
131             copyFace = Standard_True;
132           }
133           else {
134             // test if the edge must be copied
135             // i.e. it contains a bound vertex
136             
137             Standard_Boolean copyEdge = NeedCopied(fed.Current(),myBounds);
138             //Standard_Boolean copyEdge = Standard_False;
139             const TopoDS_Edge& E = TopoDS::Edge(fed.Current());
140             
141             // TopoDS_Iterator itv(E) ;
142             // for ( ; itv.More(); itv.Next()) {
143               // if (myBounds.IsBound(itv.Value())) {
144                 //      copyEdge = Standard_True;
145                 // break;
146                 //     }
147               //  }
148             
149             if (copyEdge) {
150               
151               // copy of an edge
152               
153               copyFace = Standard_True;
154               CopyShape(E,myBounds);
155               //TopoDS_Edge NE = E; //gka version for free edges
156               //NE.EmptyCopy();
157               
158               //NE.Orientation(TopAbs_FORWARD);
159               // add the edges
160               //itv.Initialize(E,Standard_False) ;
161               //for ( ; itv.More(); itv.Next()) {
162                 //const TopoDS_Shape& V = itv.Value();
163                 //if (myBounds.IsBound(V)) {
164                  // B.Add(NE,myBounds(V).Oriented(V.Orientation()));
165                 //}
166                 //else {
167                  // B.Add(NE,V);
168                 //}
169               //}
170               // set the 3d range
171               //Standard_Real f,l;
172               //BRep_Tool::Range(E,f,l);
173               //B.Range(NE,f,l);
174               
175               //myBounds.Bind(E,NE.Oriented(TopAbs_FORWARD));
176             }
177           }
178         }
179       }
180       
181       // NF will be the copy of F or F itself
182       TopoDS_Face NF = F;
183
184       if (copyFace) {
185
186         // copy of a face 
187         
188         NF.EmptyCopy();
189         NF.Orientation(TopAbs_FORWARD);
190         
191         for (TopoDS_Iterator itw(F,Standard_False); itw.More(); itw.Next()) {
192           const TopoDS_Wire& W = TopoDS::Wire(itw.Value());
193           
194           TopoDS_Wire NW;
195           B.MakeWire(NW);
196           TopoDS_Iterator ite(W,Standard_False);
197           Standard_Real   UFirst,ULast;
198           
199           // Reconstruction des wires.
200           
201           for ( ; ite.More(); ite.Next()){
202             const TopoDS_Edge& E = TopoDS::Edge(ite.Value());
203             TopAbs_Orientation OE = E.Orientation();
204             if (myBounds.Contains(E)) {
205               const TopoDS_Edge& NE = TopoDS::Edge(myBounds.FindFromKey(E));
206               // pcurve.
207               if (NE.Orientation() == TopAbs_FORWARD) {
208                 B.UpdateEdge(NE,
209                              BRep_Tool::CurveOnSurface(E,F,UFirst,ULast),
210                              F,BRep_Tool::Tolerance(E));
211               }
212               else {
213                 // Si NE est REVERSED 
214                 // => les curve3d n ont pas la meme orientation.
215                 // ( C est une convention cf BRepTools_Quilt.cdl. et la methode
216                 // Bind.)
217                 // => la PCurve de E sur F doit etre inversee.
218                 
219                 OE = TopAbs::Reverse(OE);
220                 Handle(Geom2d_Curve) CE = 
221                   BRep_Tool::CurveOnSurface(E,F,UFirst,ULast);
222                 Handle(Geom2d_Curve) NCE = CE->Reversed();
223                 B.UpdateEdge(NE,NCE,F,BRep_Tool::Tolerance(E));
224                 Standard_Real tmp = UFirst;
225                 UFirst = CE->ReversedParameter(ULast);
226                 ULast  = CE->ReversedParameter(tmp);
227               }
228               // pcurve range
229               B.Range(NE,F,UFirst,ULast);
230
231               B.Add(NW,NE.Oriented(OE));
232             }
233             else {
234               B.Add(NW,E);
235             }
236           }
237           NW.Orientation(W.Orientation());
238           B.Add(NF,NW);
239         }
240         NF.Orientation(F.Orientation());
241       }
242
243       // binds the face to itself or its copy
244       myBounds.Add(F,NF);
245     }
246   
247 }
248
249 //=======================================================================
250 //function : Bind
251 //purpose  : 
252 //=======================================================================
253
254 void BRepTools_Quilt::Bind(const TopoDS_Vertex& Vold, 
255                            const TopoDS_Vertex& Vnew)
256 {
257   if (!myBounds.Contains(Vold)) {
258     myBounds.Add(Vold,Vnew);
259   }
260 }
261
262 //=======================================================================
263 //function : Bind
264 //purpose  : 
265 //=======================================================================
266
267 void BRepTools_Quilt::Bind(const TopoDS_Edge& Eold, const TopoDS_Edge& Enew)
268 {
269   if (!myBounds.Contains(Eold)) {
270     TopoDS_Edge ENew = Enew;
271     if (IsCopied(Enew)) {
272       ENew = TopoDS::Edge(Copy(Enew));
273       ENew.Orientation(Enew.Orientation());
274     }
275     
276     if (Eold.Orientation() != ENew.Orientation()) {
277       myBounds.Add(Eold.Oriented(TopAbs_FORWARD),
278                     ENew.Oriented(TopAbs_REVERSED));
279     }
280     else {
281       myBounds.Add(Eold.Oriented(TopAbs_FORWARD),
282                     ENew.Oriented(TopAbs_FORWARD));
283     }  
284     // if new binding bind also the vertices
285     TopoDS_Iterator itold(Eold);
286     while (itold.More()) {
287       if (!myBounds.Contains(itold.Value())) {
288         // find the vertex of Enew with same orientation
289         TopAbs_Orientation anOrien = itold.Value().Orientation();
290         TopoDS_Iterator itnew(ENew);
291         while (itnew.More()) {
292           if (itnew.Value().Orientation() == anOrien) {
293             TopoDS_Vertex VNew = TopoDS::Vertex(itnew.Value());
294             if (IsCopied(VNew)) {
295               // if VNew has been copied take the copy
296               VNew = TopoDS::Vertex(Copy(VNew));
297             }
298             myBounds.Add(itold.Value(),VNew);
299             break;
300           }
301           itnew.Next();
302         }
303       }
304       itold.Next();
305     }
306     hasCopy = Standard_True;
307   }
308 }
309
310 //=======================================================================
311 //function : IsBound
312 //purpose  : 
313 //=======================================================================
314
315 Standard_Boolean BRepTools_Quilt::IsCopied(const TopoDS_Shape& S) const 
316 {
317   if (myBounds.Contains(S)) {
318     return !S.IsSame(myBounds.FindFromKey(S));
319   }
320   else
321     return Standard_False;
322 }
323
324 //=======================================================================
325 //function : Copy
326 //purpose  : 
327 //=======================================================================
328
329 const TopoDS_Shape& BRepTools_Quilt::Copy(const TopoDS_Shape& S) const 
330 {
331   Standard_NoSuchObject_Raise_if(!IsCopied(S),"BRepTools_Quilt::Copy");
332   return myBounds.FindFromKey(S);
333 }
334
335 //=======================================================================
336 //function : Shells
337 //purpose  : 
338 //=======================================================================
339
340 TopoDS_Shape BRepTools_Quilt::Shells() const 
341 {
342   // Outline of the algorithm
343   //
344   // In the map M we bind the free edges to their shells
345   // We explore all the faces in myBounds
346   // For each one we search the edges in the map and either :
347   //
348   // - Start a new shell if no edge is a free edge.
349   // - Add the face to an existing shell
350   // - Connect other shells if the face touch more than one shell
351
352   // In the Map M the Shell is bound withe the relative orientation of E 
353   // in the shell
354   // In the map MF we binb the face to its shell.
355   // In the Map MF the Shell is bound with the relative orientation of F 
356   // in the shell
357
358   TopTools_DataMapOfShapeShape M, MF;
359   BRep_Builder                 B;
360   TopoDS_Compound              result;
361
362   B.MakeCompound(result);
363   
364   TopTools_MapOfShape MapOtherShape; //gka
365   TopTools_MapOfShape EdgesFaces;
366   
367   // loop on the face in myBounds
368   //TopTools_DataMapIteratorOfDataMapOfShapeShape it(myBounds);
369
370   //while (it.More()) 
371   for(Standard_Integer ii =1; ii <= myBounds.Extent(); ii++) {
372     const TopoDS_Shape& Shape = myBounds.FindFromIndex(ii); //it.Value();
373     if (Shape.ShapeType() == TopAbs_FACE) {
374       for(TopExp_Explorer aExpEdg(Shape,TopAbs_EDGE); aExpEdg.More(); aExpEdg.Next()) //gka
375         EdgesFaces.Add(aExpEdg.Current());
376       
377       TopoDS_Shell       SH;
378       TopAbs_Orientation NewO;
379
380       TopExp_Explorer itf1( Shape,TopAbs_EDGE);
381       for ( ; itf1.More(); itf1.Next()) {
382         const TopoDS_Shape& E = itf1.Current();
383         if (M.IsBound(E)) {
384           SH = TopoDS::Shell(M(E));
385           if (SH.Orientation() == E.Orientation())
386             NewO = TopAbs::Reverse(Shape.Orientation());
387           else
388             NewO = Shape.Orientation(); 
389
390           MF.Bind (Shape,SH.Oriented(NewO));
391           break;
392         }
393       }
394
395       if (SH.IsNull()) {
396         // Create a new shell, closed. Add it to the result.
397         B.MakeShell(SH);
398         SH.Closed(Standard_True);
399         B.Add(result,SH);
400         MF.Bind (Shape,SH.Oriented(Shape.Orientation()));
401       }
402
403
404       // Add the face to the shell
405       SH.Free(Standard_True);
406 //      B.Add(SH.Oriented(TopAbs_FORWARD), F .Oriented(MF(F).Orientation()));
407       TopoDS_Shape arefShape = SH.Oriented(TopAbs_FORWARD) ;
408       B.Add( arefShape , Shape.Oriented(MF(Shape).Orientation()));
409
410       TopExp_Explorer itf(Shape.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
411
412       for ( ;itf.More(); itf.Next()) {
413         const TopoDS_Edge& E = TopoDS::Edge(itf.Current());
414         
415         if (M.IsBound(E)) {
416           const TopoDS_Shape oldShell = M(E);
417           if (!oldShell.IsSame(SH)) {
418             // Fuse the old shell with the new one        
419             // Compare the orientation of E in SH and in oldshell.
420             TopAbs_Orientation anOrien = E.Orientation();
421             if (MF(Shape).Orientation() == TopAbs_REVERSED) 
422               anOrien = TopAbs::Reverse(anOrien);
423
424             Standard_Boolean Rev = (anOrien == oldShell.Orientation());
425             //if rev = True oldShell has to be reversed.
426
427             // Add the faces of oldShell in SH.
428             for (TopoDS_Iterator its(oldShell); its.More(); its.Next()) {
429               const TopoDS_Face Fo = TopoDS::Face(its.Value());
430               TopAbs_Orientation NewO;
431               // update the orientation of Fo in SH.
432               if (Rev) 
433                 NewO = TopAbs::Reverse(MF(Fo).Orientation());
434               else
435                 NewO = MF(Fo).Orientation();
436
437               MF.Bind(Fo,SH.Oriented(NewO));
438 //            B.Add  (SH.Oriented(TopAbs_FORWARD),Fo.Oriented(NewO));
439               TopoDS_Shape arefShape = SH.Oriented(TopAbs_FORWARD) ;
440               B.Add  ( arefShape ,Fo.Oriented(NewO));
441             }
442             // Rebind the free edges of the old shell to the new shell
443             //gka BUG 6491
444             TopExp_Explorer aexp(SH,TopAbs_EDGE);
445             for( ; aexp.More(); aexp.Next()) {
446             //for (TopTools_DataMapIteratorOfDataMapOfShapeShape itm(M);
447 //               itm.More(); ) {
448               if(!M.IsBound(aexp.Current()))
449                  continue;
450               TopoDS_Shape ae = aexp.Current();
451               TopoDS_Shape as = M.Find(ae);
452               if (as.IsSame(oldShell)) {
453                 // update the orientation of free edges in SH.
454                 if (Rev)
455                   NewO = TopAbs::Reverse(as.Orientation());
456                 else
457                   NewO = as.Orientation();
458                 
459                 M.Bind(ae,SH.Oriented(NewO));
460               }
461             }
462             // remove the old shell from the result
463             B.Remove(result,oldShell.Oriented(TopAbs_FORWARD));
464           }
465           // Test if SH is always orientable.
466           TopAbs_Orientation anOrien   =  E.Orientation();
467           if (MF(Shape).Orientation() == TopAbs_REVERSED)
468             anOrien = TopAbs::Reverse(anOrien);
469
470           if (M(E).Orientation() == anOrien)
471             SH.Orientable(Standard_False);
472           
473           // remove the edge from M (no more a free edge)           
474           M.UnBind(E);
475         }
476         else {
477           NewO = E.Orientation();
478           if (MF(Shape).Orientation() == TopAbs_REVERSED)
479             NewO = TopAbs::Reverse(NewO);
480           if(!E.IsNull())
481             M.Bind(E,SH.Oriented(NewO));
482           else
483             continue;
484         }
485       }
486
487       // freeze the shell
488       SH.Free(Standard_False);
489     }
490     else 
491      MapOtherShape.Add(Shape); 
492     
493     //it.Next();
494   }
495  
496   // Unclose all shells having free edges
497   for (TopTools_DataMapIteratorOfDataMapOfShapeShape it(M); it.More(); it.Next()) {
498     TopoDS_Shape S = it.Value();
499     S.Closed(Standard_Boolean(Standard_False));
500   }
501   
502   TopTools_MapIteratorOfMapOfShape itother(MapOtherShape); //gka version for free edges
503   for( ; itother.More() ; itother.Next()) {
504     if(!EdgesFaces.Contains(itother.Key()) && myBounds.Contains(itother.Key())) {
505       TopoDS_Shape aSh = myBounds.FindFromKey(itother.Key());
506       B.Add(result,aSh);
507     }
508   }
509   return result;
510 }
511