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