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