0032485: Modeling Algorithms - Add Clone() function for adapters
[occt.git] / src / Adaptor3d / Adaptor3d_CurveOnSurface.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 #define No_Standard_OutOfRange
15
16
17 #include <Adaptor3d_CurveOnSurface.hxx>
18
19 #include <Adaptor2d_Curve2d.hxx>
20 #include <Adaptor3d_Surface.hxx>
21 #include <Adaptor3d_InterFunc.hxx>
22 #include <ElCLib.hxx>
23 #include <ElSLib.hxx>
24 #include <Geom2d_BezierCurve.hxx>
25 #include <Geom2d_BSplineCurve.hxx>
26 #include <Geom_BezierCurve.hxx>
27 #include <Geom_BSplineCurve.hxx>
28 #include <Geom_BSplineSurface.hxx>
29 #include <Geom_OffsetSurface.hxx>
30 #include <Geom_SurfaceOfLinearExtrusion.hxx>
31 #include <Geom_SurfaceOfRevolution.hxx>
32 #include <gp_Ax22d.hxx>
33 #include <gp_Circ.hxx>
34 #include <gp_Circ2d.hxx>
35 #include <gp_Elips.hxx>
36 #include <gp_Elips2d.hxx>
37 #include <gp_Hypr.hxx>
38 #include <gp_Hypr2d.hxx>
39 #include <gp_Lin.hxx>
40 #include <gp_Lin2d.hxx>
41 #include <gp_Parab.hxx>
42 #include <gp_Parab2d.hxx>
43 #include <gp_Pnt.hxx>
44 #include <gp_Pnt2d.hxx>
45 #include <gp_Vec.hxx>
46 #include <gp_Vec2d.hxx>
47 #include <math_FunctionRoots.hxx>
48 #include <Precision.hxx>
49 #include <Standard_Assert.hxx>
50 #include <Standard_DomainError.hxx>
51 #include <Standard_NoSuchObject.hxx>
52 #include <Standard_NotImplemented.hxx>
53 #include <Standard_OutOfRange.hxx>
54 #include <TColgp_Array1OfPnt.hxx>
55 #include <TColgp_Array1OfPnt2d.hxx>
56 #include <TColStd_Array1OfInteger.hxx>
57 #include <TColStd_Array1OfReal.hxx>
58 #include <TColStd_HSequenceOfReal.hxx>
59
60 IMPLEMENT_STANDARD_RTTIEXT(Adaptor3d_CurveOnSurface, Adaptor3d_Curve)
61
62 static gp_Pnt to3d(const gp_Pln& Pl, const gp_Pnt2d& P)
63 {
64   return ElSLib::Value(P.X(),P.Y(),Pl);
65 }
66
67 static gp_Vec to3d(const gp_Pln& Pl, const gp_Vec2d& V)
68 {
69   gp_Vec Vx = Pl.XAxis().Direction();
70   gp_Vec Vy = Pl.YAxis().Direction();
71   Vx.Multiply(V.X());
72   Vy.Multiply(V.Y());
73   Vx.Add(Vy);
74   return Vx;
75 }
76
77 static gp_Ax2 to3d(const gp_Pln& Pl, const gp_Ax22d& A)
78 {
79   gp_Pnt P = to3d(Pl,A.Location());
80   gp_Vec VX = to3d(Pl,A.XAxis().Direction());
81   gp_Vec VY = to3d(Pl,A.YAxis().Direction());
82   return gp_Ax2(P,VX.Crossed(VY),VX);
83 }
84
85 static gp_Circ to3d(const gp_Pln& Pl, const gp_Circ2d& C)
86 {
87   return gp_Circ(to3d(Pl,C.Axis()),C.Radius());
88 }
89
90 static gp_Elips to3d(const gp_Pln& Pl, const gp_Elips2d& E)
91 {
92   return gp_Elips(to3d(Pl,E.Axis()),E.MajorRadius(),E.MinorRadius());
93 }
94
95 static gp_Hypr to3d(const gp_Pln& Pl, const gp_Hypr2d& H)
96 {
97   return gp_Hypr(to3d(Pl,H.Axis()),H.MajorRadius(),H.MinorRadius());
98 }
99
100 static gp_Parab to3d(const gp_Pln& Pl, const gp_Parab2d& P)
101 {
102   return gp_Parab(to3d(Pl,P.Axis()),P.Focal());
103 }
104
105 static gp_Vec SetLinearForm(const gp_Vec2d DW, const gp_Vec2d D2W,const gp_Vec2d D3W,
106                             const gp_Vec D1U,  const gp_Vec D1V,  const gp_Vec D2U,
107                             const gp_Vec D2V,  const gp_Vec D2UV, const gp_Vec D3U,
108                             const gp_Vec D3V,  const gp_Vec D3UUV,const gp_Vec D3UVV)
109 {gp_Vec V31, V32, V33, V34,V3 ;
110  V31.SetLinearForm(DW.X(),D1U,
111                    D2W.X()*DW.X(),D2U,
112                    D2W.X()*DW.Y(),D2UV);
113  V31.SetLinearForm(D3W.Y(),D1V,
114                    D2W.Y()*DW.X(),D2UV,
115                    D2W.Y()*DW.Y(),D2V,
116                    V31);
117  V32.SetLinearForm(DW.X()*DW.X()*DW.Y(),D3UUV,
118                    DW.X()*DW.Y()*DW.Y(),D3UVV);
119  V32.SetLinearForm(D2W.X()*DW.Y()+DW.X()*D2W.Y(),D2UV,
120                    DW.X()*DW.Y()*DW.Y(),D3UVV,
121                    V32);
122  V33.SetLinearForm(2*D2W.X()*DW.X(),D2U,
123                    DW.X()*DW.X()*DW.X(),D3U,
124                    DW.X()*DW.X()*DW.Y(),D3UUV);
125  
126  V34.SetLinearForm(2*D2W.Y()*DW.Y(),D2V,
127                    DW.Y()*DW.Y()*DW.X(),D3UVV,
128                    DW.Y()*DW.Y()*DW.Y(),D3V);
129  V3.SetLinearForm(1,V31,2,V32,1,V33,V34);
130  return V3;
131 }
132
133 //=======================================================================
134 static void CompareBounds(gp_Pnt2d& P1,
135                           gp_Pnt2d& P2)//SVV
136 {
137    Standard_Real Lx = P1.X(),Ly = P1.Y();
138    Standard_Real Rx = P2.X(),Ry = P2.Y();
139    
140    if (Lx > Rx) { P1.SetX(Rx); P2.SetX(Lx);}
141    if (Ly > Ry) { P1.SetY(Ry); P2.SetY(Ly);}
142 }
143
144 //=======================================================================
145 //function :Hunt
146 //purpose  : 
147 //=======================================================================
148 static void Hunt(const TColStd_Array1OfReal& Arr,
149                  const Standard_Real Coord,
150                  Standard_Integer& Iloc)
151 {//Warning: Hunt is used to find number of knot which equals coordinate component,
152   //        when coordinate component definitly equals a knot only.
153   Standard_Real Tol=Precision::PConfusion()/10;
154   Standard_Integer i=1; 
155   while((i <= Arr.Upper()) && (Abs(Coord - Arr(i)) > Tol)){
156     i++;}
157  
158   if(Abs(Coord - Arr(i)) < Tol)
159     Iloc = i;
160   else
161     if(Abs(Coord - Arr(i)) > Tol) 
162       throw Standard_NotImplemented("Adaptor3d_CurveOnSurface:Hunt");
163 }
164
165 //=======================================================================
166 //function :ReverseParam
167 //purpose  : 
168 //=======================================================================
169
170 static void ReverseParam(const Standard_Real In1,
171                          const Standard_Real In2,
172                          Standard_Real& Out1,
173                          Standard_Real& Out2 )
174 {
175
176   if(In1>In2)  {Out1=In2;
177                 Out2=In1;}
178   else         {Out1=In1;
179                 Out2=In2;}
180 }
181 //=======================================================================
182 //function :ReverseParam
183 //purpose  : 
184 //=======================================================================
185
186 static void ReverseParam(const Standard_Integer In1,
187                          const Standard_Integer In2,
188                          Standard_Integer& Out1,
189                          Standard_Integer& Out2 )
190 {
191   if(In1>In2)  {Out1=In2;
192                 Out2=In1;}
193   else         {Out1=In1;
194                 Out2=In2;}
195 }
196
197 //=======================================================================
198 //function :FindBounds
199 //purpose  : 
200 //=======================================================================
201 static void FindBounds(const TColStd_Array1OfReal& Arr,
202                        const Standard_Real Coord,
203                        const Standard_Real Der,
204                        Standard_Integer& Bound1,
205                        Standard_Integer& Bound2,
206                        Standard_Boolean& DerNull)
207
208 {
209   Standard_Integer N=0;
210   Standard_Real Tol=Precision::PConfusion()/10;
211   Hunt(Arr,Coord,N);
212   DerNull=Standard_False;
213   
214   if(N==Bound1){ if(Abs(Der) > Tol) DerNull = Standard_False;
215                       if(Abs(Der)<= Tol) DerNull = Standard_True;
216                       Bound1=N;Bound2=N+1; return;
217                     }
218   if(N==Bound2){ if( Abs(Der) > Tol ) DerNull = Standard_False;
219                       if( Abs(Der)<= Tol ) DerNull = Standard_True;
220                       Bound1=N-1;Bound2=N; return;
221                     }
222   if((N!=Bound1)&&(N!=Bound2))  { 
223     if(Abs(Der) > Tol ) { 
224       if(Der>0) {Bound1=N;Bound2= N+1;}
225       else
226       if(Der<0){Bound1=N-1;Bound2=N;}
227       DerNull = Standard_False;
228     }
229     if(Abs(Der) <=Tol ) {
230       DerNull = Standard_True;
231       Bound1=N-1;
232       Bound2=N+1;
233     }
234   } 
235 }
236
237 //=======================================================================
238 //function :Locate1Coord
239 //purpose  : along BSpline curve
240 //=======================================================================
241
242 static void Locate1Coord(const Standard_Integer Index,
243                          const gp_Pnt2d& UV, 
244                          const gp_Vec2d& DUV,
245                          const Handle(Geom_BSplineCurve)& BSplC,
246                          gp_Pnt2d& LeftBot, gp_Pnt2d& RightTop)
247 {
248   Standard_Real Comp1=0, DComp1=0, cur, f = 0.0, l = 0.0;
249   Standard_Real Tol = Precision::PConfusion()/10;
250   Standard_Integer i = 1, Bnd1, Bnd2;
251   Standard_Boolean DIsNull= Standard_False; 
252   TColStd_Array1OfReal Arr(1,BSplC->NbKnots());  BSplC->Knots(Arr);
253   
254   if(Index==1) {    Comp1=UV.X();  DComp1=DUV.X(); } 
255   if(Index==2) {    Comp1=UV.Y();  DComp1=DUV.Y(); } 
256
257   Standard_Integer Lo = BSplC->FirstUKnotIndex(), Up = BSplC->LastUKnotIndex();
258
259   i = Lo;
260   while ( ( Abs(BSplC->Knot(i)-Comp1)>Tol )&& (i!=Up ) ) i++;
261   cur=BSplC->Knot(i);
262
263   if( Abs(Comp1-cur)<=Tol) {
264  
265     Bnd1 = Lo; Bnd2 = Up;
266     FindBounds(Arr,cur,DComp1,Bnd1,Bnd2,DIsNull); 
267     ReverseParam(Bnd1,Bnd2,Bnd1,Bnd2);
268     
269     if(DIsNull==Standard_False){
270       if(Index==1)  {LeftBot.SetX(BSplC->Knot(Bnd1));
271                      RightTop.SetX(BSplC->Knot(Bnd2));}
272       else 
273         if(Index==2){ LeftBot.SetY(BSplC->Knot(Bnd1));
274                       RightTop.SetY(BSplC->Knot(Bnd2)); }
275     }
276     else
277       if(DIsNull==Standard_True){
278         if( Abs( Comp1-(f=BSplC->Knot(Lo))) <= Tol)
279           {       
280             if(Index==1)   { LeftBot.SetX(BSplC->Knot(Lo));
281                              RightTop.SetX(BSplC->Knot(Lo+1));}
282             else if(Index==2)  { LeftBot.SetY(BSplC->Knot(Lo));
283                                  RightTop.SetY(BSplC->Knot(Lo+1));}
284            } else
285              if( Abs( Comp1-(l=BSplC->Knot(Up))) <= Tol)
286                {
287                  if(Index==1)   {  LeftBot.SetX(BSplC->Knot(Up-1));
288                                    RightTop.SetX(BSplC->Knot(Up));}
289                  else if(Index==2)  {LeftBot.SetY(BSplC->Knot(Up-1));
290                                      RightTop.SetY(BSplC->Knot(Up));}
291                }else
292                  if(Index==1)   {  LeftBot.SetX(BSplC->Knot(Bnd1));
293                                    RightTop.SetX(BSplC->Knot(Bnd2));}
294                  else if(Index==2)  {LeftBot.SetY(BSplC->Knot(Bnd1));
295                                      RightTop.SetY(BSplC->Knot(Bnd2));}
296       }
297   } 
298   else//*********if Coord != Knot
299     {
300       i=Lo;
301       while (i < Up) {
302         //if((f=BSplC->Knot(i))<Comp1 && (l=BSplC->Knot(i+1))>Comp1) break;
303         //skl 28.03.2002 for OCC233
304         f=BSplC->Knot(i);
305         l=BSplC->Knot(i+1);
306         if(f<Comp1 && l>Comp1) break;
307         i++; 
308       }
309       ReverseParam(f,l,f,l);
310      
311       if(i!=Up)   {
312         if(Abs(DComp1)<Tol) 
313           { if(Index==1) {LeftBot.SetX(f); RightTop.SetX(l);}else
314               if(Index==2) {LeftBot.SetY(f); RightTop.SetY(l); }
315           }else
316             if(Abs(DComp1)>Tol) 
317               { 
318                 if(Index==1) {
319                   if(DComp1>0) {LeftBot.SetX(Comp1); RightTop.SetX(l);}   else
320                     if(DComp1<0) {LeftBot.SetX(f); RightTop.SetX(Comp1);}
321                 }
322                 else
323                   if(Index==2) {
324                     if(DComp1>0) {LeftBot.SetY(Comp1); RightTop.SetY(l);} else
325                       if(DComp1<0) {LeftBot.SetY(f); RightTop.SetY(Comp1);};
326                   }
327               }
328       }else
329         if(i==Up)   {
330           if(Index==1) {LeftBot.SetX(Comp1); RightTop.SetX(BSplC->Knot(i));}else
331             if(Index==2) {LeftBot.SetY(Comp1); RightTop.SetY(BSplC->Knot(i)); }
332         }
333     }
334 }
335
336
337 //=======================================================================
338 //function :Locate1Coord
339 //purpose  : 
340 //=======================================================================
341
342 static void Locate1Coord(const Standard_Integer Index,
343         const gp_Pnt2d& UV, 
344         const gp_Vec2d& DUV,
345         const Handle(Geom_BSplineSurface)& BSplS,
346         Standard_Boolean& DIsNull,
347         gp_Pnt2d& LeftBot, 
348         gp_Pnt2d& RightTop)
349 {
350   Standard_Real Comp1=0,DComp1=0; 
351   Standard_Real Tol = Precision::PConfusion()/10;
352   Standard_Integer i=1, Up=0, Up1, Up2, Down=0, Down1, Down2;
353   Standard_Real cur = 0.;
354
355   DIsNull= Standard_False; 
356
357   Up1 =  BSplS->LastUKnotIndex();
358   Down1 = BSplS->FirstUKnotIndex();
359   Up2 =  BSplS->LastVKnotIndex();
360   Down2 = BSplS->FirstVKnotIndex();
361
362   if(Index==1)
363   { 
364     i = Down1; 
365     Comp1 =  UV.X(); 
366     DComp1= DUV.X(); 
367     Up=Up1; 
368     Down=Down1;
369
370     while ( ( Abs(BSplS->UKnot(i)-Comp1)>Tol )&&(i!=Up1 ) )
371     {
372       i++;
373     }
374
375     cur = BSplS->UKnot(i); 
376   }
377   else if(Index==2)
378   {
379     i = Down2;
380     Comp1 = UV.Y();
381     DComp1=DUV.Y();
382     Up=Up2;
383     Down=Down2;
384
385     while ( ( Abs(BSplS->VKnot(i)-Comp1)>Tol )&&(i!=Up2 ) )
386     {
387       i++;
388     }
389
390     cur = BSplS->VKnot(i);
391   }
392   
393   if( Abs(Comp1-cur)<=Tol ) 
394   { 
395     Standard_Integer Bnd1 = Down, Bnd2 = Up;
396     if(Index==1)
397     {
398       TColStd_Array1OfReal Arr1(1,BSplS->NbUKnots());
399       BSplS->UKnots(Arr1); //   Up1=Arr1.Upper(); Down1=Arr1.Lower();
400       FindBounds(Arr1,cur,DUV.X(),Bnd1,Bnd2,DIsNull); 
401     }
402     else if(Index==2)
403     {
404       TColStd_Array1OfReal Arr2(1,BSplS->NbVKnots());
405       BSplS->VKnots(Arr2); //   Up2=Arr2.Upper(); Down2=Arr2.Lower();
406       FindBounds(Arr2,cur,DUV.Y(),Bnd1,Bnd2,DIsNull); 
407     }
408     
409     ReverseParam(Bnd1,Bnd2,Bnd1,Bnd2);
410
411     if(DIsNull==Standard_False)
412     {
413       if(Index==1)
414       {
415         LeftBot.SetX(BSplS->UKnot(Bnd1));
416         RightTop.SetX(BSplS->UKnot(Bnd2));
417       }
418       else if(Index==2)
419       { 
420         LeftBot.SetY(BSplS->VKnot(Bnd1));
421         RightTop.SetY(BSplS->VKnot(Bnd2));
422       }
423     }      
424   }
425   else//*********if Coord != Knot
426   {
427     if( (Index==1)&&(Comp1 < BSplS->UKnot(Down)) )
428     { 
429       LeftBot.SetX(BSplS->UKnot(Down)); 
430       RightTop.SetX( BSplS->UKnot(Down + 1) );
431       return;
432     }
433     else if( (Index==2)&&(Comp1 < BSplS->VKnot(Down)) )
434     { 
435       LeftBot.SetY(BSplS->VKnot(Down)); 
436       RightTop.SetY( BSplS->VKnot(Down + 1) );
437       return;
438     }
439     else if( (Index==1)&&(Comp1 > BSplS->UKnot(Up)) )
440     { 
441       RightTop.SetX(BSplS->UKnot(Up - 1)); 
442       LeftBot.SetX( BSplS->UKnot(Up) );
443       return;
444     }
445     else if( (Index==2)&&(Comp1 > BSplS->VKnot(Up)) )
446     { 
447       RightTop.SetY(BSplS->VKnot(Up - 1)); 
448       LeftBot.SetY( BSplS->VKnot(Up) );
449       return;
450     } 
451     else
452     {
453       Standard_Real f = 0., l = 1.;
454       if (Index==1)
455       {
456         f=BSplS->UKnot(Down);
457         l=BSplS->UKnot(Up);
458       }
459       else if (Index == 2)
460       {
461         f=BSplS->VKnot(Down);
462         l=BSplS->VKnot(Up);
463       }
464
465       i = Down;
466       if ((!(Comp1 < f))&&(!(Comp1 > l)))
467       {
468         if (Index==1)
469         {
470           while (!(((f=BSplS->UKnot(i)) < Comp1)&&((l=BSplS->UKnot(i+1)) > Comp1)) && (i<Up)) 
471           {
472             i++;
473           }
474         }
475         else if (Index==2)
476         {
477           while (!(((f=BSplS->VKnot(i)) < Comp1)&&((l=BSplS->VKnot(i+1)) > Comp1)) && (i<Up)) 
478           {
479             i++;
480           }
481         }
482       }
483       else
484         ReverseParam(f,l,f,l);
485
486       if(i!=Up)
487       {
488         if(Abs(DComp1)>Tol)
489         {
490           if(Index==1) 
491           {  
492             if(DComp1>0)
493             { 
494               LeftBot.SetX(Comp1); 
495               RightTop.SetX(l);
496             }
497             else if(DComp1<0)
498             {
499               LeftBot.SetX(f); 
500               RightTop.SetX(Comp1);
501             }
502           }
503           else if(Index==2)
504           {
505             if(DComp1>0)
506             { 
507               LeftBot.SetY(Comp1); 
508               RightTop.SetY(l);
509             }
510             else if(DComp1<0)
511             { 
512               LeftBot.SetY(f); 
513               RightTop.SetY(Comp1);
514             }
515           }
516         }
517         else
518         {
519           if(Abs(DComp1)<Tol)
520           {
521             if(Index==1)
522             {
523               LeftBot.SetX(f); 
524               RightTop.SetX(l);
525             }
526             else if(Index==2) 
527             { 
528               LeftBot.SetY(f); 
529               RightTop.SetY(l);
530             }
531           }
532         }
533       } 
534       else if(i==Up)
535       {
536         if(Index==1)
537         {
538           LeftBot.SetX(Comp1);
539           RightTop.SetX(BSplS->UKnot(i));
540         }
541         else if(Index==2)
542         { 
543           LeftBot.SetY(Comp1); 
544           RightTop.SetY(BSplS->VKnot(i));
545         }
546       }
547     }
548   }
549 }
550 //=======================================================================
551 //function :Locate2Coord
552 //purpose  : along non-BSpline curve
553 //=======================================================================
554
555
556 static void Locate2Coord(const Standard_Integer Index,
557                          const gp_Pnt2d& UV, const gp_Vec2d& DUV, 
558                          const Standard_Real I1, 
559                          const Standard_Real I2,
560                          gp_Pnt2d& LeftBot, gp_Pnt2d& RightTop)
561 {
562   Standard_Real Tol=Precision::PConfusion()/10;
563   Standard_Real Comp1=0,DComp1=0;
564   if(Index==1)   {   Comp1=UV.X();
565                      DComp1=DUV.X();} 
566   else
567     if(Index==2)   {Comp1=UV.Y();
568                     DComp1=DUV.Y();}
569   
570   if((Comp1!=I1)&&(Comp1!=I2))
571     { if(Abs(DComp1) > Tol)
572         {  if(DComp1 < 0) 
573              {  if(Index==1) {  LeftBot.SetX(I1);
574                                 RightTop.SetX(Comp1);}
575                 if(Index==2) {  LeftBot.SetY(I1);
576                                 RightTop.SetY(Comp1);}
577               }
578         else
579           if(DComp1 > 0) 
580             {   if(Index==1) {  LeftBot.SetX(Comp1);
581                                 RightTop.SetX(I2);}
582                 if(Index==2) {  LeftBot.SetY(Comp1);
583                                 RightTop.SetY(I2);}
584               }
585           else { if(Index==1) { LeftBot.SetX(I1); 
586                                 RightTop.SetX(I2);}
587                  if(Index==2) { LeftBot.SetY(I1);
588                                 RightTop.SetY(I2);}
589                }
590          }
591     else 
592       if(Abs(DComp1)<=Tol) {
593                               if(Index==1) { LeftBot.SetX(I1) ;
594                                              RightTop.SetX(I2);}
595                               if(Index==2) { LeftBot.SetY(I1) ;
596                                              RightTop.SetY(I2);}
597                             }
598     }else 
599       if(Abs(Comp1-I1)<Tol)
600         { if(Index==1) { LeftBot.SetX(I1) ;
601                          RightTop.SetX(I2);}
602           if(Index==2) { LeftBot.SetY(I1) ;
603                          RightTop.SetY(I2);}
604         }
605       else
606         if(Abs(Comp1-I2)<Tol)
607           {        if(Index==1) { LeftBot.SetX(I1); 
608                                   RightTop.SetX(I2);}
609                    if(Index==2) { LeftBot.SetY(I1);
610                                   RightTop.SetY(I2);}
611                  } 
612 }
613
614 //=======================================================================
615 //function :Locate2Coord
616 //purpose  : 
617 //=======================================================================
618
619 static void Locate2Coord(const Standard_Integer Index,
620                          const gp_Pnt2d& UV, const gp_Vec2d& DUV, 
621                          const Handle(Geom_BSplineSurface)& BSplS,
622                          const TColStd_Array1OfReal& Arr,
623                          gp_Pnt2d& LeftBot, gp_Pnt2d& RightTop)
624 {
625   Standard_Real Comp=0,DComp=0,Tmp1=0.0,Tmp2=0.0;
626   Standard_Real Tol=Precision::PConfusion()/10;
627   Standard_Integer N=0, NUp=0, NLo=0;
628   if(Index==1)
629     { Comp=UV.X();
630       DComp=DUV.Y();
631       NUp = BSplS->LastUKnotIndex();
632       NLo = BSplS->FirstUKnotIndex();
633     }
634   if(Index==2)
635      { Comp=UV.Y();
636        DComp=DUV.X(); 
637        NUp = BSplS->LastVKnotIndex();
638        NLo = BSplS->FirstVKnotIndex();
639      }
640   
641   if((DComp > 0)&&(Abs(DComp)>Tol)) {  
642     Hunt(Arr,Comp,N);
643     if (N >= NUp){
644       //limit case: Hunt() cought upper knot. Take the last span. 
645       N = NUp - 1;
646     }
647     if(Index==1) {  Tmp1=BSplS->UKnot(N);
648                     Tmp2=BSplS->UKnot(N+1);}
649     else
650       if(Index==2) {      Tmp1=BSplS->VKnot(N);
651                           Tmp2=BSplS->VKnot(N+1);}
652     
653     ReverseParam(Tmp1,Tmp2,Tmp1,Tmp2);
654     
655     if(Index==1) {      LeftBot.SetX(Tmp1);
656                         RightTop.SetX(Tmp2);}
657     else
658       if(Index==2) {      LeftBot.SetY(Tmp1);
659                           RightTop.SetY(Tmp2);}
660     }
661   else
662     if((DComp < 0)&&(Abs(DComp)>Tol)){      
663      Hunt(Arr,Comp,N);
664      if (N <= NLo) {
665        //limit case: Hunt() cought lower knot. Take the first span.
666        N = NLo + 1;
667      }
668      if(Index==1) {       Tmp1=BSplS->UKnot(N-1);
669                           Tmp2=BSplS->UKnot(N);}
670         else
671           if(Index==2) { Tmp1=BSplS->VKnot(N-1);
672                          Tmp2=BSplS->VKnot(N);}
673      
674         ReverseParam(Tmp1,Tmp2,Tmp1,Tmp2);
675      
676         if(Index==1) {    LeftBot.SetX(Tmp1);
677                           RightTop.SetX(Tmp2);}
678         else
679           if(Index==2) {            LeftBot.SetY(Tmp1);
680                                     RightTop.SetY(Tmp2);}
681    } 
682 }
683
684
685
686 //=======================================================================
687 //function : Adaptor3d_CurveOnSurface
688 //purpose  : 
689 //=======================================================================
690
691 Adaptor3d_CurveOnSurface::Adaptor3d_CurveOnSurface()
692      : myType(GeomAbs_OtherCurve), myIntCont(GeomAbs_CN)
693 {}
694
695 //=======================================================================
696 //function : Adaptor3d_CurveOnSurface
697 //purpose  : 
698 //=======================================================================
699
700 Adaptor3d_CurveOnSurface::Adaptor3d_CurveOnSurface
701 (const Handle(Adaptor3d_Surface)& S) 
702      : myType(GeomAbs_OtherCurve), myIntCont(GeomAbs_CN)
703 {
704   Load(S);
705 }
706
707 //=======================================================================
708 //function : Adaptor3d_CurveOnSurface
709 //purpose  : 
710 //=======================================================================
711
712 Adaptor3d_CurveOnSurface::Adaptor3d_CurveOnSurface
713 (const Handle(Adaptor2d_Curve2d)& C,
714  const Handle(Adaptor3d_Surface)& S)
715      : myType(GeomAbs_OtherCurve), myIntCont(GeomAbs_CN)
716 {
717   Load(S);
718   Load(C);
719 }
720
721 //=======================================================================
722 //function : ShallowCopy
723 //purpose  : 
724 //=======================================================================
725
726 Handle(Adaptor3d_Curve) Adaptor3d_CurveOnSurface::ShallowCopy() const
727 {
728   Handle(Adaptor3d_CurveOnSurface) aCopy = new Adaptor3d_CurveOnSurface();
729
730   if (!mySurface.IsNull())
731   {
732     aCopy->mySurface = mySurface->ShallowCopy();
733   }
734   if (!myCurve.IsNull())
735   {
736     aCopy->myCurve = myCurve->ShallowCopy();
737   }
738   aCopy->myType      = myType;
739   aCopy->myCirc      = myCirc;
740   aCopy->myLin       = myLin;
741   if (!myFirstSurf.IsNull())
742   {
743     aCopy->myFirstSurf = myFirstSurf->ShallowCopy();
744   }
745   if (!myLastSurf.IsNull())
746   {
747     aCopy->myLastSurf = myLastSurf->ShallowCopy();
748   }
749   aCopy->myIntervals = myIntervals;
750   aCopy->myIntCont   = myIntCont;
751
752   return aCopy;
753 }
754
755 //=======================================================================
756 //function : Load
757 //purpose  : 
758 //=======================================================================
759
760 void Adaptor3d_CurveOnSurface::Load(const Handle(Adaptor3d_Surface)& S) 
761 {
762   mySurface = S;
763   if (!myCurve.IsNull()) EvalKPart();
764 }
765
766 //=======================================================================
767 //function : Load
768 //purpose  :
769 //=======================================================================
770
771 void Adaptor3d_CurveOnSurface::Load(const Handle(Adaptor2d_Curve2d)& C)
772 {
773   myCurve = C;
774   if (mySurface.IsNull())
775   {
776     return;
777   }
778
779   EvalKPart();
780
781   GeomAbs_SurfaceType SType = mySurface->GetType();
782   if (SType == GeomAbs_OffsetSurface)
783   {
784     SType = mySurface->BasisSurface()->GetType();
785   }
786
787   if (SType == GeomAbs_BSplineSurface ||  
788       SType == GeomAbs_SurfaceOfExtrusion ||
789       SType == GeomAbs_SurfaceOfRevolution)
790   {
791     EvalFirstLastSurf();
792   }
793 }
794
795 //=======================================================================
796 //function : Load
797 //purpose  : 
798 //=======================================================================
799
800 void Adaptor3d_CurveOnSurface::Load (const Handle(Adaptor2d_Curve2d)& C,
801                                      const Handle(Adaptor3d_Surface)& S) 
802 {
803   Load (C);
804   Load (S);
805 }
806
807 //=======================================================================
808 //function : FirstParameter
809 //purpose  : 
810 //=======================================================================
811
812 Standard_Real Adaptor3d_CurveOnSurface::FirstParameter() const 
813 {
814   return myCurve->FirstParameter();
815 }
816
817 //=======================================================================
818 //function : LastParameter
819 //purpose  : 
820 //=======================================================================
821
822 Standard_Real Adaptor3d_CurveOnSurface::LastParameter() const 
823 {
824   return myCurve->LastParameter();
825 }
826
827 //=======================================================================
828 //function : Continuity
829 //purpose  : 
830 //=======================================================================
831
832 GeomAbs_Shape Adaptor3d_CurveOnSurface::Continuity() const
833 {
834   GeomAbs_Shape ContC  = myCurve->Continuity();
835   GeomAbs_Shape ContSu = mySurface->UContinuity();
836   if ( ContSu < ContC) ContC = ContSu;
837   GeomAbs_Shape ContSv = mySurface->VContinuity();
838   if ( ContSv < ContC) ContC = ContSv;
839
840   return ContC;
841 }
842
843 // Auxiliary: adds roots of equation to sorted sequence of parameters
844 // along curve, keeping it sorted and avoiding repetitions (within tolerance Tol)
845 static void AddIntervals (const Handle(TColStd_HSequenceOfReal)& theParameters, 
846                           const math_FunctionRoots& theRoots, Standard_Real theTol)
847 {
848   if (! theRoots.IsDone() || theRoots.IsAllNull())
849     return;
850
851   Standard_Integer nsol = theRoots.NbSolutions();
852   for (Standard_Integer i = 1; i <= nsol; i++)
853   {
854     Standard_Real param = theRoots.Value(i);
855     if (param - theParameters->Value(1) < theTol) // skip param if equal to or less than theParameters(1)
856       continue;
857     for (Standard_Integer j=2; j <= theParameters->Length(); ++j)
858     {
859       Standard_Real aDelta = theParameters->Value(j) - param;
860       if (aDelta > theTol)
861       {
862         theParameters->InsertBefore (j, param);
863         break;
864       }
865       else if (aDelta >= -theTol) // param == theParameters(j) within Tol
866         break;
867     }
868   }
869 }
870
871 //=======================================================================
872 //function : NbIntervals
873 //purpose  : 
874 //=======================================================================
875
876 Standard_Integer Adaptor3d_CurveOnSurface::NbIntervals (const GeomAbs_Shape S) const
877 {
878   if(S == myIntCont && !myIntervals.IsNull())
879     return myIntervals->Length()-1;
880   
881   Standard_Integer nu,nv,nc;
882   nu=mySurface->NbUIntervals(S);
883   nv=mySurface->NbVIntervals(S);
884   nc=myCurve->NbIntervals(S);
885
886   // Allocate the memory for arrays TabU, TabV, TabC only once using the buffer TabBuf.
887   TColStd_Array1OfReal TabBuf(1, nu + nv + nc + 3);
888   TColStd_Array1OfReal TabU(TabBuf(1), 1, nu+1);
889   TColStd_Array1OfReal TabV(TabBuf(nu + 2), 1, nv+1);
890   TColStd_Array1OfReal TabC(TabBuf(nu + nv + 3), 1, nc+1);
891
892   Standard_Integer NbSample = 20;
893   Standard_Real U,V,Tdeb,Tfin;
894   Tdeb=myCurve->FirstParameter();
895   Tfin=myCurve->LastParameter();
896
897   myCurve->Intervals(TabC,S);
898
899   Standard_Real Tol= Precision::PConfusion()/10;
900
901   // sorted sequence of parameters defining continuity intervals;
902   // started with own intervals of curve and completed by 
903   // additional points coming from surface discontinuities
904   Handle(TColStd_HSequenceOfReal) aIntervals = new TColStd_HSequenceOfReal;
905   for (Standard_Integer i = 1; i <= nc + 1; i++)
906   {
907     aIntervals->Append(TabC(i));
908   }
909  
910   if (nu>1)
911   {
912     mySurface->UIntervals(TabU,S);
913     for(Standard_Integer iu = 2;iu <= nu; iu++)
914     {
915       U = TabU.Value(iu);
916       Adaptor3d_InterFunc Func(myCurve,U,1);
917       math_FunctionRoots Resol(Func,Tdeb,Tfin,NbSample,Tol,Tol,Tol,0.);
918       AddIntervals (aIntervals, Resol, Tol);
919     }
920   }
921   if (nv>1)
922   {
923     mySurface->VIntervals(TabV,S);
924     for(Standard_Integer iv = 2;iv <= nv; iv++)
925     {
926       V = TabV.Value(iv);
927       Adaptor3d_InterFunc Func(myCurve,V,2);
928       math_FunctionRoots Resol(Func,Tdeb,Tfin,NbSample,Tol,Tol,Tol,0.);
929       AddIntervals (aIntervals, Resol, Tol);
930     }
931   }
932
933   // for case intervals==1 and first point == last point SequenceOfReal
934   // contains only one value, therefore it is necessary to add second
935   // value into aIntervals which will be equal first value.
936   if (aIntervals->Length() == 1)
937     aIntervals->Append (aIntervals->Value(1));
938
939   const_cast<Adaptor3d_CurveOnSurface*>(this)->myIntervals = aIntervals;
940   const_cast<Adaptor3d_CurveOnSurface*>(this)->myIntCont = S;
941   return myIntervals->Length() - 1;
942 }
943
944 //=======================================================================
945 //function : Intervals
946 //purpose  : 
947 //=======================================================================
948
949 void Adaptor3d_CurveOnSurface::Intervals(TColStd_Array1OfReal& T,
950                                          const GeomAbs_Shape S) const
951 {
952   NbIntervals(S);
953   Standard_ASSERT_RAISE (T.Length() == myIntervals->Length(), "Error: Wrong size of array buffer in call to Adaptor3d_CurveOnSurface::Intervals");
954   for(Standard_Integer i=1; i<=myIntervals->Length(); i++) {
955     T(i) = myIntervals->Value(i);
956   }
957 }
958
959 //=======================================================================
960 //function : Trim
961 //purpose  : 
962 //=======================================================================
963
964 Handle(Adaptor3d_Curve) Adaptor3d_CurveOnSurface::Trim
965 (const Standard_Real First, 
966  const Standard_Real Last, 
967  const Standard_Real Tol) const 
968 {
969   Handle(Adaptor3d_CurveOnSurface) HCS = new Adaptor3d_CurveOnSurface();
970   HCS->Load(mySurface);
971   HCS->Load(myCurve->Trim(First,Last,Tol));
972   return HCS;
973 }
974
975 //=======================================================================
976 //function : IsClosed
977 //purpose  : 
978 //=======================================================================
979
980 Standard_Boolean Adaptor3d_CurveOnSurface::IsClosed() const
981 {
982   return myCurve->IsClosed();
983 }
984
985 //=======================================================================
986 //function : IsPeriodic
987 //purpose  : 
988 //=======================================================================
989
990 Standard_Boolean Adaptor3d_CurveOnSurface::IsPeriodic() const
991 {
992   if (myType == GeomAbs_Circle ||
993       myType == GeomAbs_Ellipse)
994     return Standard_True;
995   
996   return myCurve->IsPeriodic();
997 }
998
999 //=======================================================================
1000 //function : Period
1001 //purpose  : 
1002 //=======================================================================
1003
1004 Standard_Real Adaptor3d_CurveOnSurface::Period() const
1005 {
1006   if (myType == GeomAbs_Circle ||
1007       myType == GeomAbs_Ellipse)
1008     return (2.*M_PI);
1009   
1010   return myCurve->Period();
1011 }
1012
1013 //=======================================================================
1014 //function : Value
1015 //purpose  : 
1016 //=======================================================================
1017
1018 gp_Pnt Adaptor3d_CurveOnSurface::Value(const Standard_Real U ) const
1019 {
1020   gp_Pnt P;
1021   gp_Pnt2d Puv;
1022   
1023   if      (myType == GeomAbs_Line  ) P = ElCLib::Value(U,myLin );
1024   else if (myType == GeomAbs_Circle) P = ElCLib::Value(U,myCirc);
1025   else {
1026     myCurve->D0(U,Puv);
1027     mySurface->D0(Puv.X(),Puv.Y(),P);
1028   }
1029
1030   return P;
1031 }
1032
1033 //=======================================================================
1034 //function : D0
1035 //purpose  : 
1036 //=======================================================================
1037
1038 void Adaptor3d_CurveOnSurface::D0(const Standard_Real U ,
1039                                   gp_Pnt& P) const 
1040 {
1041   gp_Pnt2d Puv;
1042   
1043   if      (myType == GeomAbs_Line  ) P = ElCLib::Value(U,myLin );
1044   else if (myType == GeomAbs_Circle) P = ElCLib::Value(U,myCirc);
1045   else {
1046     myCurve->D0(U,Puv);
1047     mySurface->D0(Puv.X(),Puv.Y(),P);
1048   }
1049
1050 }
1051
1052
1053 //=======================================================================
1054 //function : D1
1055 //purpose  : 
1056 //=======================================================================
1057
1058 void Adaptor3d_CurveOnSurface::D1(const Standard_Real U ,
1059                                 gp_Pnt& P,
1060                                 gp_Vec& V) const 
1061 {
1062   gp_Pnt2d Puv;
1063   gp_Vec2d Duv;
1064   gp_Vec D1U,D1V;
1065   
1066   Standard_Real FP = myCurve->FirstParameter();
1067   Standard_Real LP = myCurve->LastParameter();
1068   
1069   Standard_Real Tol= Precision::PConfusion()/10; 
1070   if( ( Abs(U-FP)<Tol)&&(!myFirstSurf.IsNull()) )
1071     {
1072       myCurve->D1(U,Puv,Duv);
1073       myFirstSurf->D1(Puv.X(),Puv.Y(),P,D1U,D1V);
1074       V.SetLinearForm(Duv.X(),D1U,Duv.Y(),D1V);
1075     }
1076   else
1077     if( (Abs(U-LP)<Tol)&&(!myLastSurf.IsNull()) )
1078       {
1079         myCurve->D1(U,Puv,Duv);
1080         myLastSurf->D1(Puv.X(),Puv.Y(),P,D1U,D1V);
1081         V.SetLinearForm(Duv.X(),D1U,Duv.Y(),D1V);
1082       }
1083     else
1084       if      (myType == GeomAbs_Line  ) ElCLib::D1(U,myLin ,P,V);
1085       else if (myType == GeomAbs_Circle) ElCLib::D1(U,myCirc,P,V);
1086       else {
1087         myCurve->D1(U,Puv,Duv);
1088         mySurface->D1(Puv.X(),Puv.Y(),P,D1U,D1V);
1089         V.SetLinearForm(Duv.X(),D1U,Duv.Y(),D1V);
1090       }
1091 }
1092 //=======================================================================
1093 //function : D2
1094 //purpose  : 
1095 //=======================================================================
1096
1097 void Adaptor3d_CurveOnSurface::D2(const Standard_Real U,
1098                                 gp_Pnt& P,
1099                                 gp_Vec& V1,
1100                                 gp_Vec& V2) const
1101
1102   gp_Pnt2d UV;
1103   gp_Vec2d DW,D2W; 
1104   gp_Vec D1U,D1V,D2U,D2V,D2UV;
1105   
1106   Standard_Real FP = myCurve->FirstParameter();
1107   Standard_Real LP = myCurve->LastParameter();
1108   
1109   Standard_Real Tol= Precision::PConfusion()/10; 
1110   if( (Abs(U-FP)<Tol)&&(!myFirstSurf.IsNull()) )
1111     {
1112       myCurve->D2(U,UV,DW,D2W);
1113       myFirstSurf->D2(UV.X(),UV.Y(),P,D1U,D1V,D2U,D2V,D2UV);
1114       
1115       V1.SetLinearForm(DW.X(),D1U,DW.Y(),D1V);
1116       V2.SetLinearForm(D2W.X(), D1U, D2W.Y(), D1V, 2.*DW.X()*DW.Y(),D2UV);
1117       V2.SetLinearForm(DW.X()*DW.X(), D2U, DW.Y()*DW.Y(), D2V, V2);  
1118     }
1119   else  
1120     if( (Abs(U-LP)<Tol)&&(!myLastSurf.IsNull()) )
1121       {
1122         myCurve->D2(U,UV,DW,D2W);
1123         myLastSurf->D2(UV.X(),UV.Y(),P,D1U,D1V,D2U,D2V,D2UV);
1124         
1125         V1.SetLinearForm(DW.X(),D1U,DW.Y(),D1V);
1126         V2.SetLinearForm(D2W.X(), D1U, D2W.Y(), D1V, 2.*DW.X()*DW.Y(),D2UV);
1127         V2.SetLinearForm(DW.X()*DW.X(), D2U, DW.Y()*DW.Y(), D2V, V2);  
1128       }
1129     else
1130       if (myType == GeomAbs_Line  ) {
1131         ElCLib::D1(U,myLin,P,V1);
1132           V2.SetCoord(0.,0.,0.);
1133         }
1134       else if (myType == GeomAbs_Circle) ElCLib::D2(U,myCirc,P,V1,V2);
1135       else {
1136         myCurve->D2(U,UV,DW,D2W);
1137         mySurface->D2(UV.X(),UV.Y(),P,D1U,D1V,D2U,D2V,D2UV);
1138         
1139         V1.SetLinearForm(DW.X(),D1U,DW.Y(),D1V);
1140         V2.SetLinearForm(D2W.X(), D1U, D2W.Y(), D1V, 2.*DW.X()*DW.Y(),D2UV);
1141         V2.SetLinearForm(DW.X()*DW.X(), D2U, DW.Y()*DW.Y(), D2V, V2);  
1142       }
1143 }
1144
1145 //=======================================================================
1146 //function : D3
1147 //purpose  : 
1148 //=======================================================================
1149
1150 void Adaptor3d_CurveOnSurface::D3
1151   (const Standard_Real U,
1152    gp_Pnt& P,
1153    gp_Vec& V1,
1154    gp_Vec& V2,
1155    gp_Vec& V3) const
1156
1157   
1158   Standard_Real Tol= Precision::PConfusion()/10; 
1159   gp_Pnt2d UV;
1160   gp_Vec2d DW,D2W,D3W;
1161   gp_Vec D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV;
1162   
1163   Standard_Real FP = myCurve->FirstParameter();
1164   Standard_Real LP = myCurve->LastParameter();
1165   
1166   if( (Abs(U-FP)<Tol)&&(!myFirstSurf.IsNull()) )
1167     { myCurve->D3(U,UV,DW,D2W,D3W);
1168       myFirstSurf->D3(UV.X(),UV.Y(),P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
1169       V1.SetLinearForm(DW.X(),D1U,DW.Y(),D1V);
1170       V2.SetLinearForm(D2W.X(), D1U, D2W.Y(), D1V, 2.*DW.X()*DW.Y(),D2UV);
1171       V2.SetLinearForm(DW.X()*DW.X(), D2U, DW.Y()*DW.Y(), D2V, V2); 
1172       V3=SetLinearForm( DW, D2W, D3W, D1U, D1V, D2U, D2V, D2UV, D3U, D3V, D3UUV, D3UVV);
1173     }else
1174       
1175       if( (Abs(U-LP)<Tol)&&(!myLastSurf.IsNull()) )
1176         { myCurve->D3(U,UV,DW,D2W,D3W);
1177           myLastSurf->D3(UV.X(),UV.Y(),P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
1178           V1.SetLinearForm(DW.X(),D1U,DW.Y(),D1V);
1179           
1180           V2.SetLinearForm(D2W.X(), D1U, D2W.Y(), D1V, 2.*DW.X()*DW.Y(),D2UV);
1181           V2.SetLinearForm(DW.X()*DW.X(), D2U, DW.Y()*DW.Y(), D2V, V2);  
1182           V3=SetLinearForm( DW, D2W, D3W, D1U, D1V, D2U, D2V, D2UV, D3U, D3V, D3UUV, D3UVV);  
1183         }
1184       else
1185         if (myType == GeomAbs_Line  ) {
1186           ElCLib::D1(U,myLin,P,V1);
1187             V2.SetCoord(0.,0.,0.);
1188             V3.SetCoord(0.,0.,0.);
1189           }
1190         else if (myType == GeomAbs_Circle) ElCLib::D3(U,myCirc,P,V1,V2,V3);
1191         else {
1192           myCurve->D3(U,UV,DW,D2W,D3W);
1193           mySurface->D3(UV.X(),UV.Y(),P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
1194           V1.SetLinearForm(DW.X(),D1U,DW.Y(),D1V);
1195           
1196           V2.SetLinearForm(D2W.X(), D1U, D2W.Y(), D1V, 2.*DW.X()*DW.Y(),D2UV);
1197           V2.SetLinearForm(DW.X()*DW.X(), D2U, DW.Y()*DW.Y(), D2V, V2);  
1198           V3=SetLinearForm( DW, D2W, D3W, D1U, D1V, D2U, D2V, D2UV, D3U, D3V, D3UUV, D3UVV);  
1199         }
1200 }
1201
1202
1203 //=======================================================================
1204 //function : DN
1205 //purpose  : 
1206 //=======================================================================
1207
1208 gp_Vec Adaptor3d_CurveOnSurface::DN
1209   (const Standard_Real U, 
1210    const Standard_Integer N) const 
1211 {
1212   gp_Pnt P;
1213   gp_Vec V1, V2, V;
1214   switch (N) {
1215   case 1:
1216     D1(U,P,V);
1217     break ;
1218   case 2: 
1219     D2(U,P,V1,V);
1220     break ;
1221   case 3: 
1222     D3(U,P,V1,V2,V);
1223     break ;
1224   default:
1225     throw Standard_NotImplemented("Adaptor3d_CurveOnSurface:DN");
1226     break;
1227   }
1228   return V;
1229 }
1230
1231
1232 //=======================================================================
1233 //function : Resolution
1234 //purpose  : 
1235 //=======================================================================
1236
1237 Standard_Real Adaptor3d_CurveOnSurface::Resolution
1238   (const Standard_Real R3d) const
1239 {
1240   Standard_Real ru,rv;
1241   ru = mySurface->UResolution(R3d);
1242   rv = mySurface->VResolution(R3d);
1243   return myCurve->Resolution(Min(ru,rv)); 
1244 }
1245
1246
1247 //=======================================================================
1248 //function : GetType
1249 //purpose  : 
1250 //=======================================================================
1251
1252 GeomAbs_CurveType Adaptor3d_CurveOnSurface::GetType() const 
1253 {
1254   return myType;
1255
1256
1257
1258 //=======================================================================
1259 //function : Line
1260 //purpose  : 
1261 //=======================================================================
1262
1263 gp_Lin Adaptor3d_CurveOnSurface::Line() const
1264 {
1265   Standard_NoSuchObject_Raise_if(myType != GeomAbs_Line, "Adaptor3d_CurveOnSurface::Line(): curve is not a line")
1266   return myLin;
1267 }
1268
1269 //=======================================================================
1270 //function : Circle
1271 //purpose  : 
1272 //=======================================================================
1273
1274 gp_Circ Adaptor3d_CurveOnSurface::Circle() const
1275 {
1276   Standard_NoSuchObject_Raise_if(myType != GeomAbs_Circle, "Adaptor3d_CurveOnSurface::Line(): curve is not a circle")
1277   return myCirc;
1278 }
1279
1280 //=======================================================================
1281 //function : Ellipse
1282 //purpose  : 
1283 //=======================================================================
1284
1285 gp_Elips Adaptor3d_CurveOnSurface::Ellipse() const
1286 {
1287   return to3d(mySurface->Plane(),myCurve->Ellipse());
1288 }
1289
1290 //=======================================================================
1291 //function : Hyperbola
1292 //purpose  : 
1293 //=======================================================================
1294
1295 gp_Hypr Adaptor3d_CurveOnSurface::Hyperbola() const
1296 {
1297   return to3d(mySurface->Plane(),myCurve->Hyperbola());
1298 }
1299
1300 //=======================================================================
1301 //function : Parabola
1302 //purpose  : 
1303 //=======================================================================
1304
1305 gp_Parab Adaptor3d_CurveOnSurface::Parabola() const
1306 {
1307   return to3d(mySurface->Plane(),myCurve->Parabola());
1308 }
1309
1310 Standard_Integer  Adaptor3d_CurveOnSurface::Degree() const
1311 {
1312   
1313   // on a parametric surface should multiply
1314   // return TheCurve2dTool::Degree(myCurve);
1315
1316   return myCurve->Degree();
1317 }
1318
1319 //=======================================================================
1320 //function : IsRational
1321 //purpose  : 
1322 //=======================================================================
1323
1324 Standard_Boolean Adaptor3d_CurveOnSurface::IsRational() const
1325 {
1326   return ( myCurve->IsRational() ||
1327           mySurface->IsURational() ||
1328           mySurface->IsVRational()   );
1329 }
1330
1331 //=======================================================================
1332 //function : NbPoles
1333 //purpose  : 
1334 //=======================================================================
1335
1336 Standard_Integer  Adaptor3d_CurveOnSurface::NbPoles() const
1337 {
1338   // on a parametric surface should multiply
1339   return myCurve->NbPoles();
1340 }
1341
1342 //=======================================================================
1343 //function : NbKnots
1344 //purpose  : 
1345 //=======================================================================
1346
1347 Standard_Integer Adaptor3d_CurveOnSurface::NbKnots() const {
1348   if (mySurface->GetType()==GeomAbs_Plane)
1349     return myCurve->NbKnots();
1350   else {
1351     throw Standard_NoSuchObject();
1352   }
1353 }
1354
1355 //=======================================================================
1356 //function : Bezier
1357 //purpose  : 
1358 //=======================================================================
1359
1360 Handle(Geom_BezierCurve) Adaptor3d_CurveOnSurface::Bezier() const  
1361 {
1362   Standard_NoSuchObject_Raise_if
1363     ( mySurface->GetType() != GeomAbs_Plane,
1364      "Adaptor3d_CurveOnSurface : Bezier");
1365
1366   Handle(Geom2d_BezierCurve) Bez2d = myCurve->Bezier();
1367   Standard_Integer NbPoles = Bez2d->NbPoles();
1368
1369   const gp_Pln& Plane = mySurface->Plane();
1370
1371   TColgp_Array1OfPnt Poles(1,NbPoles);
1372   for ( Standard_Integer i=1; i<= NbPoles; i++) {
1373     Poles(i) = to3d( Plane, Bez2d->Pole(i));
1374   }
1375   Handle(Geom_BezierCurve) Bez;
1376
1377   if (Bez2d->IsRational()) {
1378     TColStd_Array1OfReal Weights(1,NbPoles);
1379     Bez2d->Weights(Weights);
1380     Bez = new Geom_BezierCurve(Poles,Weights);
1381   }
1382   else {
1383     Bez = new Geom_BezierCurve(Poles);
1384   }
1385   return Bez;
1386 }
1387
1388 //=======================================================================
1389 //function : BSpline
1390 //purpose  : 
1391 //=======================================================================
1392
1393 Handle(Geom_BSplineCurve) Adaptor3d_CurveOnSurface::BSpline() const  
1394 {
1395   Standard_NoSuchObject_Raise_if
1396     ( mySurface->GetType() != GeomAbs_Plane,
1397      "Adaptor3d_CurveOnSurface : BSpline");
1398
1399   Handle(Geom2d_BSplineCurve) Bsp2d = myCurve->BSpline();
1400   Standard_Integer NbPoles = Bsp2d->NbPoles();
1401
1402   const gp_Pln& Plane = mySurface->Plane();
1403
1404   TColgp_Array1OfPnt Poles(1,NbPoles);
1405   for ( Standard_Integer i=1; i<= NbPoles; i++) {
1406     Poles(i) = to3d( Plane, Bsp2d->Pole(i));
1407   }
1408
1409   TColStd_Array1OfReal    Knots(1,Bsp2d->NbKnots());
1410   TColStd_Array1OfInteger Mults(1,Bsp2d->NbKnots());
1411   Bsp2d->Knots(Knots);
1412   Bsp2d->Multiplicities(Mults);
1413
1414   Handle(Geom_BSplineCurve) Bsp;
1415
1416   if (Bsp2d->IsRational()) {
1417     TColStd_Array1OfReal Weights(1,NbPoles);
1418     Bsp2d->Weights(Weights);
1419     Bsp = new Geom_BSplineCurve(Poles,Weights,Knots,Mults,
1420                                 Bsp2d->Degree(),
1421                                 Bsp2d->IsPeriodic());
1422   }
1423   else {
1424     Bsp = new Geom_BSplineCurve(Poles,Knots,Mults,
1425                                 Bsp2d->Degree(),
1426                                 Bsp2d->IsPeriodic());
1427   }
1428   return Bsp;
1429 }
1430
1431 //=======================================================================
1432 //function : GetCurve
1433 //purpose  : 
1434 //=======================================================================
1435
1436 const Handle(Adaptor2d_Curve2d)& Adaptor3d_CurveOnSurface::GetCurve() const
1437 {
1438   return myCurve;
1439 }
1440
1441 //=======================================================================
1442 //function : GetSurface
1443 //purpose  : 
1444 //=======================================================================
1445
1446 const Handle(Adaptor3d_Surface)& Adaptor3d_CurveOnSurface::GetSurface() const 
1447 {
1448   return mySurface;
1449 }
1450
1451 //=======================================================================
1452 //function : ChangeCurve
1453 //purpose  : 
1454 //=======================================================================
1455
1456 Handle(Adaptor2d_Curve2d)& Adaptor3d_CurveOnSurface::ChangeCurve() 
1457 {
1458   return myCurve;
1459 }
1460
1461 //=======================================================================
1462 //function : ChangeSurface
1463 //purpose  : 
1464 //=======================================================================
1465
1466 Handle(Adaptor3d_Surface)& Adaptor3d_CurveOnSurface::ChangeSurface() {
1467   return mySurface;
1468 }
1469
1470 //=======================================================================
1471 //function : EvalKPart
1472 //purpose  : 
1473 //=======================================================================
1474
1475 void Adaptor3d_CurveOnSurface::EvalKPart()
1476 {
1477   myType = GeomAbs_OtherCurve;
1478
1479   GeomAbs_SurfaceType STy = mySurface->GetType();
1480   GeomAbs_CurveType   CTy = myCurve->GetType();
1481   if (STy == GeomAbs_Plane) {
1482     myType =  CTy;
1483     if (myType == GeomAbs_Circle) 
1484       myCirc = to3d(mySurface->Plane(),myCurve->Circle());
1485     else if (myType == GeomAbs_Line) {
1486       gp_Pnt P;
1487       gp_Vec V;
1488       gp_Pnt2d Puv;
1489       gp_Vec2d Duv;
1490       myCurve->D1(0.,Puv,Duv);
1491       gp_Vec D1U,D1V;
1492       mySurface->D1(Puv.X(),Puv.Y(),P,D1U,D1V);
1493       V.SetLinearForm(Duv.X(),D1U,Duv.Y(),D1V); 
1494       myLin = gp_Lin(P,V);
1495     }
1496   }
1497   else {
1498     if ( CTy == GeomAbs_Line) {
1499       gp_Dir2d D = myCurve->Line().Direction();
1500       if ( D.IsParallel(gp::DX2d(),Precision::Angular())) { // Iso V.
1501         if ( STy == GeomAbs_Sphere) {
1502           gp_Pnt2d  P    = myCurve->Line().Location();
1503           if ( Abs( Abs(P.Y()) -M_PI/2. ) >= Precision::PConfusion()) {
1504             myType = GeomAbs_Circle;
1505             gp_Sphere Sph  =  mySurface->Sphere();
1506             gp_Ax3    Axis = Sph.Position();
1507             myCirc   = ElSLib::SphereVIso(Axis,
1508                                           Sph.Radius(),
1509                                           P.Y());
1510             gp_Dir DRev = Axis.XDirection().Crossed(Axis.YDirection());
1511             gp_Ax1 AxeRev(Axis.Location(), DRev);
1512             myCirc.Rotate(AxeRev, P.X());
1513             if ( D.IsOpposite(gp::DX2d(),Precision::Angular())) {
1514               gp_Ax2 Ax = myCirc.Position();
1515               Ax.SetDirection(Ax.Direction().Reversed());
1516               myCirc.SetPosition(Ax);
1517             }
1518           }
1519         }
1520         else if ( STy == GeomAbs_Cylinder) {
1521           myType = GeomAbs_Circle;
1522           gp_Cylinder Cyl  = mySurface->Cylinder();
1523           gp_Pnt2d    P    = myCurve->Line().Location();
1524           gp_Ax3      Axis = Cyl.Position();
1525           myCirc           = ElSLib::CylinderVIso(Axis,
1526                                                   Cyl.Radius(),
1527                                                   P.Y());
1528           gp_Dir DRev = Axis.XDirection().Crossed(Axis.YDirection());
1529           gp_Ax1 AxeRev(Axis.Location(), DRev);
1530           myCirc.Rotate(AxeRev, P.X());
1531           if ( D.IsOpposite(gp::DX2d(),Precision::Angular())) {
1532             gp_Ax2 Ax = myCirc.Position();
1533             Ax.SetDirection(Ax.Direction().Reversed());
1534             myCirc.SetPosition(Ax);
1535           }
1536         }
1537         else if ( STy == GeomAbs_Cone) {
1538           myType = GeomAbs_Circle;
1539           gp_Cone  Cone = mySurface->Cone();
1540           gp_Pnt2d P    = myCurve->Line().Location();
1541           gp_Ax3   Axis = Cone.Position();
1542           myCirc        = ElSLib::ConeVIso(Axis,
1543                                            Cone.RefRadius(),
1544                                            Cone.SemiAngle(),
1545                                            P.Y());
1546           gp_Dir DRev = Axis.XDirection().Crossed(Axis.YDirection());
1547           gp_Ax1 AxeRev(Axis.Location(), DRev);
1548           myCirc.Rotate(AxeRev, P.X());
1549           if ( D.IsOpposite(gp::DX2d(),Precision::Angular())) {
1550             gp_Ax2 Ax = myCirc.Position();
1551             Ax.SetDirection(Ax.Direction().Reversed());
1552             myCirc.SetPosition(Ax);
1553           }
1554         }
1555         else if ( STy == GeomAbs_Torus) {
1556           myType = GeomAbs_Circle;
1557           gp_Torus Tore = mySurface->Torus();
1558           gp_Pnt2d P    = myCurve->Line().Location();
1559           gp_Ax3   Axis = Tore.Position();
1560           myCirc        = ElSLib::TorusVIso(Axis,
1561                                             Tore.MajorRadius(),
1562                                             Tore.MinorRadius(),
1563                                             P.Y());
1564           gp_Dir DRev = Axis.XDirection().Crossed(Axis.YDirection());
1565           gp_Ax1 AxeRev(Axis.Location(), DRev);
1566           myCirc.Rotate(AxeRev, P.X());
1567           if ( D.IsOpposite(gp::DX2d(),Precision::Angular())) {
1568             gp_Ax2 Ax = myCirc.Position();
1569             Ax.SetDirection(Ax.Direction().Reversed());
1570             myCirc.SetPosition(Ax);
1571           }
1572         }
1573       }
1574       else if ( D.IsParallel(gp::DY2d(),Precision::Angular())) { // Iso U.
1575         if ( STy == GeomAbs_Sphere) {
1576           myType = GeomAbs_Circle;
1577           gp_Sphere Sph  = mySurface->Sphere();
1578           gp_Pnt2d  P    = myCurve->Line().Location();
1579           gp_Ax3    Axis = Sph.Position();
1580           // calcul de l'iso 0.
1581           myCirc         = ElSLib::SphereUIso(Axis, Sph.Radius(),0.);
1582
1583           // mise a sameparameter (rotation du cercle - decalage du Y)
1584           gp_Dir DRev = Axis.XDirection().Crossed(Axis. Direction());
1585           gp_Ax1 AxeRev(Axis.Location(),DRev);
1586           myCirc.Rotate(AxeRev, P.Y());
1587
1588           // transformation en iso U ( = P.X())
1589           DRev = Axis.XDirection().Crossed(Axis.YDirection());
1590           AxeRev = gp_Ax1(Axis.Location(), DRev);
1591           myCirc.Rotate(AxeRev, P.X());
1592           
1593           if ( D.IsOpposite(gp::DY2d(),Precision::Angular())) {
1594             gp_Ax2 Ax = myCirc.Position();
1595             Ax.SetDirection(Ax.Direction().Reversed());
1596             myCirc.SetPosition(Ax);
1597           }
1598         }
1599         else if ( STy == GeomAbs_Cylinder) {
1600           myType = GeomAbs_Line;
1601           gp_Cylinder Cyl = mySurface->Cylinder();
1602           gp_Pnt2d    P   = myCurve->Line().Location();
1603           myLin           = ElSLib::CylinderUIso(Cyl.Position(),
1604                                                  Cyl.Radius(),
1605                                                  P.X());
1606           gp_Vec Tr(myLin.Direction());
1607           Tr.Multiply(P.Y());
1608           myLin.Translate(Tr);
1609           if ( D.IsOpposite(gp::DY2d(),Precision::Angular()))
1610             myLin.Reverse();
1611         }
1612         else if ( STy == GeomAbs_Cone) {
1613           myType = GeomAbs_Line;
1614           gp_Cone  Cone = mySurface->Cone();
1615           gp_Pnt2d P    = myCurve->Line().Location();
1616           myLin         = ElSLib::ConeUIso(Cone.Position(),
1617                                            Cone.RefRadius(),
1618                                            Cone.SemiAngle(),
1619                                            P.X());
1620           gp_Vec Tr(myLin.Direction());
1621           Tr.Multiply(P.Y());
1622           myLin.Translate(Tr);    
1623           if ( D.IsOpposite(gp::DY2d(),Precision::Angular()))
1624             myLin.Reverse();
1625         }
1626         else if ( STy == GeomAbs_Torus) {
1627           myType = GeomAbs_Circle;
1628           gp_Torus Tore = mySurface->Torus();
1629           gp_Pnt2d P    = myCurve->Line().Location();
1630           gp_Ax3   Axis = Tore.Position();
1631           myCirc        = ElSLib::TorusUIso(Axis,
1632                                             Tore.MajorRadius(),
1633                                             Tore.MinorRadius(),
1634                                             P.X());
1635           myCirc.Rotate(myCirc.Axis(),P.Y());
1636           
1637           if ( D.IsOpposite(gp::DY2d(),Precision::Angular())) {
1638             gp_Ax2 Ax = myCirc.Position();
1639             Ax.SetDirection(Ax.Direction().Reversed());
1640             myCirc.SetPosition(Ax);
1641           }
1642         }
1643       }
1644     }
1645   }
1646 }
1647 //=======================================================================
1648 //function :EvalFirstLastSurf 
1649 //purpose  : 
1650 //=======================================================================
1651
1652 void Adaptor3d_CurveOnSurface::EvalFirstLastSurf()
1653
1654   Standard_Real FirstPar,LastPar;
1655   gp_Pnt2d UV, LeftBot, RightTop;
1656   gp_Vec2d DUV;
1657   Standard_Real Tol= Precision::PConfusion()/10;
1658   Standard_Boolean Ok = Standard_True;
1659   
1660   
1661   FirstPar=myCurve->FirstParameter();
1662   myCurve->D1(FirstPar,UV,DUV);
1663
1664   if(DUV.Magnitude() <= Tol) Ok = Standard_False;
1665
1666   if(Ok) {
1667
1668     switch(mySurface->GetType()) {
1669     case GeomAbs_BSplineSurface :
1670       LocatePart(UV,DUV,mySurface,LeftBot,RightTop);
1671       break;
1672     case GeomAbs_SurfaceOfRevolution :
1673     case  GeomAbs_SurfaceOfExtrusion :  
1674       Ok = LocatePart_RevExt(UV,DUV,mySurface,LeftBot,RightTop);
1675       break;
1676     case GeomAbs_OffsetSurface :
1677       Ok = LocatePart_Offset(UV,DUV,mySurface,LeftBot,RightTop);
1678       break;
1679       default :
1680         throw Standard_NotImplemented("Adaptor3d_CurveOnSurface::EvalFirstLastSurf");
1681       break;
1682     }
1683   }
1684
1685   if (Ok) {
1686
1687     CompareBounds(LeftBot,RightTop); //SVV
1688     
1689     myFirstSurf = mySurface->UTrim(LeftBot.X(),RightTop.X(),Tol);
1690     myFirstSurf = myFirstSurf->VTrim(LeftBot.Y(),RightTop.Y(),Tol);
1691
1692   }
1693   else {
1694     myFirstSurf = mySurface;
1695   }
1696   
1697   LastPar=myCurve->LastParameter();
1698   Ok = Standard_True;
1699   myCurve->D1(LastPar,UV,DUV);
1700   DUV.Reverse(); //We want the other part
1701
1702   if(DUV.Magnitude() <= Tol) Ok = Standard_False;
1703
1704   if(Ok) {
1705
1706     switch(mySurface->GetType()) {
1707     case GeomAbs_BSplineSurface :
1708       LocatePart(UV,DUV,mySurface,LeftBot,RightTop);
1709       break;
1710     case GeomAbs_SurfaceOfRevolution :
1711     case  GeomAbs_SurfaceOfExtrusion :  
1712       Ok = LocatePart_RevExt(UV,DUV,mySurface,LeftBot,RightTop);
1713       break;
1714     case GeomAbs_OffsetSurface :
1715       Ok = LocatePart_Offset(UV,DUV,mySurface,LeftBot,RightTop);
1716       break;
1717       default :
1718         throw Standard_NotImplemented("Adaptor3d_CurveOnSurface::EvalFirstLastSurf");
1719       break;
1720     }
1721   }
1722
1723   if (Ok) {
1724
1725     CompareBounds(LeftBot, RightTop); //SVV
1726
1727     myLastSurf = mySurface->UTrim(LeftBot.X(),RightTop.X(),Tol);
1728     myLastSurf = myLastSurf->VTrim(LeftBot.Y(),RightTop.Y(),Tol);
1729
1730   }
1731   else {
1732     myLastSurf = mySurface;
1733   }
1734 }
1735
1736 //=======================================================================
1737 //function :LocatePart_RevExt
1738 //purpose  : processes Knots 
1739 //=======================================================================
1740
1741 Standard_Boolean Adaptor3d_CurveOnSurface::LocatePart_RevExt(const gp_Pnt2d& UV, 
1742                                                            const gp_Vec2d& DUV,
1743                                                            const Handle(Adaptor3d_Surface)& S,
1744                                                            gp_Pnt2d& LeftBot, 
1745                                                            gp_Pnt2d& RightTop) const
1746
1747   Handle(Adaptor3d_Curve) AHC = S->BasisCurve();
1748
1749   if (AHC->GetType() == GeomAbs_BSplineCurve) {
1750     Handle( Geom_BSplineCurve) BSplC;
1751     BSplC = AHC->BSpline();
1752  
1753     if((S->GetType())==GeomAbs_SurfaceOfExtrusion) { 
1754       Locate1Coord(1,UV,DUV,BSplC,LeftBot,RightTop);
1755       Locate2Coord(2,UV,DUV,S->FirstVParameter(),S->LastVParameter(),LeftBot,RightTop); 
1756     }
1757     else if((S->GetType())==GeomAbs_SurfaceOfRevolution)  { 
1758       Locate1Coord(2,UV,DUV,BSplC,LeftBot,RightTop);
1759       Locate2Coord(1,UV,DUV,S->FirstUParameter(),S->LastUParameter(),LeftBot,RightTop);
1760     } 
1761
1762     Standard_Real u1,u2,v1,v2;
1763     ReverseParam(LeftBot.X(),RightTop.X(),u1,u2);
1764     LeftBot.SetX(u1);
1765     RightTop.SetX(u2);
1766     ReverseParam(LeftBot.Y(),RightTop.Y(),v1,v2);
1767     LeftBot.SetY(v1);
1768     RightTop.SetY(v2);
1769     return Standard_True;
1770   }
1771   return Standard_False;
1772 }
1773
1774 //=======================================================================
1775 //function :LocatePart_OffsetSurface
1776 //purpose  : 
1777 //=======================================================================
1778
1779 Standard_Boolean Adaptor3d_CurveOnSurface::
1780    LocatePart_Offset(const gp_Pnt2d& UV, const gp_Vec2d& DUV,
1781                      const Handle(Adaptor3d_Surface)& S,
1782                      gp_Pnt2d& LeftBot, gp_Pnt2d& RightTop) const
1783 {
1784   Standard_Boolean Ok = Standard_True;
1785   Handle( Adaptor3d_Surface) AHS;
1786   Handle( Geom_BSplineSurface) BSplS;
1787   AHS = S->BasisSurface();
1788   GeomAbs_SurfaceType  BasisSType = AHS->GetType();
1789   switch(BasisSType) {
1790   case GeomAbs_SurfaceOfRevolution:
1791   case GeomAbs_SurfaceOfExtrusion :
1792     Ok = LocatePart_RevExt(UV,DUV,AHS,LeftBot,RightTop);
1793     break;
1794       
1795   case GeomAbs_BSplineSurface:
1796     LocatePart(UV,DUV,AHS,LeftBot,RightTop);
1797     break;
1798
1799     default : 
1800       Ok=Standard_False;
1801   }
1802   return Ok;
1803 }
1804
1805 //=======================================================================
1806 //function :LocatePart
1807 //purpose  : for BSplineSurface
1808 //=======================================================================
1809
1810 void Adaptor3d_CurveOnSurface::LocatePart(const gp_Pnt2d& UV, const gp_Vec2d& DUV,
1811                                         const Handle(Adaptor3d_Surface)& S,
1812                                         gp_Pnt2d& LeftBot, gp_Pnt2d& RightTop) const
1813 {
1814   Handle( Geom_BSplineSurface) BSplS;
1815   BSplS = S->BSpline();
1816   Standard_Boolean  DUIsNull=Standard_False,
1817   DVIsNull=Standard_False;
1818       
1819   Locate1Coord(1,UV,DUV,BSplS,DUIsNull,LeftBot,RightTop);
1820   Locate1Coord(2,UV,DUV,BSplS,DVIsNull,LeftBot,RightTop); 
1821   
1822   if((DUIsNull==Standard_True)&&(DVIsNull==Standard_False)) {
1823     TColStd_Array1OfReal ArrU(1,BSplS->NbUKnots());
1824     BSplS->UKnots(ArrU);
1825     Locate2Coord(1,UV,DUV,BSplS,ArrU,LeftBot,RightTop); 
1826   }
1827   else if((DVIsNull==Standard_True)&&(DUIsNull==Standard_False)) {
1828     TColStd_Array1OfReal ArrV(1,BSplS->NbVKnots());
1829     BSplS->VKnots(ArrV);
1830     Locate2Coord(2,UV,DUV,BSplS,ArrV,LeftBot,RightTop);
1831     }
1832 }
1833
1834
1835