0028694: IGES reader produces too small edge covered by its vertices
[occt.git] / src / ShapeFix / ShapeFix_Wire_1.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 // szv 19.08.99: new methods for fixing gaps between edges (3d curves and pcurves)
15 #include <ShapeFix_Wire.hxx>
16 #include <Standard_ErrorHandler.hxx>
17 #include <Standard_Failure.hxx>
18
19 #include <Precision.hxx>
20 #include <Bnd_Box2d.hxx>
21 #include <Geom_Curve.hxx>
22 #include <Geom2d_Curve.hxx>
23 #include <Geom2d_Line.hxx>
24
25 #include <IntRes2d_SequenceOfIntersectionPoint.hxx>
26 #include <IntRes2d_IntersectionPoint.hxx>
27 #include <TColgp_SequenceOfPnt.hxx>
28
29 #include <TopoDS.hxx>
30 #include <TopoDS_Vertex.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopTools_HSequenceOfShape.hxx>
33
34 #include <BRep_Tool.hxx>
35 #include <BRep_Builder.hxx>
36
37 #include <ShapeExtend.hxx>
38 #include <ShapeBuild_Edge.hxx>
39 #include <ShapeBuild_Vertex.hxx>
40 #include <ShapeAnalysis_Curve.hxx>
41 #include <ShapeAnalysis_Edge.hxx>
42 #include <ShapeAnalysis_Surface.hxx>
43 #include <ShapeAnalysis.hxx>
44 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
45 #include <Geom_TrimmedCurve.hxx>
46 #include <gp_Pln.hxx>
47 #include <GeomAPI.hxx>
48 #include <TColgp_Array1OfPnt.hxx>
49 #include <TColStd_Array1OfReal.hxx>
50 #include <TColStd_Array1OfInteger.hxx>
51 #include <Geom_BSplineCurve.hxx>
52 #include <Geom_SphericalSurface.hxx> //S4135
53 #include <Geom2d_BSplineCurve.hxx>
54 #include <GeomAdaptor_Curve.hxx>
55 #include <GeomAdaptor_HSurface.hxx>
56 #include <GeomAdaptor_Surface.hxx>  
57 #include <TopTools_Array1OfShape.hxx>
58 #include <BRepTools.hxx>
59 #include <Bnd_Array1OfBox2d.hxx>
60 #include <BndLib_Add2dCurve.hxx>
61 #include <Geom2dAdaptor_Curve.hxx>
62 #include <Geom2dConvert.hxx>
63 #include <Geom2d_TrimmedCurve.hxx>
64 #include <ShapeBuild_ReShape.hxx>
65
66 //szv
67 #include <TColgp_Array1OfPnt2d.hxx>
68 #include <Geom2d_Circle.hxx>
69 #include <Geom2d_Ellipse.hxx>
70 #include <Geom2d_Parabola.hxx>
71 #include <Geom2d_Hyperbola.hxx>
72 #include <Geom2d_OffsetCurve.hxx>
73 #include <Geom2dInt_GInter.hxx>
74 #include <IntRes2d_Domain.hxx>
75 #include <IntRes2d_IntersectionSegment.hxx>
76 #include <Geom2dAPI_ExtremaCurveCurve.hxx>
77 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
78 #include <Geom2dAdaptor_HCurve.hxx>
79 #include <Approx_Curve2d.hxx>
80 #include <Geom2dConvert.hxx>
81
82 #include <Geom_Line.hxx>
83 #include <Geom_Circle.hxx>
84 #include <Geom_Ellipse.hxx>
85 #include <Geom_Parabola.hxx>
86 #include <Geom_Hyperbola.hxx>
87 #include <Geom_OffsetCurve.hxx>
88 #include <GeomAPI_ExtremaCurveCurve.hxx>
89 #include <GeomAPI_ProjectPointOnCurve.hxx>
90 #include <GeomAdaptor_HCurve.hxx>
91 #include <Approx_Curve3d.hxx>
92 #include <GeomConvert.hxx>
93 #include <TopoDS_Iterator.hxx>
94 #include <ShapeFix_ShapeTolerance.hxx>
95 #include <ShapeAnalysis_TransferParametersProj.hxx>
96 #include <Geom_Conic.hxx>
97 #include <Geom_BezierCurve.hxx>
98 #include <Geom2d_Conic.hxx>
99 #include <Geom2d_BezierCurve.hxx>
100 //=======================================================================
101 //function : FixGaps3d
102 //purpose  : 
103 //=======================================================================
104
105 Standard_Boolean ShapeFix_Wire::FixGaps3d ()
106 {
107   myStatusGaps3d = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
108 // if ( !IsReady() ) return Standard_False;
109   
110   Standard_Integer i, start = ( myClosedMode ? 1 : 2 );
111   if (myFixGapsByRanges) 
112   {
113     for ( i = start; i <= NbEdges(); i++ ) 
114     {
115       FixGap3d ( i );
116       myStatusGaps3d |= myLastFixStatus;
117     }
118   }
119   for ( i = start; i <= NbEdges(); i++ ) 
120   {
121     FixGap3d ( i, Standard_True );
122     myStatusGaps3d |= myLastFixStatus;
123   }
124
125   return StatusGaps3d ( ShapeExtend_DONE );
126 }
127
128 //=======================================================================
129 //function : FixGaps2d
130 //purpose  : 
131 //=======================================================================
132
133  Standard_Boolean ShapeFix_Wire::FixGaps2d ()
134 {
135   myStatusGaps2d = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
136 //  if ( !IsReady() ) return Standard_False;
137
138   Standard_Integer i, start = ( myClosedMode ? 1 : 2 );
139   if (myFixGapsByRanges) 
140   {
141     for ( i = start; i <= NbEdges(); i++ ) 
142     {
143       FixGap2d ( i );
144       myStatusGaps2d |= myLastFixStatus;
145     }
146   }
147   for ( i = start; i <= NbEdges(); i++ ) 
148   {
149     FixGap2d ( i, Standard_True );
150     myStatusGaps2d |= myLastFixStatus;
151   }
152
153   return StatusGaps2d ( ShapeExtend_DONE );
154 }
155
156 //=======================================================================
157 //function : FixGap3d
158 //purpose  : 
159 //=======================================================================
160
161 static Standard_Real AdjustOnPeriodic3d (const Handle(Geom_Curve)& c,
162                                          const Standard_Boolean takefirst,
163                                          const Standard_Real first,
164                                          const Standard_Real last,
165                                          const Standard_Real param)
166 {
167   // 15.11.2002 PTV OCC966
168   if (ShapeAnalysis_Curve::IsPeriodic(c)) 
169   {
170     Standard_Real T = c->Period();
171     Standard_Real shift = -IntegerPart(first/T)*T; if (first<0.) shift += T;
172     Standard_Real sfirst = first+shift, slast = last+shift;
173     if ( takefirst && (param>slast) && (param>sfirst)) return param-T-shift;
174     if (!takefirst && (param<slast) && (param<sfirst)) return param+T-shift;
175   }
176   return param;
177 }
178
179  Standard_Boolean ShapeFix_Wire::FixGap3d (const Standard_Integer num,
180                                            const Standard_Boolean convert)
181 {
182   myLastFixStatus = ShapeExtend::EncodeStatus( ShapeExtend_OK );
183 //  if ( !IsReady() ) return Standard_False;
184
185   //=============
186   // First phase: analysis whether the problem (gap) exists
187   //=============
188
189   if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);
190
191   Standard_Real preci = Precision();
192
193   Handle(ShapeExtend_WireData) sbwd = WireData();
194   Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
195   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
196 //smh#8
197   TopoDS_Shape tmp1 = Context()->Apply(sbwd->Edge(n1)),
198                tmp2 = Context()->Apply(sbwd->Edge(n2));
199   TopoDS_Edge E1 = TopoDS::Edge(tmp1),
200               E2 = TopoDS::Edge(tmp2);
201 //  TopoDS_Face face = myAnalyzer->Face(); // comment by enk 
202
203   // Retrieve curves on edges
204   Standard_Real cfirst1, clast1, cfirst2, clast2;
205   Handle(Geom_Curve) C1, C2;
206   ShapeAnalysis_Edge SAE;
207   if (!SAE.Curve3d(E1,C1,cfirst1,clast1) ||
208       !SAE.Curve3d(E2,C2,cfirst2,clast2)) 
209   {
210     myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
211     return Standard_False;
212   }
213   
214   // Check gap in 3d space
215   gp_Pnt cpnt1 = C1->Value(clast1), cpnt2 = C2->Value(cfirst2);
216   Standard_Real gap = cpnt1.Distance(cpnt2);
217   if (!convert && gap<=preci) return Standard_False;
218     
219   //=============
220   // Second phase: collecting data necessary for further analysis
221   //=============
222
223   Standard_Boolean reversed1 = (E1.Orientation()==TopAbs_REVERSED),
224                    reversed2 = (E2.Orientation()==TopAbs_REVERSED);
225
226   TopoDS_Vertex V1 = SAE.LastVertex(E1), V2 = SAE.FirstVertex(E2);
227   gp_Pnt vpnt = (V1.IsSame(V2))? BRep_Tool::Pnt(V1) :
228     gp_Pnt((BRep_Tool::Pnt(V1).XYZ()+BRep_Tool::Pnt(V2).XYZ())*0.5);
229
230   Standard_Real first1, last1, first2, last2;
231   if (reversed1) 
232   { 
233     first1 = clast1;  last1 = cfirst1; 
234   }
235   else           
236   { 
237     first1 = cfirst1; last1 = clast1;  
238   }
239   if (reversed2) 
240   { 
241     first2 = clast2;  last2 = cfirst2; 
242   }
243   else           
244   { 
245     first2 = cfirst2; last2 = clast2;  
246   }
247
248   Handle(Geom_Curve) c1 = C1, c2 = C2;
249
250   // Extract basic curves from trimmed and offset
251   Standard_Boolean basic = Standard_False;
252   Standard_Boolean trimmed1 = Standard_False, offset1 = Standard_False;
253   gp_XYZ offval1(0.,0.,0.);
254   while (!basic) 
255   {
256     if (c1->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) 
257     {
258       c1 = Handle(Geom_TrimmedCurve)::DownCast(c1)->BasisCurve();
259       trimmed1 = Standard_True;
260     }
261     else if (c1->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) 
262     {
263       Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c1);
264       c1 = oc->BasisCurve();
265       offval1 += oc->Offset()*oc->Direction().XYZ();
266       offset1 = Standard_True;
267     }
268     else basic = Standard_True;
269   }
270   basic = Standard_False;
271   Standard_Boolean trimmed2 = Standard_False, offset2 = Standard_False;
272   gp_XYZ offval2(0.,0.,0.);
273   while (!basic) 
274   {
275     if (c2->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) 
276     {
277       c2 = Handle(Geom_TrimmedCurve)::DownCast(c2)->BasisCurve();
278       trimmed2 = Standard_True;
279     }
280     else if (c2->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) 
281     {
282       Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c2);
283       c2 = oc->BasisCurve();
284       offval2 += oc->Offset()*oc->Direction().XYZ();
285       offset2 = Standard_True;
286     }
287     else basic = Standard_True;
288   }
289   // Restore offset curves
290   if (offset1) c1 = new Geom_OffsetCurve(c1,offval1.Modulus(),gp_Dir(offval1));
291   if (offset2) c2 = new Geom_OffsetCurve(c2,offval2.Modulus(),gp_Dir(offval2));
292
293   Standard_Boolean done1 = Standard_False, done2 = Standard_False;
294
295   if (convert) 
296   {
297     // Check that gap satisfies the precision - in this case no convertation produced
298     if (cpnt1.Distance(vpnt) < preci && cpnt2.Distance(vpnt) < preci)
299       return Standard_False;
300
301     Handle(Geom_BSplineCurve) bsp1, bsp2;
302     Handle(Geom_Curve) c;
303     Standard_Real first, last;
304
305     // iterate on curves
306     Standard_Integer nbcurv = (n1==n2? 1 : 2);
307     for (Standard_Integer j=1; j<=nbcurv; j++) 
308     {
309       //Standard_Boolean trim = Standard_False;  // skl
310       if (j==1) 
311       {
312         if (cpnt1.Distance(vpnt)<preci) 
313         {
314           if (n1==n2) 
315           { 
316             if (cpnt2.Distance(vpnt)<preci) continue; 
317           }
318           else continue;
319         }
320         c = c1; first = first1; last = last1; /*trim = trimmed1;*/ // skl
321       }
322       else 
323       {
324         if (cpnt2.Distance(vpnt)<preci) continue;
325         c = c2; first = first2; last = last2; /*trim = trimmed2;*/ // skl
326       }
327
328       Handle(Geom_BSplineCurve) bsp;
329
330       // Convert curve to bspline
331       if (c->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) 
332       {
333         bsp = Handle(Geom_BSplineCurve)::DownCast(c->Copy());
334         // take segment if trim and range differ
335         Standard_Real fbsp = bsp->FirstParameter(), lbsp = bsp->LastParameter();
336         Standard_Boolean segment = Standard_False;
337         if (first>fbsp) 
338         { 
339           fbsp = first; segment = Standard_True; 
340         }
341         if (last<lbsp) 
342         { 
343           lbsp = last; segment = Standard_True; 
344         }
345         if (segment)
346           bsp = GeomConvert::SplitBSplineCurve(bsp,fbsp,lbsp,
347                                                ::Precision::Confusion());
348       }
349       else if (c->IsKind(STANDARD_TYPE(Geom_Conic))) 
350       {
351         Approx_Curve3d Conv(new GeomAdaptor_HCurve(c,first,last),
352                             myAnalyzer->Precision(),GeomAbs_C1,9,1000);
353         if (Conv.IsDone() || Conv.HasResult()) bsp = Conv.Curve();
354       }
355       else 
356       {
357         // Restore trim for pcurve
358         Handle(Geom_Curve) tc ;     
359         try 
360         {
361           OCC_CATCH_SIGNALS
362           // 15.11.2002 PTV OCC966
363           if(!ShapeAnalysis_Curve::IsPeriodic(c))
364             tc = new Geom_TrimmedCurve(c,Max(first,c->FirstParameter()),Min(last,c->LastParameter()));
365           else tc = new Geom_TrimmedCurve(c,first,last);
366           bsp = GeomConvert::CurveToBSplineCurve(tc);
367         }
368         catch (Standard_Failure const& anException) {
369 #ifdef OCCT_DEBUG
370           cout << "Warning: ShapeFix_Wire_1::FixGap3d: Exception in TrimmedCurve" <<first<<" " <<last<<endl;
371           anException.Print(cout); cout << endl; 
372 #endif  
373           (void)anException;
374         }
375       }
376
377       if (j==1) bsp1 = bsp; else bsp2 = bsp;
378     }
379     
380     // Take curves ends if could not convert
381     if (bsp1.IsNull()) vpnt = cpnt1;
382     else if (bsp2.IsNull()) vpnt = cpnt2;
383
384     if (!bsp1.IsNull()) 
385     {
386       if(bsp1->Degree() == 1) bsp1->IncreaseDegree(2); //gka
387       if (n1==n2) 
388       { 
389         bsp1->SetPole(1,vpnt); bsp1->SetPole(bsp1->NbPoles(),vpnt); 
390       }
391       else 
392       {
393         if (reversed1) bsp1->SetPole(1,vpnt);
394         else bsp1->SetPole(bsp1->NbPoles(),vpnt);
395       }
396       first1 = bsp1->FirstParameter(); last1 = bsp1->LastParameter();
397       c1 = bsp1;
398       done1 = Standard_True;
399     }
400     if (!bsp2.IsNull()) 
401     {
402       if(bsp2->Degree() == 1) bsp2->IncreaseDegree(2); //gka
403       if (reversed2) bsp2->SetPole(bsp2->NbPoles(),vpnt);
404       else bsp2->SetPole(1,vpnt);
405       first2 = bsp2->FirstParameter(); last2 = bsp2->LastParameter();
406       c2 = bsp2;
407       done2 = Standard_True;
408     }
409   }
410   else 
411   {
412
413     if (n1==n2) 
414     {
415       if (c1->IsKind(STANDARD_TYPE(Geom_Circle)) ||
416           c1->IsKind(STANDARD_TYPE(Geom_Ellipse))) 
417       {
418         Standard_Real diff = M_PI - Abs(clast1-cfirst2)*0.5;
419         first1 -= diff; last1 += diff;
420         done1 = Standard_True;
421       }
422     }
423     else 
424     {
425
426       // Determine domains for extremal points locating
427       Standard_Real domfirst1 = first1, domlast1 = last1;
428       if (c1->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
429           c1->IsKind(STANDARD_TYPE(Geom_BezierCurve))) 
430       {
431         domfirst1 = c1->FirstParameter();
432         domlast1  = c1->LastParameter();
433       }
434       else if (c1->IsKind(STANDARD_TYPE(Geom_Line)) ||
435                c1->IsKind(STANDARD_TYPE(Geom_Parabola)) ||
436                c1->IsKind(STANDARD_TYPE(Geom_Hyperbola))) 
437       {
438         Standard_Real diff = domlast1 - domfirst1;
439         if (reversed1) domfirst1 -= 10.*diff;
440         else           domlast1 += 10.*diff;
441       }
442       else if (c1->IsKind(STANDARD_TYPE(Geom_Circle)) ||
443                c1->IsKind(STANDARD_TYPE(Geom_Ellipse))) 
444       {
445         domfirst1 = 0.; domlast1 = 2*M_PI;
446       }
447       Standard_Real domfirst2 = first2, domlast2 = last2;
448       if (c2->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
449           c2->IsKind(STANDARD_TYPE(Geom_BezierCurve))) 
450       {
451         domfirst2 = c2->FirstParameter();
452         domlast2  = c2->LastParameter();
453       }
454       else if (c2->IsKind(STANDARD_TYPE(Geom_Line)) ||
455                c2->IsKind(STANDARD_TYPE(Geom_Parabola)) ||
456                c2->IsKind(STANDARD_TYPE(Geom_Hyperbola))) 
457       {
458         Standard_Real diff = domlast2 - domfirst2;
459         if (reversed2) domlast2 += 10.*diff;
460         else           domfirst2 -= 10.*diff;
461       }
462       else if (c2->IsKind(STANDARD_TYPE(Geom_Circle)) ||
463                c2->IsKind(STANDARD_TYPE(Geom_Ellipse))) 
464       {
465         domfirst2 = 0.; domlast2 = 2*M_PI;
466       }
467
468       Standard_Real ipar1 = clast1, ipar2 = cfirst2;
469
470       // Try to find projections of vertex point
471       GeomAPI_ProjectPointOnCurve Proj;
472       Standard_Real u1 = ipar1, u2 = ipar2;
473       Proj.Init(vpnt,c1,domfirst1,domlast1);
474       if (Proj.NbPoints()) 
475       {
476         Standard_Integer index = 1;
477         Standard_Real dist, mindist=-1.;
478         for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
479         {
480           dist = vpnt.Distance(Proj.Point(i));
481           if (mindist>dist || mindist<0.) 
482           { 
483             index = i; mindist = dist; 
484           }
485           u1 = Proj.Parameter(index);
486         }
487       }
488       Proj.Init(vpnt,c2,domfirst2,domlast2);
489       if (Proj.NbPoints()) 
490       {
491         Standard_Integer index = 1;
492         Standard_Real dist, mindist=-1.;
493         for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
494         {
495           dist = vpnt.Distance(Proj.Point(i));
496           if (mindist>dist || mindist<0.) 
497           { 
498             index = i; mindist = dist; 
499           }
500           u2 = Proj.Parameter(index);
501         }
502       }
503       // Ajust parameters on periodic curves
504       u1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,u1);
505       u2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,u2);
506       // Check points to satisfy distance criterium
507       gp_Pnt p1 = c1->Value(u1), p2 = c2->Value(u2);
508       if (p1.Distance(p2)<=gap &&
509           Abs(cfirst1-u1) > ::Precision::PConfusion() &&
510           Abs(clast2-u2) > ::Precision::PConfusion() &&
511           (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
512            (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap))) 
513       {
514         ipar1 = u1; ipar2 = u2;
515         done1 = done2 = Standard_True;
516       }
517
518       // Try to find closest points if nothing yet found
519       if (!done1) 
520       {
521
522         // Recompute domains
523         if (reversed1) 
524         { 
525           domfirst1 = ipar1; domlast1 = last1; 
526         }
527         else 
528         { 
529           domfirst1 = first1; domlast1 = ipar1; 
530         }
531         if (reversed2) 
532         { 
533           domfirst2 = first2; domlast2 = ipar2; 
534         }
535         else 
536         { 
537           domfirst2 = ipar2; domlast2 = last2; 
538         }
539
540         GeomAPI_ExtremaCurveCurve Extr(c1,c2,domfirst1,domlast1,domfirst2,domlast2);
541         if (Extr.NbExtrema()) 
542         {
543           try 
544           {
545             OCC_CATCH_SIGNALS
546             // First find all intersections
547             gp_Pnt pp1, pp2;
548             Standard_Integer index1=0, index2=0;
549             Standard_Real uu1, uu2, pardist, pardist1=-1., pardist2=-1.;
550             for (Standard_Integer i=1; i<=Extr.NbExtrema(); i++) 
551             {
552               Extr.Parameters(i,uu1,uu2);
553               // Ajust parameters on periodic curves
554               uu1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,uu1);
555               uu2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,uu2);
556               pp1 = c1->Value(uu1); pp2 = c2->Value(uu2);
557               if (pp1.Distance(pp2) < ::Precision::Confusion()) 
558               {
559                 // assume intersection
560                 pardist = Abs(cfirst1-uu1);
561                 if (pardist1>pardist || pardist1<0.) 
562                 { 
563                   index1 = i; pardist1 = pardist; 
564                 }
565                 pardist = Abs(clast2-uu2);
566                 if (pardist2>pardist || pardist2<0.) 
567                 { 
568                   index2 = i; pardist2 = pardist; 
569                 }
570               }
571             }
572             if (index1!=0 && index2!=0) 
573             {
574               if (index1!=index2) 
575               {
576                 // take intersection closer to vertex point
577                 Extr.Parameters(index1,uu1,uu2);
578                 pp1 = gp_Pnt((c1->Value(uu1).XYZ()+c2->Value(uu2).XYZ())*0.5);
579                 Extr.Parameters(index2,uu1,uu2);
580                 pp2 = gp_Pnt((c1->Value(uu1).XYZ()+c2->Value(uu2).XYZ())*0.5);
581                 if (pp2.Distance(vpnt) < pp1.Distance(vpnt)) index1 = index2;
582               }
583               Extr.Parameters(index1,uu1,uu2);
584             }
585             else Extr.LowerDistanceParameters(uu1,uu2);
586             // Ajust parameters on periodic curves
587             uu1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,uu1);
588             uu2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,uu2);
589             // Check points to satisfy distance criterium
590             pp1 = c1->Value(uu1), pp2 = c2->Value(uu2);
591             if (pp1.Distance(pp2)<=gap &&
592                 Abs(cfirst1-uu1) > ::Precision::PConfusion() &&
593                 Abs(clast2-uu2) > ::Precision::PConfusion() &&
594                 (((uu1>first1) && (uu1<last1)) || ((uu2>first2) && (uu2<last2)) ||
595                  (cpnt1.Distance(pp1)<=gap) || (cpnt2.Distance(pp2)<=gap))) 
596             {
597               ipar1 = uu1; ipar2 = uu2;
598               done1 = done2 = Standard_True;
599             }
600           }
601           catch ( Standard_Failure ) 
602           {
603           }
604         }
605       }
606       
607       try 
608       {
609         OCC_CATCH_SIGNALS
610         if (done1) 
611         {
612           if (ipar1==clast1) done1 = Standard_False;
613           else 
614           {
615             // Set up new bounds for curve
616             if (reversed1) first1 = ipar1; else last1 = ipar1;
617             // Set new trim for old curve
618             if (trimmed1) 
619             {
620               // Standard_Real ff1 = c1->FirstParameter();
621               // Standard_Real ll1 = c1->LastParameter();
622               c1 = new Geom_TrimmedCurve(c1,first1,last1);
623             }
624           }
625         }
626         if (done2) 
627         {
628           if (ipar2==cfirst2) done2 = Standard_False;
629           else 
630           {
631             // Set up new bounds for curve
632             if (reversed2) last2 = ipar2; else first2 = ipar2;
633             // Set new trim for old curve
634             if (trimmed2) 
635             {
636               // Standard_Real ff2 = c2->FirstParameter();
637               // Standard_Real ll2 = c2->LastParameter();
638               c2 = new Geom_TrimmedCurve(c2,first2,last2);
639             }
640           }
641         }
642       }
643       catch (Standard_Failure const& anException) {
644 #ifdef OCCT_DEBUG
645         cout << "Warning: ShapeFix_Wire_1::FixGap3d: Exception in TrimmedCurve      :"<<endl;
646         anException.Print(cout); cout << endl;
647 #endif
648         (void)anException;
649       }  
650     }
651   }
652   
653   if (done1 || done2) 
654   {
655
656     BRep_Builder B;
657     ShapeBuild_Edge SBE;
658     ShapeFix_ShapeTolerance SFST;
659
660     // Update vertices
661     TopoDS_Vertex nullV, newV1;
662 //smh#8
663     TopoDS_Shape emptyCopiedV2 = V2.EmptyCopied();
664     TopoDS_Vertex newV2 = TopoDS::Vertex(emptyCopiedV2);
665     SFST.SetTolerance(newV2,::Precision::Confusion());
666     Context()->Replace(V2,newV2);
667     if (V1.IsSame(V2))
668 //smh#8
669       {
670         TopoDS_Shape tmpV2 = newV2.Oriented(TopAbs_REVERSED);
671         newV1 = TopoDS::Vertex(tmpV2);
672       }
673     else 
674     {
675 //smh#8
676       TopoDS_Shape emptyCopied = V1.EmptyCopied();
677       newV1 = TopoDS::Vertex(emptyCopied);
678       SFST.SetTolerance(newV1,::Precision::Confusion());
679       Context()->Replace(V1,newV1);
680     }
681
682     if (done1) 
683     {
684       // Update first edge
685       TopoDS_Edge newE1 = SBE.CopyReplaceVertices(E1,nullV,newV1);
686 //smh#8
687       TopoDS_Shape tmpE1 = newE1.Oriented(TopAbs_FORWARD);
688       B.UpdateEdge(TopoDS::Edge(tmpE1),c1,0.);
689       SBE.SetRange3d(TopoDS::Edge(tmpE1),first1,last1);
690       SFST.SetTolerance(newE1,::Precision::Confusion(),TopAbs_EDGE);
691       B.SameRange(newE1,Standard_False);
692 //      B.SameParameter(newE1,Standard_False);
693       
694       //To keep NM vertices belonging initial edges
695       TopoDS_Iterator aItv(E1,Standard_False);
696       for( ; aItv.More(); aItv.Next()) {
697         if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
698            aItv.Value().Orientation() == TopAbs_EXTERNAL) {
699           TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
700           TopoDS_Vertex anewV =  ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE1,E1);
701           B.Add(newE1,anewV);
702           Context()->Replace(aOldV,anewV);
703         }
704       }
705       
706       Context()->Replace(E1,newE1);
707       sbwd->Set(newE1,n1);
708     }
709
710     if (done2) 
711     {
712       // Update second edge
713       TopoDS_Edge newE2 = SBE.CopyReplaceVertices(E2,newV2,nullV);
714 //smh#8
715       TopoDS_Shape tmpE2 = newE2.Oriented(TopAbs_FORWARD);
716       B.UpdateEdge(TopoDS::Edge(tmpE2),c2,0.);
717       SBE.SetRange3d(TopoDS::Edge(tmpE2),first2,last2);
718       SFST.SetTolerance(newE2,::Precision::Confusion(),TopAbs_EDGE);
719       B.SameRange(newE2,Standard_False);
720 //      B.SameParameter(newE2,Standard_False);
721       
722       //To keep NM vertices belonging initial edges
723       TopoDS_Iterator aItv(E2,Standard_False);
724       for( ; aItv.More(); aItv.Next()) {
725         if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
726            aItv.Value().Orientation() == TopAbs_EXTERNAL) {
727           TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
728           TopoDS_Vertex anewV =  ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE2,E2);
729           B.Add(newE2,anewV);
730           Context()->Replace(aOldV,anewV);
731         }
732       }
733       Context()->Replace(E2,newE2);
734       sbwd->Set(newE2,n2);
735     }
736
737     myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
738   }
739   else
740     if (convert)
741       myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL2 );
742
743   return (done1 || done2);
744 }
745
746 //=======================================================================
747 //function : FixGap2d
748 //purpose  : 
749 //=======================================================================
750
751 static Standard_Real AdjustOnPeriodic2d (const Handle(Geom2d_Curve)& pc,
752                                          const Standard_Boolean takefirst,
753                                          const Standard_Real first,
754                                          const Standard_Real last,
755                                          const Standard_Real param)
756 {
757   // 15.11.2002 PTV OCC966
758   if (ShapeAnalysis_Curve::IsPeriodic(pc)) 
759   {
760     Standard_Real T = pc->Period();
761     Standard_Real shift = -IntegerPart(first/T)*T; if (first<0.) shift += T;
762     Standard_Real sfirst = first+shift, slast = last+shift;
763     if ( takefirst && (param>slast) && (param>sfirst)) return param-T-shift;
764     if (!takefirst && (param<slast) && (param<sfirst)) return param+T-shift;
765   }
766   return param;
767 }
768
769  Standard_Boolean ShapeFix_Wire::FixGap2d (const Standard_Integer num,
770                                            const Standard_Boolean convert)
771 {
772   myLastFixStatus = ShapeExtend::EncodeStatus( ShapeExtend_OK );
773   if ( !IsReady() ) return Standard_False;
774
775   //=============
776   // First phase: analysis whether the problem (gap) exists
777   //=============
778
779   if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);
780
781   Standard_Real preci = ::Precision::PConfusion();
782   //Standard_Real preci = Precision();
783   //GeomAdaptor_Surface& SA = Analyzer().Surface()->Adaptor()->ChangeSurface();
784   //preci = Max(SA.UResolution(preci), SA.VResolution(preci));
785
786   Handle(ShapeExtend_WireData) sbwd = WireData();
787   Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
788   Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
789 //smh#8
790   TopoDS_Shape tmp1 = Context()->Apply(sbwd->Edge(n1)),
791                tmp2 = Context()->Apply(sbwd->Edge(n2));
792   TopoDS_Edge E1 = TopoDS::Edge(tmp1),
793               E2 = TopoDS::Edge(tmp2);
794   TopoDS_Face face = myAnalyzer->Face();
795
796   // Retrieve pcurves on edges
797   Standard_Real cfirst1, clast1, cfirst2, clast2;
798   Handle(Geom2d_Curve) PC1, PC2;
799   ShapeAnalysis_Edge SAE;
800   if (!SAE.PCurve(E1,face,PC1,cfirst1,clast1) ||
801       !SAE.PCurve(E2,face,PC2,cfirst2,clast2) ||
802       sbwd->IsSeam(n1) || sbwd->IsSeam(n2)) 
803   {
804     myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
805     return Standard_False;
806   }
807   
808   // Check gap in 2d space
809   gp_Pnt2d cpnt1 = PC1->Value(clast1), cpnt2 = PC2->Value(cfirst2);
810   Standard_Real gap = cpnt1.Distance(cpnt2);
811   if (gap<=preci) return Standard_False;
812     
813   //=============
814   // Second phase: collecting data necessary for further analysis
815   //=============
816
817   Standard_Boolean reversed1 = (E1.Orientation()==TopAbs_REVERSED),
818                    reversed2 = (E2.Orientation()==TopAbs_REVERSED);
819
820   Standard_Real first1, last1, first2, last2;
821   if (reversed1) 
822   { 
823     first1 = clast1;  last1 = cfirst1; 
824   }
825   else           
826   { 
827     first1 = cfirst1; last1 = clast1;  
828   }
829   if (reversed2) 
830   { 
831     first2 = clast2;  last2 = cfirst2; 
832   }
833   else           
834   { 
835     first2 = cfirst2; last2 = clast2;  
836   }
837
838   Handle(Geom2d_Curve) pc1 = PC1, pc2 = PC2;
839
840   // Extract basic curves from trimmed and offset
841   Standard_Boolean basic = Standard_False;
842   Standard_Boolean trimmed1 = Standard_False, offset1 = Standard_False;
843   Standard_Real offval1 = 0.;
844   while (!basic) 
845   {
846     if (pc1->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) 
847     {
848       pc1 = Handle(Geom2d_TrimmedCurve)::DownCast(pc1)->BasisCurve();
849       trimmed1 = Standard_True;
850     }
851     else if (pc1->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) 
852     {
853       Handle(Geom2d_OffsetCurve) oc = Handle(Geom2d_OffsetCurve)::DownCast(pc1);
854       pc1 = oc->BasisCurve();
855       offval1 += oc->Offset();
856       offset1 = Standard_True;
857     }
858     else basic = Standard_True;
859   }
860   basic = Standard_False;
861   Standard_Boolean trimmed2 = Standard_False, offset2 = Standard_False;
862   Standard_Real offval2 = 0.;
863   while (!basic) 
864   {
865     if (pc2->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) 
866     {
867       pc2 = Handle(Geom2d_TrimmedCurve)::DownCast(pc2)->BasisCurve();
868       trimmed2 = Standard_True;
869     }
870     else if (pc2->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) 
871     {
872       Handle(Geom2d_OffsetCurve) oc = Handle(Geom2d_OffsetCurve)::DownCast(pc2);
873       pc2 = oc->BasisCurve();
874       offval2 += oc->Offset();
875       offset2 = Standard_True;
876     }
877     else basic = Standard_True;
878   }
879   // Restore offset curves
880   if (offset1) pc1 = new Geom2d_OffsetCurve(pc1,offval1);
881   if (offset2) pc2 = new Geom2d_OffsetCurve(pc2,offval2);
882
883   Standard_Boolean done1 = Standard_False, done2 = Standard_False;
884
885   // Determine same edge case
886   if (convert) 
887   {
888
889     Handle(Geom2d_BSplineCurve) bsp1, bsp2;
890     Handle(Geom2d_Curve) pc;
891     Standard_Real first, last;
892
893     // iterate on pcurves
894     Standard_Integer nbcurv = (n1==n2? 1 : 2);
895     for (Standard_Integer j=1; j<=nbcurv; j++) 
896     {
897       //Standard_Integer trim = Standard_False; // skl
898       Handle(Geom2d_BSplineCurve) bsp;
899
900       if (j==1) 
901       { 
902         pc = pc1; first = first1; last = last1; /*trim = trimmed1;*/
903       } // skl
904       else      
905       { 
906         pc = pc2; first = first2; last = last2; /*trim = trimmed2;*/
907       } // skl
908
909       // Convert pcurve to bspline
910       if (pc->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) 
911       {
912         bsp = Handle(Geom2d_BSplineCurve)::DownCast(pc->Copy());
913         // take segment if trim and range differ
914         Standard_Real fbsp = bsp->FirstParameter(), lbsp = bsp->LastParameter();
915         Standard_Boolean segment = Standard_False;
916         if (first>fbsp) 
917         { 
918           fbsp = first; segment = Standard_True; 
919         }
920         if (last<lbsp) 
921         { 
922           lbsp = last; segment = Standard_True; 
923         }
924         if (segment)
925           bsp = Geom2dConvert::SplitBSplineCurve(bsp,fbsp,lbsp,
926                                                  ::Precision::PConfusion());
927       }
928       else if (pc->IsKind(STANDARD_TYPE(Geom2d_Conic))) 
929       {
930         GeomAdaptor_Surface& AS = myAnalyzer->Surface()->Adaptor3d()->ChangeSurface();
931         Standard_Real tolu = AS.UResolution(myAnalyzer->Precision()),
932         tolv = AS.VResolution(myAnalyzer->Precision());
933         Approx_Curve2d Conv(new Geom2dAdaptor_HCurve(pc,first,last),
934                             first,last,tolu,tolv,GeomAbs_C1,9,1000);
935         if (Conv.IsDone() || Conv.HasResult()) bsp = Conv.Curve();
936       }
937       else 
938       {
939         // Restore trim for pcurve
940         try 
941         {
942           OCC_CATCH_SIGNALS
943           Handle(Geom2d_Curve) c;
944           // 15.11.2002 PTV OCC966
945           if(!ShapeAnalysis_Curve::IsPeriodic(pc))
946             c = new Geom2d_TrimmedCurve(pc,Max(first,pc->FirstParameter()),Min(last,pc->LastParameter()));
947           else 
948             c = new Geom2d_TrimmedCurve(pc,first,last);
949           bsp = Geom2dConvert::CurveToBSplineCurve(c);
950         }
951         catch (Standard_Failure const& anException) {
952 #ifdef OCCT_DEBUG
953           cout << "Warning: ShapeFix_Wire_1::FixGap2d: Exception in TrimmedCurve2d" <<first<<" " <<last<<endl;
954           anException.Print(cout); cout << endl; 
955 #endif  
956           (void)anException;
957         }
958       }
959       
960       if (j==1) bsp1 = bsp; else bsp2 = bsp;
961     }
962     
963     // Take curves ends if could not convert
964     gp_Pnt2d mpnt((cpnt1.XY()+cpnt2.XY())*0.5);
965     if (bsp1.IsNull()) mpnt = cpnt1;
966     else if (bsp2.IsNull()) mpnt = cpnt2;
967
968     if (!bsp1.IsNull()) 
969     {
970       if(bsp1->Degree() == 1) bsp1->IncreaseDegree(2);
971       if (n1==n2) 
972       { 
973         bsp1->SetPole(1,mpnt); bsp1->SetPole(bsp1->NbPoles(),mpnt); 
974       }
975       else 
976       {
977         if (reversed1) bsp1->SetPole(1,mpnt);
978         else bsp1->SetPole(bsp1->NbPoles(),mpnt);
979       }
980       first1 = bsp1->FirstParameter(); last1 = bsp1->LastParameter();
981       pc1 = bsp1;
982       done1 = Standard_True;
983     }
984     if (!bsp2.IsNull()) 
985     {
986       if(bsp2->Degree() == 1) bsp2->IncreaseDegree(2);
987       if (reversed2) bsp2->SetPole(bsp2->NbPoles(),mpnt);
988       else bsp2->SetPole(1,mpnt);
989       first2 = bsp2->FirstParameter(); last2 = bsp2->LastParameter();
990       pc2 = bsp2;
991       done2 = Standard_True;
992     }
993   }
994   else 
995   {
996
997     if (n1==n2) 
998     {
999       if (pc1->IsKind(STANDARD_TYPE(Geom2d_Circle)) ||
1000           pc1->IsKind(STANDARD_TYPE(Geom2d_Ellipse))) 
1001       {
1002         Standard_Real diff = M_PI - Abs(clast1-cfirst2)*0.5;
1003         first1 -= diff; last1 += diff;
1004         done1 = Standard_True;
1005       }
1006     }
1007     else 
1008     {
1009
1010       // Determine domains for extremal points locating
1011       Standard_Real domfirst1 = first1, domlast1 = last1;
1012       if (pc1->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) ||
1013           pc1->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) 
1014       {
1015         domfirst1 = pc1->FirstParameter();
1016         domlast1  = pc1->LastParameter();
1017       }
1018       else if (pc1->IsKind(STANDARD_TYPE(Geom2d_Line)) ||
1019                pc1->IsKind(STANDARD_TYPE(Geom2d_Parabola)) ||
1020                pc1->IsKind(STANDARD_TYPE(Geom2d_Hyperbola))) 
1021       {
1022         Standard_Real diff = domlast1 - domfirst1;
1023         if (reversed1) domfirst1 -= 10.*diff;
1024         else           domlast1 += 10.*diff;
1025       }
1026       else if (pc1->IsKind(STANDARD_TYPE(Geom2d_Circle)) ||
1027                pc1->IsKind(STANDARD_TYPE(Geom2d_Ellipse))) 
1028       {
1029         domfirst1 = 0.; domlast1 = 2*M_PI;
1030       }
1031       Standard_Real domfirst2 = first2, domlast2 = last2;
1032       if (pc2->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) ||
1033           pc2->IsKind(STANDARD_TYPE(Geom2d_BezierCurve))) 
1034       {
1035         domfirst2 = pc2->FirstParameter();
1036         domlast2  = pc2->LastParameter();
1037       }
1038       else if (pc2->IsKind(STANDARD_TYPE(Geom2d_Line)) ||
1039                pc2->IsKind(STANDARD_TYPE(Geom2d_Parabola)) ||
1040                pc2->IsKind(STANDARD_TYPE(Geom2d_Hyperbola))) 
1041       {
1042         Standard_Real diff = domlast2 - domfirst2;
1043         if (reversed2) domlast2 += 10.*diff;
1044         else           domfirst2 -= 10.*diff;
1045       }
1046       else if (pc2->IsKind(STANDARD_TYPE(Geom2d_Circle)) ||
1047                pc2->IsKind(STANDARD_TYPE(Geom2d_Ellipse))) 
1048       {
1049         domfirst2 = 0.; domlast2 = 2*M_PI;
1050       }
1051
1052       Standard_Real ipar1 = clast1, ipar2 = cfirst2;
1053
1054       Geom2dInt_GInter Inter;
1055       Standard_Real tolint = ::Precision::PConfusion();
1056
1057       Geom2dAdaptor_Curve AC1(pc1), AC2(pc2);
1058
1059       // Try to find intersection points
1060       IntRes2d_Domain dom1(pc1->Value(domfirst1),domfirst1,tolint,
1061                            pc1->Value(domlast1),domlast1,tolint);
1062       IntRes2d_Domain dom2(pc2->Value(domfirst2),domfirst2,tolint,
1063                            pc2->Value(domlast2),domlast2,tolint);
1064       Inter.Perform( AC1, dom1, AC2, dom2, tolint, tolint );
1065       if (Inter.IsDone()) 
1066       {
1067         if (Inter.NbPoints() || Inter.NbSegments()) 
1068         {
1069           Standard_Integer i, index1 = 0, index2 = 0;
1070           Standard_Real pardist, pardist1=-1., pardist2=-1.;
1071           // iterate on intersection points
1072           IntRes2d_IntersectionPoint IP;
1073           for ( i=1; i<=Inter.NbPoints(); i++ ) 
1074           {
1075             IP = Inter.Point(i);
1076             // Adjust parameters on periodic curves
1077             Standard_Real u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,
1078                                                   IP.ParamOnFirst());
1079             Standard_Real u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,
1080                                                   IP.ParamOnSecond());
1081             pardist = Abs(cfirst1-u1);
1082             if (pardist1>pardist || pardist1<0.) 
1083             { 
1084               index1 = i; pardist1 = pardist; 
1085             }
1086               pardist = Abs(clast2-u2);
1087             if (pardist2>pardist || pardist2<0.) 
1088             { 
1089               index2 = i; pardist2 = pardist; 
1090             }
1091           }
1092           Standard_Integer flag1 = 0, flag2 = 0;
1093           // iterate on intersection segments
1094           IntRes2d_IntersectionSegment IS;
1095           for ( i=1; i<=Inter.NbSegments(); i++ ) 
1096           {
1097             IS = Inter.Segment(i);
1098             for (Standard_Integer j=1; j<=2; j++) 
1099             {
1100               if ((j==1 && IS.HasFirstPoint()) ||
1101                   (j==2 && IS.HasLastPoint())) 
1102               {
1103                 if (j==1) IP = IS.FirstPoint();
1104                 else      IP = IS.LastPoint();
1105                 // Adjust parameters on periodic curves
1106                 Standard_Real u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,
1107                                                       IP.ParamOnFirst());
1108                 Standard_Real u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,
1109                                                       IP.ParamOnSecond());
1110                 pardist = Abs(cfirst1-u1);
1111                 if (pardist1>pardist || pardist1<0.) 
1112                 {
1113                   flag1 = j; index1 = i; pardist1 = pardist;
1114                 }
1115                 pardist = Abs(clast2-u2);
1116                 if (pardist2>pardist || pardist2<0.) 
1117                 {
1118                   flag2 = j; index2 = i; pardist2 = pardist;
1119                 }
1120               }
1121             }
1122           }
1123           if (index1!=index2 || flag1!=flag2) 
1124           {
1125             // take intersection closer to mean point
1126             gp_Pnt2d pt1, pt2;
1127             if (flag1==0) pt1 = Inter.Point(index1).Value();
1128             else 
1129             {
1130               IS = Inter.Segment(index1);
1131               if (flag1==1) pt1 = IS.FirstPoint().Value();
1132               else          pt1 = IS.LastPoint().Value();
1133             }
1134             if (flag2==0) pt2 = Inter.Point(index2).Value();
1135             else 
1136             {
1137               IS = Inter.Segment(index2);
1138               if (flag2==1) pt2 = IS.FirstPoint().Value();
1139               else          pt2 = IS.LastPoint().Value();
1140             }
1141             gp_Pnt2d mpnt((cpnt1.XY()+cpnt2.XY())*0.5);
1142             if (pt2.Distance(mpnt) < pt1.Distance(mpnt)) 
1143             {
1144               index1 = index2; flag1 = flag2;
1145             }
1146           }
1147           if (flag1==0) IP = Inter.Point(index1);
1148           else 
1149           {
1150             IS = Inter.Segment(index1);
1151             if (flag1==1) IP = IS.FirstPoint();
1152             else          IP = IS.LastPoint();
1153           }
1154           // Ajust parameters on periodic curves
1155           Standard_Real u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,
1156                                                 IP.ParamOnFirst());
1157           Standard_Real u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,
1158                                                 IP.ParamOnSecond());
1159           // Check points to satisfy distance criterium
1160           gp_Pnt2d p1 = pc1->Value(u1), p2 = pc2->Value(u2);
1161           if (p1.Distance(p2)<=gap &&
1162               Abs(cfirst1-u1) > ::Precision::PConfusion() &&
1163               Abs(clast2 -u2) > ::Precision::PConfusion() &&
1164               (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
1165                (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap))) 
1166           {
1167             ipar1 = u1; ipar2 = u2;
1168             done1 = done2 = Standard_True;
1169           }
1170         }
1171       }
1172
1173       // Try to find closest points if nothing yet found
1174       if (!done1) 
1175       {
1176         Geom2dAPI_ExtremaCurveCurve Extr(pc1,pc2,domfirst1,domlast1,domfirst2,domlast2);
1177         if (Extr.NbExtrema()) 
1178         {
1179           Standard_Real u1, u2;
1180           Extr.LowerDistanceParameters(u1,u2);
1181           // Ajust parameters on periodic curves
1182           u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,u1);
1183           u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,u2);
1184           // Check points to satisfy distance criterium
1185           gp_Pnt2d p1 = pc1->Value(u1), p2 = pc2->Value(u2);
1186           if (p1.Distance(p2)<=gap &&
1187               Abs(cfirst1-u1) > ::Precision::PConfusion() &&
1188               Abs(clast2 -u2) > ::Precision::PConfusion() &&
1189               (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
1190                (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap))) 
1191           {
1192             ipar1 = u1; ipar2 = u2;
1193             done1 = done2 = Standard_True;
1194           }
1195         }
1196       }
1197
1198       // Try to find projections if nothing yet found
1199       if (!done1) 
1200       {
1201         Geom2dAPI_ProjectPointOnCurve Proj;
1202         gp_Pnt2d ipnt1 = cpnt1, ipnt2 = cpnt2;
1203         Standard_Real u1 = ipar1, u2 = ipar2;
1204         Proj.Init(cpnt2,pc1,domfirst1,domlast1);
1205         if (Proj.NbPoints()) 
1206         {
1207           Standard_Integer index = 1;
1208           Standard_Real dist, mindist=-1.;
1209           for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
1210           {
1211             dist = cpnt2.Distance(Proj.Point(i));
1212             if (mindist>dist || mindist<0.) 
1213             { 
1214               index = i; mindist = dist; 
1215             }
1216             ipnt1 = Proj.Point(index);
1217             u1 = Proj.Parameter(index);
1218           }
1219         }
1220         Proj.Init(cpnt1,pc2,domfirst2,domlast2);
1221         if (Proj.NbPoints()) 
1222         {
1223           Standard_Integer index = 1;
1224           Standard_Real dist, mindist=-1.;
1225           for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
1226           {
1227             dist = cpnt1.Distance(Proj.Point(i));
1228             if (mindist>dist || mindist<0.) 
1229             { 
1230               index = i; mindist = dist; 
1231             }
1232             ipnt2 = Proj.Point(index);
1233             u2 = Proj.Parameter(index);
1234           }
1235         }
1236         // Ajust parameters on periodic curves
1237         u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,u1);
1238         u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,u2);
1239         // Process special case of projection
1240         if ((((reversed1 && u1>clast1)  || (!reversed1 && u1<clast1)) &&
1241              ((reversed2 && u2<cfirst2) || (!reversed2 && u2>cfirst2))) ||
1242             (((reversed1 && u1<clast1)  || (!reversed1 && u1>clast1)) &&
1243              ((reversed2 && u2>cfirst2) || (!reversed2 && u2<cfirst2)))) 
1244         {
1245           // both projections lie inside/outside initial domains
1246           // project mean point
1247           gp_Pnt2d mpnt((cpnt1.XY()+cpnt2.XY())*0.5);
1248           u1 = ipar1; u2 = ipar2;
1249           Proj.Init(mpnt,pc1,domfirst1,domlast1);
1250           if (Proj.NbPoints()) 
1251           {
1252             Standard_Integer index = 1;
1253             Standard_Real dist, mindist=-1.;
1254             for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
1255             {
1256               dist = mpnt.Distance(Proj.Point(i));
1257               if (mindist>dist || mindist<0.) 
1258               { 
1259                 index = i; mindist = dist; 
1260               }
1261               ipnt1 = Proj.Point(index);
1262               u1 = Proj.Parameter(index);
1263             }
1264           }
1265           Proj.Init(mpnt,pc2,domfirst2,domlast2);
1266           if (Proj.NbPoints()) 
1267           {
1268             Standard_Integer index = 1;
1269             Standard_Real dist, mindist=-1.;
1270             for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
1271             {
1272               dist = mpnt.Distance(Proj.Point(i));
1273               if (mindist>dist || mindist<0.) 
1274               { 
1275                 index = i; mindist = dist; 
1276               }
1277               ipnt2 = Proj.Point(index);
1278               u2 = Proj.Parameter(index);
1279             }
1280           }
1281         }
1282         else 
1283         {
1284           if (cpnt1.Distance(ipnt2)<cpnt2.Distance(ipnt1)) u1 = ipar1;
1285           else                                             u2 = ipar2;
1286         }
1287         // Ajust parameters on periodic curves
1288         u1 = AdjustOnPeriodic2d(pc1,reversed1,first1,last1,u1);
1289         u2 = AdjustOnPeriodic2d(pc2,!reversed2,first2,last2,u2);
1290         // Check points to satisfy distance criterium
1291         gp_Pnt2d p1 = pc1->Value(u1), p2 = pc2->Value(u2);
1292         if (p1.Distance(p2)<=gap &&
1293             Abs(cfirst1-u1) > ::Precision::PConfusion() &&
1294             Abs(clast2 -u2) > ::Precision::PConfusion() &&
1295             (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
1296              (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap))) 
1297         {
1298           ipar1 = u1; ipar2 = u2;
1299           done1 = done2 = Standard_True;
1300         }
1301       }
1302
1303       if (done1) 
1304       {
1305
1306         if (ipar1<first1 || ipar1>last1 || ipar2<first2 || ipar2>last2) 
1307         {
1308
1309           // Check whether new points lie inside the surface bounds
1310           Standard_Real umin, umax, vmin, vmax;
1311           myAnalyzer->Surface()->Surface()->Bounds(umin,umax,vmin,vmax);
1312           if (::Precision::IsInfinite(umin) || ::Precision::IsInfinite(umax) ||
1313               ::Precision::IsInfinite(vmin) || ::Precision::IsInfinite(vmax)) 
1314           {
1315             Standard_Real fumin, fumax, fvmin, fvmax;
1316             BRepTools::UVBounds(face,fumin,fumax,fvmin,fvmax);
1317             if (::Precision::IsInfinite(umin)) umin = fumin-preci;
1318             if (::Precision::IsInfinite(umax)) umax = fumax+preci;
1319             if (::Precision::IsInfinite(vmin)) vmin = fvmin-preci;
1320             if (::Precision::IsInfinite(vmax)) vmax = fvmax+preci;
1321           }
1322
1323           gp_Pnt2d ipnt, P1, P2;
1324           Standard_Real u, v;
1325           Standard_Boolean out;
1326           // iterate on curves
1327           for (Standard_Integer j=1; j<=2; j++) 
1328           {
1329
1330             if (j==1) 
1331             {
1332               if (ipar1>=first1 && ipar1<=last1) continue;
1333               ipnt = pc1->Value(ipar1);
1334             }
1335             else 
1336             {
1337               if (ipar2>=first2 && ipar2<=last2) continue;
1338               ipnt = pc2->Value(ipar2);
1339             }
1340
1341             // iterate on bounding lines
1342             for (Standard_Integer k=1; k<=2; k++) 
1343             {
1344
1345               u = ipnt.X(); v = ipnt.Y();
1346
1347               out = Standard_True;
1348               if (k==1) 
1349               {
1350                 if (u<umin) 
1351                 { 
1352                   P1 = gp_Pnt2d(umin,vmin); P2 = gp_Pnt2d(umin,vmax); 
1353                 }
1354                 else if (u>umax) 
1355                 { 
1356                   P1 = gp_Pnt2d(umax,vmin); P2 = gp_Pnt2d(umax,vmax); 
1357                 }
1358                 else out = Standard_False;
1359               }
1360               else 
1361               {
1362                 if (v<vmin) 
1363                 { 
1364                   P1 = gp_Pnt2d(umin,vmin); P2 = gp_Pnt2d(umax,vmin); 
1365                 }
1366                 else if (v>vmax) 
1367                 { 
1368                   P1 = gp_Pnt2d(umin,vmax); P2 = gp_Pnt2d(umax,vmax); 
1369                 }
1370                 else out = Standard_False;
1371               }
1372
1373               if (out) 
1374               {
1375                 // Intersect pcurve with bounding line
1376                 Handle(Geom2d_Line) lin = new Geom2d_Line(P1,gp_Dir2d(gp_Vec2d(P1,P2)));
1377                 Geom2dAdaptor_Curve ACL(lin);
1378                 IntRes2d_Domain dlin(P1,0.,tolint,P2,P1.Distance(P2),tolint);
1379
1380                 Handle(Geom2d_Curve) pc;
1381                 Standard_Real fpar, lpar;
1382                 if (j==1) 
1383                 {
1384                   if (cfirst1<ipar1) 
1385                   { 
1386                     fpar = cfirst1, lpar = ipar1; 
1387                   }
1388                   else 
1389                   { 
1390                     fpar = ipar1, lpar = cfirst1; 
1391                   }
1392                   pc = pc1;
1393                 }
1394                 else 
1395                 {
1396                   if (clast2<ipar2) 
1397                   { 
1398                     fpar = clast2, lpar = ipar2; 
1399                   }
1400                   else 
1401                   { 
1402                     fpar = ipar2, lpar = clast2; 
1403                   }
1404                   pc = pc2;
1405                 }
1406                 Geom2dAdaptor_Curve ACC(pc);
1407                 IntRes2d_Domain domc(pc->Value(fpar),fpar,tolint,
1408                                      pc->Value(lpar),lpar,tolint);
1409
1410                 // Intersect line with the pcurve
1411                 Inter.Perform( ACL, dlin, ACC, domc, tolint, tolint );
1412                 if (Inter.IsDone()) 
1413                 {
1414                   if (Inter.NbPoints() || Inter.NbSegments()) 
1415                   {
1416                     Standard_Integer i, index = 1;
1417                     Standard_Real uu, dist, mindist=-1.;
1418                     // iterate on intersection points
1419                     for ( i=1; i<=Inter.NbPoints(); i++ ) 
1420                     {
1421                       // Adjust parameters on periodic curve
1422                       uu = AdjustOnPeriodic2d(pc,(j==1? reversed1 : !reversed2),
1423                                               fpar,lpar,Inter.Point(i).ParamOnSecond());
1424                       dist = Abs((j==1? cfirst1 : clast2)-uu);
1425                       if (mindist>dist || mindist<0.) 
1426                       { 
1427                         index = i; mindist = dist; 
1428                       }
1429                     }
1430                     // iterate on intersection segments
1431                     Standard_Integer flag = 0;
1432                     IntRes2d_IntersectionPoint IP;
1433                     IntRes2d_IntersectionSegment IS;
1434                     for ( i=1; i<=Inter.NbSegments(); i++ ) 
1435                     {
1436                       IS = Inter.Segment(i);
1437                       for (Standard_Integer jj=1; jj<=2; jj++) 
1438                       {
1439                         if ((jj==1 && IS.HasFirstPoint()) ||
1440                             (jj==2 && IS.HasLastPoint())) 
1441                         {
1442                           if (jj==1) IP = IS.FirstPoint();
1443                           else       IP = IS.LastPoint();
1444                           // Adjust parameters on periodic curve
1445                           uu = AdjustOnPeriodic2d(pc,(jj==1? reversed1 : !reversed2),
1446                                                   fpar,lpar,IP.ParamOnSecond());
1447                           dist = Abs((jj==1? cfirst1 : clast2)-uu);
1448                           if (mindist>dist || mindist<0.)
1449                           { 
1450                             flag = jj; index = i; mindist = dist; 
1451                           }
1452                         }
1453                       }
1454                     }
1455                     if (flag==0) IP = Inter.Point(index);
1456                     else 
1457                     {
1458                       IS = Inter.Segment(index);
1459                       if (flag==1) IP = IS.FirstPoint();
1460                       else         IP = IS.LastPoint();
1461                     }
1462                     // Ajust parameters on periodic curve
1463                     uu = AdjustOnPeriodic2d(pc,(j==1? reversed1 : !reversed2),
1464                                             fpar,lpar,IP.ParamOnSecond());
1465                     if (j==1 && Abs(cfirst1-uu) > ::Precision::PConfusion())
1466                     { 
1467                       ipar1 = uu; ipnt = IP.Value(); 
1468                     }
1469                     if (j==2 && Abs(clast2-uu) > ::Precision::PConfusion())
1470                     { 
1471                       ipar2 = uu; ipnt = IP.Value(); 
1472                     }
1473                   }
1474                 }
1475               }
1476             }
1477
1478             // Adjust if intersection lies inside old bounds
1479             if (j==1) 
1480             {
1481               if (reversed1) 
1482               { 
1483                 if (ipar1>first1) ipar1 = first1; 
1484               }
1485               else           
1486               { 
1487                 if (ipar1<last1) ipar1 = last1; 
1488               }
1489             }
1490             else 
1491             {
1492               if (reversed2) 
1493               { 
1494                 if (ipar2<last2) ipar2 = last2; 
1495               }
1496               else           
1497               { 
1498                 if (ipar2>first2) ipar2 = first2; 
1499               }
1500             }
1501           }
1502         }
1503       }
1504       try 
1505       {
1506         OCC_CATCH_SIGNALS
1507         if (done1) 
1508         {
1509           if (ipar1==clast1) done1 = Standard_False;
1510           else 
1511           {
1512             // Set up new bounds for pcurve
1513             if (reversed1) first1 = ipar1; else last1 = ipar1;
1514             // Set new trim for old pcurve
1515             if (trimmed1) pc1 = new Geom2d_TrimmedCurve(pc1,first1,last1);
1516           }
1517         }
1518         if (done2) 
1519         {
1520           if (ipar2==cfirst2) done2 = Standard_False;
1521           else 
1522           {
1523             // Set up new bounds for pcurve
1524             if (reversed2) last2 = ipar2; else first2 = ipar2;
1525             // Set new trim for old pcurve
1526             if (trimmed2) pc2 = new Geom2d_TrimmedCurve(pc2,first2,last2);
1527           }
1528         }
1529       }
1530       catch (Standard_Failure const& anException) {
1531 #ifdef OCCT_DEBUG
1532         cout << "Warning: ShapeFix_Wire_1::FixGap2d: Exception in TrimmedCurve2d  :"<<endl;
1533         anException.Print(cout); cout << endl;
1534 #endif  
1535         (void)anException;
1536       }  
1537     }
1538   }
1539
1540   if (done1 || done2) 
1541   {
1542
1543     BRep_Builder B;
1544     ShapeBuild_Edge SBE;
1545     ShapeFix_ShapeTolerance SFST;
1546
1547     // Update vertices
1548     TopoDS_Vertex V1 = SAE.LastVertex(E1), V2 = SAE.FirstVertex(E2);
1549     TopoDS_Vertex nullV, newV1;
1550 //smh#8
1551     TopoDS_Shape emptyCopiedV2 = V2.EmptyCopied();
1552     TopoDS_Vertex newV2 = TopoDS::Vertex(emptyCopiedV2);
1553     SFST.SetTolerance(newV2,::Precision::Confusion());
1554     Context()->Replace(V2,newV2);
1555     if (V1.IsSame(V2))
1556 //smh#8
1557     {
1558       TopoDS_Shape tmpVertexRev = newV2.Oriented(TopAbs_REVERSED);
1559       newV1 = TopoDS::Vertex(tmpVertexRev);
1560     }
1561     else 
1562     {
1563 //smh#8
1564       TopoDS_Shape emptyCopiedV1 = V1.EmptyCopied();
1565       newV1 = TopoDS::Vertex(emptyCopiedV1);
1566       SFST.SetTolerance(newV1,::Precision::Confusion());
1567       Context()->Replace(V1,newV1);
1568     }
1569
1570     if (done1) 
1571     {
1572       // Update first edge
1573       TopoDS_Edge newE1 = SBE.CopyReplaceVertices(E1,nullV,newV1);
1574 //smh#8
1575       TopoDS_Shape tmpE1 = newE1.Oriented(TopAbs_FORWARD);
1576       B.UpdateEdge(TopoDS::Edge(tmpE1),pc1,face,0.);
1577       B.Range(TopoDS::Edge(tmpE1),face,first1,last1);
1578       SFST.SetTolerance(newE1,::Precision::Confusion(),TopAbs_EDGE);
1579       B.SameRange(newE1,Standard_False);
1580 //      B.SameParameter(newE1,Standard_False);
1581       
1582       //To keep NM vertices belonging initial edges
1583       TopoDS_Iterator aItv(E1,Standard_False);
1584       for( ; aItv.More(); aItv.Next()) {
1585         if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
1586            aItv.Value().Orientation() == TopAbs_EXTERNAL) {
1587           TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
1588           TopoDS_Vertex anewV =  ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE1,E1);
1589           B.Add(newE1,anewV);
1590           Context()->Replace(aOldV,anewV);
1591         }
1592       }
1593       
1594       Context()->Replace(E1,newE1);
1595       sbwd->Set(newE1,n1);
1596     }
1597
1598     if (done2) 
1599     {
1600       // Update second edge
1601       TopoDS_Edge newE2 = SBE.CopyReplaceVertices(E2,newV2,nullV);
1602 //smh#8
1603       TopoDS_Shape tmpE2 = newE2.Oriented(TopAbs_FORWARD);
1604       B.UpdateEdge(TopoDS::Edge(tmpE2),pc2,face,0.);
1605       B.Range(TopoDS::Edge(tmpE2),face,first2,last2);
1606       SFST.SetTolerance(newE2,::Precision::Confusion(),TopAbs_EDGE);
1607       B.SameRange(newE2,Standard_False);
1608 //      B.SameParameter(newE2,Standard_False);
1609       //To keep NM vertices belonging initial edges
1610       TopoDS_Iterator aItv(E2,Standard_False);
1611       for( ; aItv.More(); aItv.Next()) {
1612         if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
1613            aItv.Value().Orientation() == TopAbs_EXTERNAL) {
1614           TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
1615           TopoDS_Vertex anewV =  ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE2,E2);
1616           B.Add(newE2,anewV);
1617           Context()->Replace(aOldV,anewV);
1618         }
1619       }
1620       Context()->Replace(E2,newE2);
1621       sbwd->Set(newE2,n2);
1622     }
1623
1624     myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
1625   }
1626   else
1627     if (convert)
1628       myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL2 );
1629
1630   return (done1 || done2);
1631 }