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