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