Integration of OCCT 6.5.0 from SVN
[occt.git] / src / BRepTools / BRepTools_WireExplorer.cxx
1 // File:        BRepTools_WireExplorer.cxx
2 // Created:     Thu Jan 21 19:09:53 1993
3 // Author:      Remi LEQUETTE
4 //              <rle@phylox>
5
6
7 #include <BRepTools_WireExplorer.ixx>
8 #include <TopExp.hxx>
9 #include <TopoDS.hxx>
10 #include <TopoDS_Iterator.hxx>
11 #include <TopTools_MapOfShape.hxx>
12 #include <TopTools_MapIteratorOfMapOfShape.hxx>
13 #include <TopTools_ListOfShape.hxx>
14 #include <TopTools_ListIteratorOfListOfShape.hxx>
15 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
16 #include <BRep_Tool.hxx>
17 #include <gp_Pnt2d.hxx>
18 #include <Precision.hxx>
19 #include <BRepTools.hxx>
20 #include <Geom2d_Curve.hxx>
21 #include <GeomAdaptor_Surface.hxx>
22 #include <TopExp_Explorer.hxx>
23 #include <Geom_Surface.hxx>
24
25 //=======================================================================
26 // forward declarations of aux functions
27 //=======================================================================
28 static Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
29                                      TopTools_ListOfShape& L,
30                                      TopoDS_Edge&          E);
31
32 static Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
33                                           TopoDS_Edge&          E);
34
35 static Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
36                                       const gp_Pnt2d& aPRef,
37                                       const Standard_Real& fP,
38                                       const Standard_Real& lP,
39                                       const Standard_Real& tolU,
40                                       const Standard_Real& tolV,
41                                       const Standard_Boolean& reverse);
42
43 //=======================================================================
44 //function : BRepTools_WireExplorer
45 //purpose  : 
46 //=======================================================================
47 BRepTools_WireExplorer::BRepTools_WireExplorer() 
48 {
49 }
50
51 //=======================================================================
52 //function : BRepTools_WireExplorer
53 //purpose  : 
54 //=======================================================================
55 BRepTools_WireExplorer::BRepTools_WireExplorer(const TopoDS_Wire& W)
56 {
57   TopoDS_Face F = TopoDS_Face();
58   Init(W,F);
59 }
60
61 //=======================================================================
62 //function : BRepTools_WireExplorer
63 //purpose  : 
64 //=======================================================================
65 BRepTools_WireExplorer::BRepTools_WireExplorer(const TopoDS_Wire& W,
66                                                const TopoDS_Face& F)
67 {
68   Init(W,F);
69 }
70
71 //=======================================================================
72 //function : Init
73 //purpose  : 
74 //=======================================================================
75 void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W)
76 {  
77   TopoDS_Face F = TopoDS_Face();
78   Init(W,F);
79 }
80
81 //=======================================================================
82 //function : Init
83 //purpose  : 
84 //=======================================================================
85 void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
86                                    const TopoDS_Face& F)
87 {
88   myEdge = TopoDS_Edge();
89   myVertex = TopoDS_Vertex();
90   myMap.Clear();
91   myDoubles.Clear();
92
93   if( W.IsNull() )
94     return;
95
96   myFace = F;
97   Standard_Real dfVertToler = 0.;
98   myReverse = Standard_False;
99
100   if (!myFace.IsNull())
101     {
102       BRepTools::Update(myFace);
103       TopLoc_Location aL;  
104       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(myFace, aL);
105       GeomAdaptor_Surface aGAS(aSurf);
106       TopExp_Explorer anExp(W, TopAbs_VERTEX);
107       for(; anExp.More(); anExp.Next())
108         {
109           const TopoDS_Vertex& aV = TopoDS::Vertex(anExp.Current());
110           dfVertToler = Max(BRep_Tool::Tolerance(aV), dfVertToler);
111         }
112       myTolU = 2. * aGAS.UResolution(dfVertToler);
113       myTolV = 2. * aGAS.VResolution(dfVertToler);
114       
115       // uresolution for cone with infinite vmin vmax is too small.
116       if(aGAS.GetType() == GeomAbs_Cone)
117         {
118           Standard_Real u1, u2, v1, v2;
119           BRepTools::UVBounds(myFace, u1, u2, v1, v2);
120           gp_Pnt aP;
121           gp_Vec aD1U, aD1V;
122           aGAS.D1(u1, v1, aP, aD1U, aD1V);
123           Standard_Real tol1, tol2, maxtol = .0005*(u2-u1);
124           Standard_Real a = aD1U.Magnitude();
125
126           if(a <= Precision::Confusion())
127             tol1 = maxtol;
128           else
129             tol1 = Min(maxtol, dfVertToler/a);
130
131           aGAS.D1(u1, v2, aP, aD1U, aD1V);
132           a = aD1U.Magnitude();
133           if(a <= Precision::Confusion())
134             tol2 = maxtol;
135           else
136             tol2 = Min(maxtol, dfVertToler/a);
137
138           myTolU = 2. * Max(tol1, tol2);
139         }
140
141       if( aGAS.GetType() == GeomAbs_BSplineSurface || 
142           aGAS.GetType() == GeomAbs_BezierSurface )
143         {
144           Standard_Real maxTol = Max(myTolU,myTolV);
145           myTolU = maxTol;
146           myTolV = maxTol;
147         }
148
149       myReverse = (myFace.Orientation() == TopAbs_REVERSED);
150     }
151       
152   // map of vertices to know if the wire is open
153   TopTools_MapOfShape vmap;
154   //  Modified by Sergey KHROMOV - Mon May 13 11:50:48 2002 Begin
155   //  map of infinite edges
156   TopTools_MapOfShape anInfEmap;
157   //  Modified by Sergey KHROMOV - Mon May 13 11:50:49 2002 End
158
159   // list the vertices
160   TopoDS_Vertex V1,V2;
161   TopTools_ListOfShape empty;
162
163   TopoDS_Iterator it(W);
164   while (it.More())
165     {
166       const TopoDS_Edge& E = TopoDS::Edge(it.Value());
167       TopAbs_Orientation Eori = E.Orientation();
168       if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL)
169         {
170           it.Next();
171           continue;
172         }
173       TopExp::Vertices(E,V1,V2,Standard_True);
174
175       if( !V1.IsNull() )
176         {
177           if( !myMap.IsBound(V1) )
178             myMap.Bind(V1,empty);
179           myMap(V1).Append(E);
180
181           // add or remove in the vertex map
182           V1.Orientation(TopAbs_FORWARD);
183           if( !vmap.Add(V1) )
184             vmap.Remove(V1);
185         }
186
187       if( !V2.IsNull() )
188         {
189           V2.Orientation(TopAbs_REVERSED);
190           if(!vmap.Add(V2))
191             vmap.Remove(V2);
192         }
193
194       //  Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 Begin
195       if (V1.IsNull() || V2.IsNull())
196         {
197           Standard_Real aF = 0., aL = 0.;
198           BRep_Tool::Range(E, aF, aL);
199           
200           if(Eori == TopAbs_FORWARD)
201             {
202               if (aF == -Precision::Infinite())
203                 anInfEmap.Add(E);
204             }
205           else
206             { // Eori == TopAbs_REVERSED
207               if (aL == Precision::Infinite())
208                 anInfEmap.Add(E);
209             }
210         }
211       //  Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 End
212       it.Next();
213     }
214
215   //Construction de l ensemble des aretes doubles.
216   TopoDS_Iterator it2(W);  
217   TopTools_MapOfShape emap;
218   while (it2.More()) {
219     if (!emap.Add(it2.Value())) 
220       myDoubles.Add(it2.Value());
221     it2.Next();
222   }
223
224   // if vmap is not empty the wire is open, let us find the first vertex
225   if (!vmap.IsEmpty()) {
226     TopTools_MapIteratorOfMapOfShape itt(vmap); // skl : I change "it" to "itt"
227     while (itt.Key().Orientation() != TopAbs_FORWARD) {
228       itt.Next();
229       if (!itt.More()) break;
230     }
231     if (itt.More()) V1 = TopoDS::Vertex(itt.Key());
232   }
233   else {
234 //  Modified by Sergey KHROMOV - Mon May 13 12:05:30 2002 Begin
235 //   The wire is infinite Try to find the first vertex. It may be NULL.
236     if (!anInfEmap.IsEmpty()) {
237       TopTools_MapIteratorOfMapOfShape itt(anInfEmap);
238
239       for (; itt.More(); itt.Next()) {
240         TopoDS_Edge        anEdge = TopoDS::Edge(itt.Key());
241         TopAbs_Orientation anOri  = anEdge.Orientation();
242         Standard_Real      aF;
243         Standard_Real      aL;
244
245         BRep_Tool::Range(anEdge, aF, aL);
246         if ((anOri == TopAbs_FORWARD  && aF == -Precision::Infinite()) ||
247             (anOri == TopAbs_REVERSED && aL ==  Precision::Infinite())) {
248           myEdge   = anEdge;
249           myVertex = TopoDS_Vertex();
250
251           return;
252         }
253       }
254     }
255 //  Modified by Sergey KHROMOV - Mon May 13 12:05:31 2002 End
256
257
258     // use the first vertex in iterator
259     it.Initialize(W);
260     while (it.More()) {
261       const TopoDS_Edge& E = TopoDS::Edge(it.Value());
262       TopAbs_Orientation Eori = E.Orientation();
263       if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL) {
264         // JYL 10-03-97 : en attendant un traitement correct 
265         // des aretes INTERNAL/EXTERNAL
266         it.Next();
267         continue;
268       }
269       TopExp::Vertices(E,V1,V2,Standard_True);
270       break;
271     }
272   }
273
274   if (V1.IsNull() ) return;
275   if (!myMap.IsBound(V1)) return;
276   
277   TopTools_ListOfShape& l = myMap(V1);
278   myEdge = TopoDS::Edge(l.First());
279   l.RemoveFirst();
280   myVertex = TopExp::FirstVertex (myEdge, Standard_True);
281
282 }
283
284 //=======================================================================
285 //function : More
286 //purpose  : 
287 //=======================================================================
288 Standard_Boolean  BRepTools_WireExplorer::More()const 
289 {
290   return !myEdge.IsNull();
291 }
292
293 //=======================================================================
294 //function : Next
295 //purpose  : 
296 //=======================================================================
297 void  BRepTools_WireExplorer::Next()
298 {
299   myVertex = TopExp::LastVertex (myEdge, Standard_True);
300
301   if (myVertex.IsNull()) {
302      myEdge = TopoDS_Edge();
303      return;
304   }
305   if (!myMap.IsBound(myVertex)) {
306      myEdge = TopoDS_Edge();
307      return;
308   }
309
310   TopTools_ListOfShape& l = myMap(myVertex);
311
312   if (l.IsEmpty()) {
313     myEdge = TopoDS_Edge();
314   }
315   else if (l.Extent() == 1) {
316 //  Modified by Sergey KHROMOV - Fri Jun 21 10:28:01 2002 OCC325 Begin
317     TopoDS_Vertex aV1;
318     TopoDS_Vertex aV2;
319     TopoDS_Edge   aNextEdge = TopoDS::Edge(l.First());
320
321     TopExp::Vertices(aNextEdge, aV1, aV2, Standard_True);
322
323     if (!aV1.IsSame(myVertex)) {
324       myEdge = TopoDS_Edge();
325       return;
326     }
327     if (!myFace.IsNull() && aV1.IsSame(aV2)) {
328       Handle(Geom2d_Curve) aPrevPC;
329       Handle(Geom2d_Curve) aNextPC;
330       Standard_Real        aPar11, aPar12;
331       Standard_Real        aPar21, aPar22;
332       Standard_Real        aPrevPar;
333       Standard_Real        aNextFPar;
334       Standard_Real        aNextLPar;
335
336       aPrevPC = BRep_Tool::CurveOnSurface(myEdge, myFace, aPar11, aPar12);
337       aNextPC = BRep_Tool::CurveOnSurface(aNextEdge, myFace, aPar21, aPar22);
338
339       if (aPrevPC.IsNull() || aNextPC.IsNull()) {
340         myEdge = TopoDS_Edge();
341         return;
342       }
343
344       if (myEdge.Orientation() == TopAbs_FORWARD)
345         aPrevPar = aPar12;
346       else
347         aPrevPar = aPar11;
348
349       if (aNextEdge.Orientation() == TopAbs_FORWARD) {
350         aNextFPar = aPar21;
351         aNextLPar = aPar22;
352       } else {
353         aNextFPar = aPar22;
354         aNextLPar = aPar21;
355       }
356
357       gp_Pnt2d aPPrev  = aPrevPC->Value(aPrevPar);
358       gp_Pnt2d aPNextF = aNextPC->Value(aNextFPar);
359       gp_Pnt2d aPNextL = aNextPC->Value(aNextLPar);
360
361       if (aPPrev.SquareDistance(aPNextF) > aPPrev.SquareDistance(aPNextL)) {
362         myEdge = TopoDS_Edge();
363         return;
364       }
365     }
366 //  Modified by Sergey KHROMOV - Fri Jun 21 11:08:16 2002 End
367     myEdge = TopoDS::Edge(l.First());
368     l.Clear();
369   }
370   else {
371     if (myFace.IsNull()) {
372       // Sans la Face On essait qd meme de renvoyer les aretes
373       // le plus logiquement possible
374       // En premier choix les aretes degenerees.
375       TopoDS_Edge E = myEdge;
376       if (SelectDegenerated(l,E)) {
377         myEdge = E;
378         return;
379       }
380       // En deuxieme choix les aretes doubles.
381       E = myEdge;
382       if (SelectDouble(myDoubles,l,E)) {
383         myEdge = E;
384         return;
385       }
386
387       TopTools_ListIteratorOfListOfShape it(l); 
388       Standard_Boolean notfound = Standard_True;
389       while (it.More()) {
390         if (!it.Value().IsSame(myEdge)) {
391           myEdge = TopoDS::Edge(it.Value());
392           l.Remove(it);
393           notfound = Standard_False;
394           break;
395         }
396         it.Next();
397       }
398       
399       if(notfound) {
400         myEdge = TopoDS_Edge();
401         return;
402       }
403
404     }
405     else
406       {
407         // If we have more than one edge attached to the list
408         // probably wire that we explore contains a loop or loops.
409         Standard_Real dfFPar = 0., dfLPar = 0.;
410         Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (myEdge, myFace, dfFPar, dfLPar);
411         if(aPCurve.IsNull())
412           {
413             myEdge = TopoDS_Edge();
414             return;
415           }
416         // Note: current < myVertex > which is last on < myEdge >
417         //       equals in 2D to following 2D points:
418         //       edge is FORWARD  - point with MAX parameter on PCurve;
419         //       edge is REVERSED - point with MIN parameter on PCurve.
420
421         // Get 2D point equals to < myVertex > in 2D for current edge.
422         gp_Pnt2d PRef;
423         if( myEdge.Orientation() == TopAbs_REVERSED )
424           aPCurve->D0(dfFPar, PRef);
425         else 
426           aPCurve->D0(dfLPar, PRef);
427
428         // Get next 2D point from current edge's PCurve with parameter
429         // F + dP (REV) or L - dP (FOR)
430         Standard_Boolean isrevese = ( myEdge.Orientation() == TopAbs_REVERSED );
431         Standard_Real dfMPar = GetNextParamOnPC(aPCurve,PRef,dfFPar,dfLPar,myTolU,myTolV,isrevese);
432
433         gp_Pnt2d PRefm;
434         aPCurve->D0(dfMPar, PRefm);
435         // Get vector from PRef to PRefm
436         gp_Vec2d anERefDir(PRef,PRefm);
437         // Search the list of edges looking for the edge having hearest
438         // 2D point of connected vertex to current one and smallest angle.
439         // First process all degenerated edges, then - all others.
440
441         TopTools_ListIteratorOfListOfShape it;
442         Standard_Integer k = 1, kMin = 0, iDone = 0;
443         Standard_Boolean isDegenerated = Standard_True;
444         Standard_Real dmin = RealLast();
445         Standard_Real dfMinAngle = 3.0*PI, dfCurAngle = 3.0*PI;
446
447         for(iDone = 0; iDone < 2; iDone++)
448           {
449             it.Initialize(l);
450             while( it.More() )
451               {
452                 const TopoDS_Edge& E = TopoDS::Edge(it.Value());
453                 if( E.IsSame(myEdge) )
454                   {
455                     it.Next();
456                     k++;
457                     continue;
458                   }
459                 
460                 TopoDS_Vertex aVert1, aVert2;
461                 TopExp::Vertices (E, aVert1, aVert2, Standard_True);
462                 if( aVert1.IsNull() || aVert2.IsNull() )
463                   {
464                     it.Next();
465                     k++;
466                     continue;
467                   }
468                 
469                 aPCurve = BRep_Tool::CurveOnSurface (E, myFace, dfFPar, dfLPar);
470                 if( aPCurve.IsNull() )
471                   {
472                     it.Next();
473                     k++;
474                     continue;
475                   }
476                 
477                 gp_Pnt2d aPEb, aPEe;
478                 if( aVert1.IsSame(aVert2) == isDegenerated )
479                   {
480                     if( E.Orientation() == TopAbs_REVERSED )
481                       aPCurve->D0(dfLPar, aPEb);
482                     else        
483                       aPCurve->D0(dfFPar, aPEb);
484
485                     if( Abs(dfLPar-dfFPar) > Precision::PConfusion() )
486                       {
487                         isrevese = ( E.Orientation() == TopAbs_REVERSED );
488                         isrevese = !isrevese;
489                         Standard_Real aEPm = GetNextParamOnPC(aPCurve,aPEb,dfFPar,dfLPar,myTolU,myTolV,isrevese);
490                         
491                         aPCurve->D0 (aEPm, aPEe);
492                         gp_Vec2d anEDir(aPEb, aPEe);
493                         dfCurAngle = Abs( anEDir.Angle(anERefDir) );
494                       }
495
496                     if( dfCurAngle <= dfMinAngle )
497                       {
498                         Standard_Real d = PRef.SquareDistance(aPEb);
499                         if( d <= Precision::PConfusion() )
500                           d = 0.;
501                         if( Abs(aPEb.X()-PRef.X()) < myTolU  &&  Abs(aPEb.Y()-PRef.Y()) < myTolV )
502                           {
503                             if( d <= dmin )
504                               {
505                                 dfMinAngle = dfCurAngle;
506                                 kMin = k;
507                                 dmin = d;
508                               }
509                           }
510                       }
511                   }
512                 it.Next();
513                 k++;
514               }// while it
515
516             if( kMin == 0 )
517               {
518                 isDegenerated = Standard_False;
519                 k = 1;
520                 dmin = RealLast();
521               }
522             else
523               break;
524           }// for iDone
525
526         if(kMin == 0)
527           {
528             // probably unclosed in 2d space wire
529             myEdge = TopoDS_Edge();
530             return;
531           }
532
533         // Selection the edge.
534         it.Initialize(l);
535         k = 1;
536         while( it.More() )
537           {
538             if( k == kMin )
539               {
540                 myEdge = TopoDS::Edge(it.Value());
541                 l.Remove(it);
542                 break;
543               }
544             it.Next();
545             k++;
546           }
547       }//else face != NULL && l > 1
548   }//else l > 1
549 }
550
551 //=======================================================================
552 //function : Current
553 //purpose  : 
554 //=======================================================================
555 const TopoDS_Edge&  BRepTools_WireExplorer::Current()const 
556 {
557   return myEdge;
558 }
559
560 //=======================================================================
561 //function : Orientation
562 //purpose  : 
563 //=======================================================================
564 TopAbs_Orientation BRepTools_WireExplorer::Orientation() const
565 {
566   TopoDS_Iterator it(myEdge,Standard_False);
567   while (it.More()) {
568     if (myVertex.IsSame(it.Value()))
569       return it.Value().Orientation();
570     it.Next();
571   }
572   Standard_NoSuchObject::Raise("BRepTools_WireExplorer::Orientation");
573   return TopAbs_FORWARD;
574 }
575
576 //=======================================================================
577 //function : CurrentVertex
578 //purpose  : 
579 //=======================================================================
580 const TopoDS_Vertex& BRepTools_WireExplorer::CurrentVertex() const
581 {
582   return myVertex;
583 }
584
585 //=======================================================================
586 //function : Clear
587 //purpose  : 
588 //=======================================================================
589
590 void BRepTools_WireExplorer::Clear()
591 {
592   myMap.Clear();
593   myDoubles.Clear();
594   myEdge = TopoDS_Edge();
595   myFace = TopoDS_Face();
596   myVertex = TopoDS_Vertex();
597 }
598
599
600 //=======================================================================
601 //function : SelectDouble
602 //purpose  : 
603 //=======================================================================
604
605 Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
606                               TopTools_ListOfShape& L,
607                               TopoDS_Edge&          E)
608 {
609   TopTools_ListIteratorOfListOfShape it(L);
610   
611   for (; it.More(); it.Next()) {
612     const TopoDS_Shape& CE = it.Value();
613     if (Doubles.Contains(CE) && (!E.IsSame(CE))) {
614       E = TopoDS::Edge(CE);
615       L.Remove(it);
616       return 1;
617     }
618   }
619   return 0;
620 }
621
622 //=======================================================================
623 //function : SelectDegenerated
624 //purpose  : 
625 //=======================================================================
626
627 Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
628                                    TopoDS_Edge&          E)
629 {
630   TopTools_ListIteratorOfListOfShape it(L);
631   while (it.More()) {
632     if (!it.Value().IsSame(E)) {
633       E = TopoDS::Edge(it.Value());
634       if (BRep_Tool::Degenerated(E)) {
635         L.Remove(it);
636         return 1;
637       }
638     }
639     it.Next();
640   } 
641   return 0;
642 }
643
644 //=======================================================================
645 //function : GetNextParamOnPC
646 //purpose  : 
647 //=======================================================================
648 Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
649                                const gp_Pnt2d& aPRef,
650                                const Standard_Real& fP,
651                                const Standard_Real& lP,
652                                const Standard_Real& tolU,
653                                const Standard_Real& tolV,
654                                const Standard_Boolean& reverse)
655 {
656   Standard_Real result = ( reverse ) ? fP : lP;
657   Standard_Real dP = Abs( lP - fP ) / 1000.; // was / 16.;
658   if( reverse )
659     {
660       Standard_Real startPar = fP;
661       Standard_Boolean nextPntOnEdge = Standard_False;
662       while( !nextPntOnEdge && startPar < lP )
663         {
664           gp_Pnt2d pnt;
665           startPar += dP;
666           aPC->D0(startPar, pnt);
667           if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
668             continue;
669           else
670             {
671               result = startPar;
672               nextPntOnEdge = Standard_True;
673               break;
674             }
675         }
676       
677       if( !nextPntOnEdge )
678         result = lP;
679
680       if( result > lP )
681         result = lP;
682     }
683   else
684     {
685       Standard_Real startPar = lP;
686       Standard_Boolean nextPntOnEdge = Standard_False;
687       while( !nextPntOnEdge && startPar > fP )
688         {
689           gp_Pnt2d pnt;
690           startPar -= dP;
691           aPC->D0(startPar, pnt);
692           if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
693             continue;
694           else
695             {
696               result = startPar;
697               nextPntOnEdge = Standard_True;
698               break;
699             }
700         }
701       
702       if( !nextPntOnEdge )
703         result = fP;
704
705       if( result < fP )
706         result = fP;
707     }
708
709   return result;
710 }