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