0023982: Wire explorer raises exception
[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
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
7fd59977 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//=======================================================================
44static Standard_Boolean SelectDouble(TopTools_MapOfShape& Doubles,
45 TopTools_ListOfShape& L,
46 TopoDS_Edge& E);
47
48static Standard_Boolean SelectDegenerated(TopTools_ListOfShape& L,
49 TopoDS_Edge& E);
50
51static 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//=======================================================================
63BRepTools_WireExplorer::BRepTools_WireExplorer()
64{
65}
66
67//=======================================================================
68//function : BRepTools_WireExplorer
69//purpose :
70//=======================================================================
71BRepTools_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//=======================================================================
81BRepTools_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//=======================================================================
91void 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//=======================================================================
101void 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
0d969553 231 //Construction of the set of double edges.
7fd59977 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) {
0d969553
Y
280 // JYL 10-03-97 : waiting for correct processing
281 // of INTERNAL/EXTERNAL edges
7fd59977 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//=======================================================================
304Standard_Boolean BRepTools_WireExplorer::More()const
305{
306 return !myEdge.IsNull();
307}
308
309//=======================================================================
310//function : Next
311//purpose :
312//=======================================================================
313void 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()) {
a0f8845f 356 myEdge = TopoDS_Edge();
357 return;
7fd59977 358 }
359
360 if (myEdge.Orientation() == TopAbs_FORWARD)
a0f8845f 361 aPrevPar = aPar12;
7fd59977 362 else
a0f8845f 363 aPrevPar = aPar11;
7fd59977 364
365 if (aNextEdge.Orientation() == TopAbs_FORWARD) {
a0f8845f 366 aNextFPar = aPar21;
367 aNextLPar = aPar22;
7fd59977 368 } else {
a0f8845f 369 aNextFPar = aPar22;
370 aNextLPar = aPar21;
7fd59977 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)) {
a0f8845f 378 myEdge = TopoDS_Edge();
379 return;
7fd59977 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()) {
0d969553
Y
388 // Without Face - try to return edges
389 // as logically as possible
390 // At first degenerated edges.
7fd59977 391 TopoDS_Edge E = myEdge;
392 if (SelectDegenerated(l,E)) {
a0f8845f 393 myEdge = E;
394 return;
7fd59977 395 }
0d969553 396 // At second double edges.
7fd59977 397 E = myEdge;
398 if (SelectDouble(myDoubles,l,E)) {
a0f8845f 399 myEdge = E;
400 return;
7fd59977 401 }
402
403 TopTools_ListIteratorOfListOfShape it(l);
404 Standard_Boolean notfound = Standard_True;
405 while (it.More()) {
a0f8845f 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();
7fd59977 413 }
414
415 if(notfound) {
a0f8845f 416 myEdge = TopoDS_Edge();
417 return;
7fd59977 418 }
419
420 }
421 else
a0f8845f 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())
7fd59977 428 {
a0f8845f 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
7fd59977 581 }//else l > 1
582}
583
584//=======================================================================
585//function : Current
586//purpose :
587//=======================================================================
588const TopoDS_Edge& BRepTools_WireExplorer::Current()const
589{
590 return myEdge;
591}
592
593//=======================================================================
594//function : Orientation
595//purpose :
596//=======================================================================
597TopAbs_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//=======================================================================
613const TopoDS_Vertex& BRepTools_WireExplorer::CurrentVertex() const
614{
615 return myVertex;
616}
617
618//=======================================================================
619//function : Clear
620//purpose :
621//=======================================================================
622
623void 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
638Standard_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
660Standard_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//=======================================================================
681Standard_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}