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