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