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