Integration of OCCT 6.5.0 from SVN
[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 #ifdef DEB
198           Standard_Real   Tol = BRep_Tool::Tolerance(F);
199 #else
200           BRep_Tool::Tolerance(F);
201 #endif
202           Standard_Real   UFirst,ULast;
203           
204           // Reconstruction des wires.
205           
206           for ( ; ite.More(); ite.Next()){
207             const TopoDS_Edge& E = TopoDS::Edge(ite.Value());
208             TopAbs_Orientation OE = E.Orientation();
209             if (myBounds.Contains(E)) {
210               const TopoDS_Edge& NE = TopoDS::Edge(myBounds.FindFromKey(E));
211               // pcurve.
212               if (NE.Orientation() == TopAbs_FORWARD) {
213                 B.UpdateEdge(NE,
214                              BRep_Tool::CurveOnSurface(E,F,UFirst,ULast),
215                              F,BRep_Tool::Tolerance(E));
216               }
217               else {
218                 // Si NE est REVERSED 
219                 // => les curve3d n ont pas la meme orientation.
220                 // ( C est une convention cf BRepTools_Quilt.cdl. et la methode
221                 // Bind.)
222                 // => la PCurve de E sur F doit etre inversee.
223                 
224                 OE = TopAbs::Reverse(OE);
225                 Handle(Geom2d_Curve) CE = 
226                   BRep_Tool::CurveOnSurface(E,F,UFirst,ULast);
227                 Handle(Geom2d_Curve) NCE = CE->Reversed();
228                 B.UpdateEdge(NE,NCE,F,BRep_Tool::Tolerance(E));
229                 Standard_Real tmp = UFirst;
230                 UFirst = CE->ReversedParameter(ULast);
231                 ULast  = CE->ReversedParameter(tmp);
232               }
233               // pcurve range
234               B.Range(NE,F,UFirst,ULast);
235
236               B.Add(NW,NE.Oriented(OE));
237             }
238             else {
239               B.Add(NW,E);
240             }
241           }
242           NW.Orientation(W.Orientation());
243           B.Add(NF,NW);
244         }
245         NF.Orientation(F.Orientation());
246       }
247
248       // binds the face to itself or its copy
249       myBounds.Add(F,NF);
250     }
251   
252 }
253
254 //=======================================================================
255 //function : Bind
256 //purpose  : 
257 //=======================================================================
258
259 void BRepTools_Quilt::Bind(const TopoDS_Vertex& Vold, 
260                            const TopoDS_Vertex& Vnew)
261 {
262   if (!myBounds.Contains(Vold)) {
263     myBounds.Add(Vold,Vnew);
264   }
265 }
266
267 //=======================================================================
268 //function : Bind
269 //purpose  : 
270 //=======================================================================
271
272 void BRepTools_Quilt::Bind(const TopoDS_Edge& Eold, const TopoDS_Edge& Enew)
273 {
274   if (!myBounds.Contains(Eold)) {
275     TopoDS_Edge ENew = Enew;
276     if (IsCopied(Enew)) {
277       ENew = TopoDS::Edge(Copy(Enew));
278       ENew.Orientation(Enew.Orientation());
279     }
280     
281     if (Eold.Orientation() != ENew.Orientation()) {
282       myBounds.Add(Eold.Oriented(TopAbs_FORWARD),
283                     ENew.Oriented(TopAbs_REVERSED));
284     }
285     else {
286       myBounds.Add(Eold.Oriented(TopAbs_FORWARD),
287                     ENew.Oriented(TopAbs_FORWARD));
288     }  
289     // if new binding bind also the vertices
290     TopoDS_Iterator itold(Eold);
291     while (itold.More()) {
292       if (!myBounds.Contains(itold.Value())) {
293         // find the vertex of Enew with same orientation
294         TopAbs_Orientation anOrien = itold.Value().Orientation();
295         TopoDS_Iterator itnew(ENew);
296         while (itnew.More()) {
297           if (itnew.Value().Orientation() == anOrien) {
298             TopoDS_Vertex VNew = TopoDS::Vertex(itnew.Value());
299             if (IsCopied(VNew)) {
300               // if VNew has been copied take the copy
301               VNew = TopoDS::Vertex(Copy(VNew));
302             }
303             myBounds.Add(itold.Value(),VNew);
304             break;
305           }
306           itnew.Next();
307         }
308       }
309       itold.Next();
310     }
311     hasCopy = Standard_True;
312   }
313 }
314
315 //=======================================================================
316 //function : IsBound
317 //purpose  : 
318 //=======================================================================
319
320 Standard_Boolean BRepTools_Quilt::IsCopied(const TopoDS_Shape& S) const 
321 {
322   if (myBounds.Contains(S)) {
323     return !S.IsSame(myBounds.FindFromKey(S));
324   }
325   else
326     return Standard_False;
327 }
328
329 //=======================================================================
330 //function : Copy
331 //purpose  : 
332 //=======================================================================
333
334 const TopoDS_Shape& BRepTools_Quilt::Copy(const TopoDS_Shape& S) const 
335 {
336   Standard_NoSuchObject_Raise_if(!IsCopied(S),"BRepTools_Quilt::Copy");
337   return myBounds.FindFromKey(S);
338 }
339
340 //=======================================================================
341 //function : Shells
342 //purpose  : 
343 //=======================================================================
344
345 TopoDS_Shape BRepTools_Quilt::Shells() const 
346 {
347   // Outline of the algorithm
348   //
349   // In the map M we bind the free edges to their shells
350   // We explore all the faces in myBounds
351   // For each one we search the edges in the map and either :
352   //
353   // - Start a new shell if no edge is a free edge.
354   // - Add the face to an existing shell
355   // - Connect other shells if the face touch more than one shell
356
357   // In the Map M the Shell is bound withe the relative orientation of E 
358   // in the shell
359   // In the map MF we binb the face to its shell.
360   // In the Map MF the Shell is bound with the relative orientation of F 
361   // in the shell
362
363   TopTools_DataMapOfShapeShape M, MF;
364   BRep_Builder                 B;
365   TopoDS_Compound              result;
366
367   B.MakeCompound(result);
368   
369   TopTools_MapOfShape MapOtherShape; //gka
370   TopTools_MapOfShape EdgesFaces;
371   
372   // loop on the face in myBounds
373   //TopTools_DataMapIteratorOfDataMapOfShapeShape it(myBounds);
374
375   //while (it.More()) 
376   for(Standard_Integer ii =1; ii <= myBounds.Extent(); ii++) {
377     const TopoDS_Shape& Shape = myBounds.FindFromIndex(ii); //it.Value();
378     if (Shape.ShapeType() == TopAbs_FACE) {
379       for(TopExp_Explorer aExpEdg(Shape,TopAbs_EDGE); aExpEdg.More(); aExpEdg.Next()) //gka
380         EdgesFaces.Add(aExpEdg.Current());
381       
382       TopoDS_Shell       SH;
383       TopAbs_Orientation NewO;
384
385       TopExp_Explorer itf1( Shape,TopAbs_EDGE);
386       for ( ; itf1.More(); itf1.Next()) {
387         const TopoDS_Shape& E = itf1.Current();
388         if (M.IsBound(E)) {
389           SH = TopoDS::Shell(M(E));
390           if (SH.Orientation() == E.Orientation())
391             NewO = TopAbs::Reverse(Shape.Orientation());
392           else
393             NewO = Shape.Orientation(); 
394
395           MF.Bind (Shape,SH.Oriented(NewO));
396           break;
397         }
398       }
399
400       if (SH.IsNull()) {
401         // Create a new shell, closed. Add it to the result.
402         B.MakeShell(SH);
403         SH.Closed(Standard_True);
404         B.Add(result,SH);
405         MF.Bind (Shape,SH.Oriented(Shape.Orientation()));
406       }
407
408
409       // Add the face to the shell
410       SH.Free(Standard_True);
411 //      B.Add(SH.Oriented(TopAbs_FORWARD), F .Oriented(MF(F).Orientation()));
412       TopoDS_Shape arefShape = SH.Oriented(TopAbs_FORWARD) ;
413       B.Add( arefShape , Shape.Oriented(MF(Shape).Orientation()));
414
415       TopExp_Explorer itf(Shape.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
416
417       for ( ;itf.More(); itf.Next()) {
418         const TopoDS_Edge& E = TopoDS::Edge(itf.Current());
419         
420         if (M.IsBound(E)) {
421           const TopoDS_Shape oldShell = M(E);
422           if (!oldShell.IsSame(SH)) {
423             // Fuse the old shell with the new one        
424             // Compare the orientation of E in SH and in oldshell.
425             TopAbs_Orientation anOrien = E.Orientation();
426             if (MF(Shape).Orientation() == TopAbs_REVERSED) 
427               anOrien = TopAbs::Reverse(anOrien);
428
429             Standard_Boolean Rev = (anOrien == oldShell.Orientation());
430             //if rev = True oldShell has to be reversed.
431
432             // Add the faces of oldShell in SH.
433             for (TopoDS_Iterator its(oldShell); its.More(); its.Next()) {
434               const TopoDS_Face Fo = TopoDS::Face(its.Value());
435               TopAbs_Orientation NewO;
436               // update the orientation of Fo in SH.
437               if (Rev) 
438                 NewO = TopAbs::Reverse(MF(Fo).Orientation());
439               else
440                 NewO = MF(Fo).Orientation();
441
442               MF.Bind(Fo,SH.Oriented(NewO));
443 //            B.Add  (SH.Oriented(TopAbs_FORWARD),Fo.Oriented(NewO));
444               TopoDS_Shape arefShape = SH.Oriented(TopAbs_FORWARD) ;
445               B.Add  ( arefShape ,Fo.Oriented(NewO));
446             }
447             Standard_Integer kk =1;
448             Standard_Integer p =0;
449             // Rebind the free edges of the old shell to the new shell
450             //gka BUG 6491
451             TopExp_Explorer aexp(SH,TopAbs_EDGE);
452             for( ; aexp.More(); aexp.Next()) {
453             //for (TopTools_DataMapIteratorOfDataMapOfShapeShape itm(M);
454 //               itm.More(); ) {
455               if(!M.IsBound(aexp.Current()))
456                  continue;
457               TopoDS_Shape ae = aexp.Current();
458               TopoDS_Shape as = M.Find(ae);
459               if (as.IsSame(oldShell)) {
460                 // update the orientation of free edges in SH.
461                 if (Rev)
462                   NewO = TopAbs::Reverse(as.Orientation());
463                 else
464                   NewO = as.Orientation();
465                 
466                 M.Bind(ae,SH.Oriented(NewO));
467               }
468             }
469             // remove the old shell from the result
470             B.Remove(result,oldShell.Oriented(TopAbs_FORWARD));
471           }
472           // Test if SH is always orientable.
473           TopAbs_Orientation anOrien   =  E.Orientation();
474           if (MF(Shape).Orientation() == TopAbs_REVERSED)
475             anOrien = TopAbs::Reverse(anOrien);
476
477           if (M(E).Orientation() == anOrien)
478             SH.Orientable(Standard_False);
479           
480           // remove the edge from M (no more a free edge)           
481           M.UnBind(E);
482         }
483         else {
484           NewO = E.Orientation();
485           if (MF(Shape).Orientation() == TopAbs_REVERSED)
486             NewO = TopAbs::Reverse(NewO);
487           if(!E.IsNull())
488             M.Bind(E,SH.Oriented(NewO));
489           else
490             continue;
491         }
492       }
493
494       // freeze the shell
495       SH.Free(Standard_False);
496     }
497     else 
498      MapOtherShape.Add(Shape); 
499     
500     //it.Next();
501   }
502  
503   // Unclose all shells having free edges
504   for (TopTools_DataMapIteratorOfDataMapOfShapeShape it(M); it.More(); it.Next()) {
505     TopoDS_Shape S = it.Value();
506     S.Closed(Standard_Boolean(Standard_False));
507   }
508   
509   TopTools_MapIteratorOfMapOfShape itother(MapOtherShape); //gka version for free edges
510   for( ; itother.More() ; itother.Next()) {
511     if(!EdgesFaces.Contains(itother.Key()) && myBounds.Contains(itother.Key())) {
512       TopoDS_Shape aSh = myBounds.FindFromKey(itother.Key());
513       B.Add(result,aSh);
514     }
515   }
516   return result;
517 }
518