0023982: Wire explorer raises exception
[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               if(aPEb.SquareDistance(aPEe) <= gp::Resolution())
509               {
510                 //seems to be very short curve
511                 gp_Vec2d aD;
512                 aPCurve->D1(aEPm, aPEe, aD);
513                       if( E.Orientation() == TopAbs_REVERSED )
514                   aPEe.SetXY(aPEb.XY()-aD.XY());
515                       else      
516                   aPEe.SetXY(aPEb.XY()+aD.XY());
517
518                 if(aPEb.SquareDistance(aPEe) <= gp::Resolution())
519                 {
520                   it.Next();
521                   k++;
522                   continue;
523                 }
524               }
525                           gp_Vec2d anEDir(aPEb, aPEe);
526                           dfCurAngle = Abs( anEDir.Angle(anERefDir) );
527                   }
528
529                   if( dfCurAngle <= dfMinAngle )
530                   {
531                           Standard_Real d = PRef.SquareDistance(aPEb);
532                           if( d <= Precision::PConfusion() )
533                             d = 0.;
534                           if( Abs(aPEb.X()-PRef.X()) < myTolU  &&  Abs(aPEb.Y()-PRef.Y()) < myTolV )
535                           {
536                             if( d <= dmin )
537                             {
538                                     dfMinAngle = dfCurAngle;
539                                     kMin = k;
540                                     dmin = d;
541                             }
542                           }
543                   }
544                 }
545                 it.Next();
546                 k++;
547         }// while it
548
549         if( kMin == 0 )
550         {
551                 isDegenerated = Standard_False;
552                 k = 1;
553                 dmin = RealLast();
554         }
555         else
556           break;
557       }// for iDone
558
559       if(kMin == 0)
560       {
561         // probably unclosed in 2d space wire
562         myEdge = TopoDS_Edge();
563         return;
564       }
565
566       // Selection the edge.
567       it.Initialize(l);
568       k = 1;
569       while( it.More() )
570       {
571         if( k == kMin )
572         {
573           myEdge = TopoDS::Edge(it.Value());
574           l.Remove(it);
575           break;
576         }
577         it.Next();
578         k++;
579       }
580     }//else face != NULL && l > 1
581   }//else l > 1
582 }
583
584 //=======================================================================
585 //function : Current
586 //purpose  : 
587 //=======================================================================
588 const TopoDS_Edge&  BRepTools_WireExplorer::Current()const 
589 {
590   return myEdge;
591 }
592
593 //=======================================================================
594 //function : Orientation
595 //purpose  : 
596 //=======================================================================
597 TopAbs_Orientation BRepTools_WireExplorer::Orientation() const
598 {
599   TopoDS_Iterator it(myEdge,Standard_False);
600   while (it.More()) {
601     if (myVertex.IsSame(it.Value()))
602       return it.Value().Orientation();
603     it.Next();
604   }
605   Standard_NoSuchObject::Raise("BRepTools_WireExplorer::Orientation");
606   return TopAbs_FORWARD;
607 }
608
609 //=======================================================================
610 //function : CurrentVertex
611 //purpose  : 
612 //=======================================================================
613 const TopoDS_Vertex& BRepTools_WireExplorer::CurrentVertex() const
614 {
615   return myVertex;
616 }
617
618 //=======================================================================
619 //function : Clear
620 //purpose  : 
621 //=======================================================================
622
623 void BRepTools_WireExplorer::Clear()
624 {
625   myMap.Clear();
626   myDoubles.Clear();
627   myEdge = TopoDS_Edge();
628   myFace = TopoDS_Face();
629   myVertex = TopoDS_Vertex();
630 }
631
632
633 //=======================================================================
634 //function : SelectDouble
635 //purpose  : 
636 //=======================================================================
637
638 Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
639                               TopTools_ListOfShape& L,
640                               TopoDS_Edge&          E)
641 {
642   TopTools_ListIteratorOfListOfShape it(L);
643   
644   for (; it.More(); it.Next()) {
645     const TopoDS_Shape& CE = it.Value();
646     if (Doubles.Contains(CE) && (!E.IsSame(CE))) {
647       E = TopoDS::Edge(CE);
648       L.Remove(it);
649       return 1;
650     }
651   }
652   return 0;
653 }
654
655 //=======================================================================
656 //function : SelectDegenerated
657 //purpose  : 
658 //=======================================================================
659
660 Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
661                                    TopoDS_Edge&          E)
662 {
663   TopTools_ListIteratorOfListOfShape it(L);
664   while (it.More()) {
665     if (!it.Value().IsSame(E)) {
666       E = TopoDS::Edge(it.Value());
667       if (BRep_Tool::Degenerated(E)) {
668         L.Remove(it);
669         return 1;
670       }
671     }
672     it.Next();
673   } 
674   return 0;
675 }
676
677 //=======================================================================
678 //function : GetNextParamOnPC
679 //purpose  : 
680 //=======================================================================
681 Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
682                                const gp_Pnt2d& aPRef,
683                                const Standard_Real& fP,
684                                const Standard_Real& lP,
685                                const Standard_Real& tolU,
686                                const Standard_Real& tolV,
687                                const Standard_Boolean& reverse)
688 {
689   Standard_Real result = ( reverse ) ? fP : lP;
690   Standard_Real dP = Abs( lP - fP ) / 1000.; // was / 16.;
691   if( reverse )
692     {
693       Standard_Real startPar = fP;
694       Standard_Boolean nextPntOnEdge = Standard_False;
695       while( !nextPntOnEdge && startPar < lP )
696         {
697           gp_Pnt2d pnt;
698           startPar += dP;
699           aPC->D0(startPar, pnt);
700           if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
701             continue;
702           else
703             {
704               result = startPar;
705               nextPntOnEdge = Standard_True;
706               break;
707             }
708         }
709       
710       if( !nextPntOnEdge )
711         result = lP;
712
713       if( result > lP )
714         result = lP;
715     }
716   else
717     {
718       Standard_Real startPar = lP;
719       Standard_Boolean nextPntOnEdge = Standard_False;
720       while( !nextPntOnEdge && startPar > fP )
721         {
722           gp_Pnt2d pnt;
723           startPar -= dP;
724           aPC->D0(startPar, pnt);
725           if( Abs( aPRef.X() - pnt.X() ) < tolU && Abs( aPRef.Y() - pnt.Y() ) < tolV )
726             continue;
727           else
728             {
729               result = startPar;
730               nextPntOnEdge = Standard_True;
731               break;
732             }
733         }
734       
735       if( !nextPntOnEdge )
736         result = fP;
737
738       if( result < fP )
739         result = fP;
740     }
741
742   return result;
743 }