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