0030675: Visualization - remove redundant proxy classes in hierarchy of PrsMgr_Presen...
[occt.git] / src / ShapeExtend / ShapeExtend_WireData.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 //:q0 abv 12.03.99: mat-a.stp: protection against no pcurves in SwapSeam()
15 //    abv 28.04.99  S4137: added method Add(WireData), method SetLast fixed
16 //    abv 05.05.99  S4174: protection against INTERNAL/EXTERNAL edges
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <BRepBuilderAPI_MakeWire.hxx>
21 #include <BRepTools_WireExplorer.hxx>
22 #include <Geom2d_Curve.hxx>
23 #include <ShapeExtend_WireData.hxx>
24 #include <Standard_Type.hxx>
25 #include <TopExp.hxx>
26 #include <TopoDS.hxx>
27 #include <TopoDS_Edge.hxx>
28 #include <TopoDS_Face.hxx>
29 #include <TopoDS_Iterator.hxx>
30 #include <TopoDS_Shape.hxx>
31 #include <TopoDS_Vertex.hxx>
32 #include <TopoDS_Wire.hxx>
33 #include <TopTools_IndexedMapOfShape.hxx>
34
35 IMPLEMENT_STANDARD_RTTIEXT(ShapeExtend_WireData,Standard_Transient)
36
37 //=======================================================================
38 //function : ShapeExtend_WireData
39 //purpose  : 
40 //=======================================================================
41 ShapeExtend_WireData::ShapeExtend_WireData()
42 {
43   Clear();  
44 }
45
46 //=======================================================================
47 //function : ShapeExtend_WireData
48 //purpose  : 
49 //=======================================================================
50
51 ShapeExtend_WireData::ShapeExtend_WireData (const TopoDS_Wire& wire,
52                                             const Standard_Boolean chained,
53                                             const Standard_Boolean theManifold)
54 {
55   Init ( wire, chained ,theManifold);  
56 }
57
58 //=======================================================================
59 //function : Init
60 //purpose  : 
61 //=======================================================================
62
63 void ShapeExtend_WireData::Init (const Handle(ShapeExtend_WireData)& other) 
64 {
65   Clear();
66   Standard_Integer i, nb = other->NbEdges();
67   for (i = 1; i <= nb; i++) Add ( other->Edge(i) );
68   nb = other->NbNonManifoldEdges();
69   for (i = 1; i <= nb; i++) Add ( other->NonmanifoldEdge(i) );
70   myManifoldMode = other->ManifoldMode();
71 }
72
73 //=======================================================================
74 //function : Init
75 //purpose  : 
76 //=======================================================================
77
78 Standard_Boolean ShapeExtend_WireData::Init (const TopoDS_Wire& wire,
79                                              const Standard_Boolean chained,
80                                              const Standard_Boolean theManifold) 
81 {
82   Clear();
83   myManifoldMode = theManifold;
84   Standard_Boolean OK = Standard_True;
85   TopoDS_Vertex Vlast;
86   for ( TopoDS_Iterator it(wire); it.More(); it.Next() ) {
87     TopoDS_Edge E = TopoDS::Edge ( it.Value() );
88
89     // protect against INTERNAL/EXTERNAL edges
90     if ( (E.Orientation() != TopAbs_REVERSED &&
91          E.Orientation() != TopAbs_FORWARD)) {
92       myNonmanifoldEdges->Append(E);
93       continue;
94     }
95     
96     TopoDS_Vertex V1, V2;
97     for ( TopoDS_Iterator itv(E); itv.More(); itv.Next() ) {
98       TopoDS_Vertex V = TopoDS::Vertex ( itv.Value() );
99       if ( V.Orientation() == TopAbs_FORWARD ) V1 = V;
100       else if ( V.Orientation() == TopAbs_REVERSED ) V2 = V;
101     }
102
103     // chainage? Si pas bon et chained False on repart sur WireExplorer
104     if ( ! Vlast.IsNull() && ! Vlast.IsSame ( V1 ) && theManifold) {
105       OK = Standard_False;
106       if ( ! chained ) break;
107     }
108     Vlast = V2;
109     if(wire.Orientation() == TopAbs_REVERSED)
110       myEdges->Prepend( E );
111     else
112       myEdges->Append ( E );
113   }
114
115   if(!myManifoldMode) {
116     Standard_Integer nb = myNonmanifoldEdges->Length();
117     Standard_Integer i =1;
118     for( ; i <= nb; i++)
119       myEdges->Append(myNonmanifoldEdges->Value(i));
120     myNonmanifoldEdges->Clear();
121   }
122 //    refaire chainage ?  Par WireExplorer
123   if ( OK || chained ) return OK;
124
125   Clear();
126   for ( BRepTools_WireExplorer we(wire); we.More(); we.Next() ) 
127     myEdges->Append ( TopoDS::Edge ( we.Current() ) );
128
129   return OK;
130 }
131
132 //=======================================================================
133 //function : Clear
134 //purpose  : 
135 //=======================================================================
136
137 void ShapeExtend_WireData::Clear() 
138 {
139   myEdges = new TopTools_HSequenceOfShape();
140   myNonmanifoldEdges = new TopTools_HSequenceOfShape;
141   mySeamF = mySeamR = -1;  
142   mySeams.Nullify();
143   myManifoldMode = Standard_True;
144 }
145
146 //=======================================================================
147 //function : ComputeSeams
148 //purpose  : 
149 //=======================================================================
150
151 void ShapeExtend_WireData::ComputeSeams (const Standard_Boolean enforce) 
152 {
153   if (mySeamF >= 0 && !enforce) return;
154
155   mySeams = new TColStd_HSequenceOfInteger();
156   mySeamF = mySeamR = 0;
157   TopoDS_Shape S;
158   Standard_Integer i, nb = NbEdges();
159   TopTools_IndexedMapOfShape ME;
160   Standard_Integer* SE = new Standard_Integer [nb+1];
161
162   //  deux passes : d abord on mappe les Edges REVERSED
163   //  Pour chacune, on note aussi son RANG dans la liste
164   for (i = 1; i <= nb; i ++) {
165     S = Edge(i);
166     if (S.Orientation() == TopAbs_REVERSED) {
167       Standard_Integer num = ME.Add (S);
168       SE[num] = i;
169     }
170   }
171   
172   //  ensuite on voit les Edges FORWARD qui y seraient deja -> on note leur n0
173   //  c-a-d le n0 de la directe ET de la reverse
174   for (i = 1; i <= nb; i ++) {
175     S = Edge(i);
176     if (S.Orientation() == TopAbs_REVERSED) continue;
177     Standard_Integer num = ME.FindIndex (S);
178     if (num <= 0) continue;
179     if (mySeamF == 0) { mySeamF = i; mySeamR = SE[num]; }
180     else { mySeams->Append(i); mySeams->Append( SE[num] ); }
181   }
182
183   delete [] SE;  // ne pas oublier !!
184 }
185
186 //=======================================================================
187 //function : SetLast
188 //purpose  : 
189 //=======================================================================
190
191 void ShapeExtend_WireData::SetLast (const Standard_Integer num) 
192 {
193   if (num == 0) return;
194   Standard_Integer i, nb = NbEdges();
195   for (i = nb; i > num; i--) {
196     TopoDS_Edge edge = TopoDS::Edge ( myEdges->Value(nb) );
197     myEdges->Remove (nb);
198     myEdges->InsertBefore (1, edge);
199   }
200   mySeamF = -1;
201 }
202
203 //=======================================================================
204 //function : SetDegeneratedLast
205 //purpose  : 
206 //=======================================================================
207
208 void ShapeExtend_WireData::SetDegeneratedLast() 
209 {
210   Standard_Integer i, nb = NbEdges();
211   for (i = 1; i <= nb; i ++) {
212     if ( BRep_Tool::Degenerated ( Edge(i) ) ) {
213       SetLast ( i );
214       return;
215     }
216   }
217 }
218
219 //=======================================================================
220 //function : Add
221 //purpose  : 
222 //=======================================================================
223
224 void ShapeExtend_WireData::Add (const TopoDS_Edge& edge,
225                                const Standard_Integer atnum) 
226 {
227   if(edge.Orientation()!= TopAbs_REVERSED &&
228          edge.Orientation() != TopAbs_FORWARD && myManifoldMode) {
229     myNonmanifoldEdges->Append(edge);
230     return;
231   }
232     
233   if (edge.IsNull()) return;
234   if (atnum == 0) {
235     myEdges->Append (edge);
236   } 
237   else {
238     myEdges->InsertBefore (atnum,edge);
239   }
240   mySeamF = -1;
241 }
242
243 //=======================================================================
244 //function : Add
245 //purpose  : 
246 //=======================================================================
247
248 void ShapeExtend_WireData::Add (const TopoDS_Wire& wire,
249                                 const Standard_Integer atnum) 
250 {
251   if (wire.IsNull()) return;
252   Standard_Integer n = atnum;
253   TopTools_SequenceOfShape aNMEdges;
254   for (TopoDS_Iterator it(wire); it.More(); it.Next()) {
255     TopoDS_Edge edge = TopoDS::Edge (it.Value());
256     if(edge.Orientation()!= TopAbs_REVERSED &&
257          edge.Orientation() != TopAbs_FORWARD) {
258       if(myManifoldMode)
259         myNonmanifoldEdges->Append(edge);
260       else
261         aNMEdges.Append(edge);
262       continue;
263     }
264     if (n == 0) {
265       myEdges->Append (edge);
266     } else {
267       myEdges->InsertBefore (n,edge);
268       n++;
269     }
270   }
271   Standard_Integer i =1, nb = aNMEdges.Length();
272   for( ; i <= nb ; i++)
273     myEdges->Append(aNMEdges.Value(i));
274   mySeamF = -1;
275 }
276
277 //=======================================================================
278 //function : Add
279 //purpose  : 
280 //=======================================================================
281
282 void ShapeExtend_WireData::Add (const Handle(ShapeExtend_WireData) &wire,
283                                 const Standard_Integer atnum) 
284 {
285   if ( wire.IsNull() ) return;
286   TopTools_SequenceOfShape aNMEdges;
287   Standard_Integer n = atnum;
288   Standard_Integer i=1;
289   for (; i <= wire->NbEdges(); i++ ) {
290     TopoDS_Edge aE =  wire->Edge(i);
291     if(aE.Orientation() == TopAbs_INTERNAL || 
292        aE.Orientation() == TopAbs_EXTERNAL) {
293       aNMEdges.Append(aE);
294       continue;
295     }
296       
297     if (n == 0 ) {
298       myEdges->Append ( wire->Edge(i) );
299     } 
300     else {
301       myEdges->InsertBefore ( n, wire->Edge(i) );
302       n++;
303     }
304   }
305   
306   //non-manifold edges for non-manifold wire shoud be added at end
307   for (i=1; i <=aNMEdges.Length(); i++)
308     myEdges->Append(aNMEdges.Value(i));
309   
310   for (i=1; i <= wire->NbNonManifoldEdges(); i++) {
311     if( myManifoldMode)
312       myNonmanifoldEdges->Append(wire->NonmanifoldEdge(i));
313     else {
314       if (n == 0) 
315         myEdges->Append ( wire->Edge(i) );
316     
317       else {
318         myEdges->InsertBefore ( n, wire->Edge(i) );
319         n++;
320       }
321     }
322   }
323   
324   mySeamF = -1;
325 }
326
327 //=======================================================================
328 //function : Add
329 //purpose  : 
330 //=======================================================================
331
332 void ShapeExtend_WireData::Add (const TopoDS_Shape& shape,
333                                const Standard_Integer atnum) 
334 {
335   if      (shape.ShapeType() == TopAbs_EDGE) Add (TopoDS::Edge (shape), atnum);
336   else if (shape.ShapeType() == TopAbs_WIRE) Add (TopoDS::Wire (shape), atnum);
337 }
338
339 //=======================================================================
340 //function : AddOriented
341 //purpose  : 
342 //=======================================================================
343
344 void ShapeExtend_WireData::AddOriented (const TopoDS_Edge& edge,
345                                        const Standard_Integer mode) 
346 {
347   if (edge.IsNull() || mode < 0) return;
348   TopoDS_Edge E = edge;
349   if (mode == 1 || mode == 3) E.Reverse();
350   Add (E, mode/2);  // mode = 0,1 -> 0  mode = 2,3 -> 1
351 }
352
353 //=======================================================================
354 //function : AddOriented
355 //purpose  : 
356 //=======================================================================
357
358 void ShapeExtend_WireData::AddOriented (const TopoDS_Wire& wire,
359                                        const Standard_Integer mode) 
360 {
361   if (wire.IsNull() || mode < 0) return;
362   TopoDS_Wire W = wire;
363   if (mode == 1 || mode == 3) W.Reverse();
364   Add (W, mode/2);  // mode = 0,1 -> 0  mode = 2,3 -> 1
365 }
366
367 void ShapeExtend_WireData::AddOriented (const TopoDS_Shape& shape,
368                                         const Standard_Integer mode) 
369 {
370   if      (shape.ShapeType() == TopAbs_EDGE) AddOriented (TopoDS::Edge (shape), mode);
371   else if (shape.ShapeType() == TopAbs_WIRE) AddOriented (TopoDS::Wire (shape), mode);
372 }
373
374 //=======================================================================
375 //function : Remove
376 //purpose  : 
377 //=======================================================================
378
379 void ShapeExtend_WireData::Remove (const Standard_Integer num) 
380 {
381  
382   myEdges->Remove ( num > 0 ? num : NbEdges() );
383  
384   mySeamF = -1;
385 }
386
387 //=======================================================================
388 //function : Set
389 //purpose  : 
390 //=======================================================================
391
392 void ShapeExtend_WireData::Set (const TopoDS_Edge& edge,
393                                const Standard_Integer num) 
394 {
395   if(edge.Orientation()!= TopAbs_REVERSED &&
396          edge.Orientation() != TopAbs_FORWARD && myManifoldMode) {
397     if(num <= myNonmanifoldEdges->Length())
398       myNonmanifoldEdges->SetValue(num,edge);
399     else
400       myNonmanifoldEdges->Append(edge);
401   }
402   
403   else
404     myEdges->SetValue ( ( num > 0 ? num : NbEdges() ), edge);
405   mySeamF = -1;
406 }
407
408 //=======================================================================
409 //function : Reverse
410 //purpose  : reverse order of edges in the wire
411 //=======================================================================
412
413 void ShapeExtend_WireData::Reverse () 
414 {
415   Standard_Integer i, nb = NbEdges();
416
417   // inverser les edges + les permuter pour inverser le wire
418   for (i = 1; i <= nb/2; i ++) {
419     TopoDS_Shape S1 = myEdges->Value(i);      S1.Reverse();
420     TopoDS_Shape S2 = myEdges->Value(nb+1-i); S2.Reverse();
421     myEdges->SetValue (i,      S2);
422     myEdges->SetValue (nb+1-i, S1);
423   }
424   //  nb d edges impair : inverser aussi l edge du milieu (rang inchange)
425   if ( nb % 2 ) {    //  test impair
426     i = (nb+1)/2;
427     TopoDS_Shape SI = myEdges->Value(i);      SI.Reverse();
428     myEdges->SetValue (i, SI);
429   }
430   mySeamF = -1;
431 }
432
433 //=======================================================================
434 //function : Reverse
435 //purpose  : 
436 //=======================================================================
437
438 //  Fonction auxiliaire SwapSeam pour inverser
439 static void SwapSeam (const TopoDS_Shape& S, const TopoDS_Face& F)
440 {
441   TopoDS_Edge E = TopoDS::Edge (S);
442   if ( E.IsNull() || F.IsNull() ) return;
443   if ( E.Orientation() == TopAbs_REVERSED ) return;  // ne le faire qu une fois !
444
445   TopoDS_Face theface = F;  
446   theface.Orientation(TopAbs_FORWARD);
447   
448 //:S4136  Standard_Real Tol = BRep_Tool::Tolerance(theface);
449   Handle(Geom2d_Curve) c2df,c2dr;
450   Standard_Real uff,ulf,ufr,ulr;
451
452   // d abord FWD puis REV
453   c2df = BRep_Tool::CurveOnSurface (E,theface,uff,ulf);
454   E.Orientation (TopAbs_REVERSED);
455   c2dr = BRep_Tool::CurveOnSurface (E,theface,ufr,ulr);
456   if ( c2df.IsNull() || c2dr.IsNull() ) return; //:q0
457   // On permute
458   E.Orientation (TopAbs_FORWARD);
459   BRep_Builder B;
460   B.UpdateEdge (E,c2dr,c2df,theface,0.); //:S4136: Tol
461   B.Range (E,theface,uff,ulf);
462 }
463
464 void ShapeExtend_WireData::Reverse (const TopoDS_Face &face) 
465 {
466   Reverse();
467   if ( face.IsNull() ) return;
468
469   //  ATTENTION aux coutures
470   //  Une edge de couture est presente deux fois, FWD et REV
471   //  Les inverser revient a permuter leur role ... donc ne rien faire
472   //  Il faut donc aussi permuter leurs pcurves
473   ComputeSeams(Standard_True);
474   if (mySeamF > 0) SwapSeam (myEdges->Value(mySeamF),face);
475   if (mySeamR > 0) SwapSeam (myEdges->Value(mySeamR),face);
476   Standard_Integer nb = (mySeams.IsNull() ? 0 : mySeams->Length());
477   for ( Standard_Integer i = 1; i <= nb; i ++) {
478     SwapSeam (myEdges->Value(mySeams->Value(i)),face);
479   }
480   mySeamF = -1;
481 }
482
483 //=======================================================================
484 //function : NbEdges
485 //purpose  : 
486 //=======================================================================
487
488 Standard_Integer ShapeExtend_WireData::NbEdges() const
489 {
490   return myEdges->Length();
491 }
492
493 //=======================================================================
494 //function : Edge
495 //purpose  : 
496 //=======================================================================
497
498 TopoDS_Edge ShapeExtend_WireData::Edge (const Standard_Integer num) const
499 {
500   if (num < 0) {
501     TopoDS_Edge E = Edge (-num);
502     E.Reverse();
503     return E;
504   }
505   return TopoDS::Edge ( myEdges->Value ( num ) );
506 }
507 //=======================================================================
508 //function : NbNonManifoldEdges
509 //purpose  : 
510 //=======================================================================
511
512 Standard_Integer ShapeExtend_WireData::NbNonManifoldEdges() const
513 {
514   return myNonmanifoldEdges->Length();
515 }
516
517 //=======================================================================
518 //function : Edge
519 //purpose  : 
520 //=======================================================================
521
522 TopoDS_Edge ShapeExtend_WireData::NonmanifoldEdge (const Standard_Integer num) const
523 {
524   TopoDS_Edge E;
525   if (num < 0) 
526     return E;
527   
528   return TopoDS::Edge ( myNonmanifoldEdges->Value ( num ) );
529 }
530 //=======================================================================
531 //function : Index
532 //purpose  : 
533 //=======================================================================
534
535 Standard_Integer ShapeExtend_WireData::Index (const TopoDS_Edge& edge)
536 {
537   for (Standard_Integer i = 1; i <= NbEdges(); i++)
538     if (Edge (i).IsSame (edge) && (Edge(i).Orientation() == edge.Orientation() || !IsSeam(i)))
539       return i;
540   return 0;
541 }
542
543 //=======================================================================
544 //function : IsSeam
545 //purpose  : 
546 //=======================================================================
547
548 Standard_Boolean ShapeExtend_WireData::IsSeam (const Standard_Integer num) 
549 {
550   if (mySeamF < 0) ComputeSeams();
551   if (mySeamF == 0) return Standard_False;
552   
553   if (num == mySeamF || num == mySeamR) return Standard_True;
554 //  Pas suffisant : on regarde dans la liste
555   Standard_Integer i, nb = mySeams->Length();
556   for (i = 1; i <= nb; i ++) {
557     if (num == mySeams->Value(i)) return Standard_True;
558   }
559   return Standard_False;
560 }
561
562 //=======================================================================
563 //function : Make
564 //purpose  : 
565 //=======================================================================
566
567 TopoDS_Wire ShapeExtend_WireData::Wire() const
568 {
569   TopoDS_Wire W;
570   BRep_Builder B;
571   B.MakeWire (W); 
572   Standard_Integer i, nb = NbEdges();
573   Standard_Boolean ismanifold = Standard_True;
574   for (i = 1; i <= nb; i ++) {
575     TopoDS_Edge aE =  Edge(i);
576     if (aE.Orientation() != TopAbs_FORWARD &&
577         aE.Orientation() != TopAbs_REVERSED)
578       ismanifold = Standard_False;
579     B.Add (W, aE);
580   }
581   if(ismanifold) {
582     TopoDS_Vertex vf, vl;
583     TopExp::Vertices (W, vf, vl);
584     if (!vf.IsNull() && !vl.IsNull() && vf.IsSame (vl)) W.Closed (Standard_True);
585   }
586   if(myManifoldMode) {
587     nb = NbNonManifoldEdges();
588     for (i = 1; i <= nb; i ++) B.Add (W, NonmanifoldEdge(i));
589   }
590   return W;
591 }
592
593 //=======================================================================
594 //function : APIMake
595 //purpose  : 
596 //=======================================================================
597
598 TopoDS_Wire ShapeExtend_WireData::WireAPIMake() const
599 {
600   TopoDS_Wire W;
601   BRepBuilderAPI_MakeWire MW;
602   Standard_Integer i, nb = NbEdges();
603   for (i = 1; i <= nb; i ++)  MW.Add (Edge(i));
604   if(myManifoldMode) {
605     nb = NbNonManifoldEdges();
606     for (i = 1; i <= nb; i ++) MW.Add (NonmanifoldEdge(i));
607   }
608   if ( MW.IsDone() ) W = MW.Wire();
609   return W;
610 }
611
612 //=======================================================================
613 //function : NonmanifoldEdges
614 //purpose  : 
615 //=======================================================================
616 Handle(TopTools_HSequenceOfShape) ShapeExtend_WireData::NonmanifoldEdges() const
617 {
618   return myNonmanifoldEdges;
619 }
620
621 //=======================================================================
622 //function : ManifoldMode
623 //purpose  : 
624 //=======================================================================
625 Standard_Boolean&  ShapeExtend_WireData::ManifoldMode()
626 {
627   return myManifoldMode;
628 }