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