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