79f0190c31e5d113f04aee7cf5f760cd4709897e
[occt.git] / src / BinTools / BinTools_CurveSet.cxx
1 // Created on: 2004-05-20
2 // Created by: Sergey ZARITCHNY
3 // Copyright (c) 2004-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <BinTools_CurveSet.ixx>
17 #include <BinTools.hxx>
18 #include <Geom_Circle.hxx>
19 #include <Geom_Line.hxx>
20 #include <Geom_Ellipse.hxx>
21 #include <Geom_Parabola.hxx>
22 #include <Geom_Hyperbola.hxx>
23 #include <Geom_BezierCurve.hxx>
24 #include <Geom_BSplineCurve.hxx>
25 #include <Geom_TrimmedCurve.hxx>
26 #include <Geom_OffsetCurve.hxx>
27
28 #include <gp_Lin.hxx>
29 #include <gp_Circ.hxx>
30 #include <gp_Elips.hxx>
31 #include <gp_Parab.hxx>
32 #include <gp_Hypr.hxx>
33
34 #include <TColStd_Array1OfReal.hxx>
35 #include <TColStd_Array1OfInteger.hxx>
36 #include <TColgp_Array1OfPnt.hxx>
37 #include <Standard_Failure.hxx>
38 #include <Standard_ErrorHandler.hxx>
39
40 #define LINE      1
41 #define CIRCLE    2
42 #define ELLIPSE   3
43 #define PARABOLA  4
44 #define HYPERBOLA 5
45 #define BEZIER    6
46 #define BSPLINE   7
47 #define TRIMMED   8
48 #define OFFSET    9
49
50 //=======================================================================
51 //function : BinTools_CurveSet
52 //purpose  : 
53 //=======================================================================
54
55 BinTools_CurveSet::BinTools_CurveSet() 
56 {
57 }
58
59
60 //=======================================================================
61 //function : Clear
62 //purpose  : 
63 //=======================================================================
64
65 void  BinTools_CurveSet::Clear()
66 {
67   myMap.Clear();
68 }
69
70
71 //=======================================================================
72 //function : Add
73 //purpose  : 
74 //=======================================================================
75
76 Standard_Integer  BinTools_CurveSet::Add(const Handle(Geom_Curve)& C)
77 {
78   return  (C.IsNull()) ? 0 : myMap.Add(C);
79 }
80
81
82 //=======================================================================
83 //function : Curve
84 //purpose  : 
85 //=======================================================================
86
87 Handle(Geom_Curve)  BinTools_CurveSet::Curve
88        (const Standard_Integer I)const 
89 {
90   if  (I == 0) {
91         Handle(Geom_Curve) dummy;
92         return dummy;
93   }
94   else
95     return Handle(Geom_Curve)::DownCast(myMap(I));
96 }
97
98
99 //=======================================================================
100 //function : Index
101 //purpose  : 
102 //=======================================================================
103
104 Standard_Integer  BinTools_CurveSet::Index
105   (const Handle(Geom_Curve)& S)const 
106 {
107   return S.IsNull() ? 0 : myMap.FindIndex(S);
108 }
109
110
111 //=======================================================================
112 //function : operator << (gp_Pnt)
113 //purpose  : 
114 //=======================================================================
115
116 static Standard_OStream& operator <<(Standard_OStream& OS, const gp_Pnt P)
117 {
118   BinTools::PutReal(OS, P.X());
119   BinTools::PutReal(OS, P.Y());
120   BinTools::PutReal(OS, P.Z());
121   return OS;
122 }
123
124 //=======================================================================
125 //function : operator << (gp_Dir)
126 //purpose  : 
127 //=======================================================================
128
129 static Standard_OStream& operator <<(Standard_OStream& OS, const gp_Dir D)
130 {
131   BinTools::PutReal(OS, D.X());
132   BinTools::PutReal(OS, D.Y());
133   BinTools::PutReal(OS, D.Z());
134   return OS;
135 }
136
137
138 //=======================================================================
139 //function : operator << (Geom_Line)
140 //purpose  : 
141 //=======================================================================
142
143 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_Line)& L)
144 {
145   OS << (Standard_Byte)LINE;
146   gp_Lin C = L->Lin();
147   OS << C.Location();//Pnt
148   OS << C.Direction();//Dir
149   return OS;
150   
151 }
152
153 //=======================================================================
154 //function :  operator <<(Geom_Circle)
155 //purpose  : 
156 //=======================================================================
157
158 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_Circle)& CC)
159 {
160   OS << (Standard_Byte)CIRCLE;
161   gp_Circ C = CC->Circ();
162   OS << C.Location();
163   OS << C.Axis().Direction();
164   OS << C.XAxis().Direction();
165   OS << C.YAxis().Direction();
166   BinTools::PutReal(OS, C.Radius());
167   return OS;
168 }
169
170 //=======================================================================
171 //function : operator <<(Geom_Ellipse)
172 //purpose  : 
173 //=======================================================================
174
175 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_Ellipse)& E)
176 {
177   OS << (Standard_Byte)ELLIPSE;
178   gp_Elips C = E->Elips();
179   OS << C.Location();
180   OS << C.Axis().Direction();
181   OS << C.XAxis().Direction();
182   OS << C.YAxis().Direction();
183   BinTools::PutReal(OS, C.MajorRadius());
184   BinTools::PutReal(OS, C.MinorRadius());
185   return OS;  
186 }
187
188 //=======================================================================
189 //function : operator <<(Geom_Parabola)
190 //purpose  : 
191 //=======================================================================
192
193 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_Parabola)& P)
194 {
195   OS << (Standard_Byte)PARABOLA;
196   gp_Parab C = P->Parab();
197   OS << C.Location();
198   OS << C.Axis().Direction();
199   OS << C.XAxis().Direction();
200   OS << C.YAxis().Direction();
201   BinTools::PutReal(OS, C.Focal());
202   return OS;  
203 }
204
205 //=======================================================================
206 //function : operator <<(Geom_Hyperbola)
207 //purpose  : 
208 //=======================================================================
209
210 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_Hyperbola)& H)
211 {
212   OS << (Standard_Byte)HYPERBOLA;
213   gp_Hypr C = H->Hypr();
214   OS << C.Location();
215   OS << C.Axis().Direction();
216   OS << C.XAxis().Direction();
217   OS << C.YAxis().Direction();
218   BinTools::PutReal(OS, C.MajorRadius());
219   BinTools::PutReal(OS, C.MinorRadius());
220   return OS; 
221 }
222
223 //=======================================================================
224 //function : operator <<(Geom_BezierCurve)
225 //purpose  : 
226 //=======================================================================
227
228 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_BezierCurve)& B)
229 {
230   OS << (Standard_Byte)BEZIER;
231   Standard_Boolean aRational = B->IsRational() ? 1:0;
232   BinTools::PutBool(OS, aRational); //rational
233   // poles and weights
234   Standard_Integer i,aDegree = B->Degree(); 
235   BinTools::PutExtChar(OS, (Standard_ExtCharacter)aDegree); //<< Degree
236   for (i = 1; i <= aDegree+1; i++) {
237     OS << B->Pole(i); //Pnt
238     if (aRational)
239       BinTools::PutReal(OS, B->Weight(i));//Real
240   }
241   return OS;  
242 }
243
244 //=======================================================================
245 //function : operator <<(Geom_BSplineCurve)
246 //purpose  : 
247 //=======================================================================
248
249 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_BSplineCurve)& B)
250 {
251   OS << (Standard_Byte)BSPLINE;
252   Standard_Boolean aRational = B->IsRational() ? 1:0;
253   BinTools::PutBool(OS, aRational); //rational
254   Standard_Boolean aPeriodic = B->IsPeriodic() ? 1:0;
255   BinTools::PutBool(OS, aPeriodic); //periodic
256   // poles and weights
257   Standard_Integer i,aDegree,aNbPoles,aNbKnots;
258   aDegree = B->Degree();
259   aNbPoles = B->NbPoles();
260   aNbKnots = B->NbKnots();
261   BinTools::PutExtChar(OS, (Standard_ExtCharacter) aDegree);
262   BinTools::PutInteger(OS, aNbPoles);
263   BinTools::PutInteger(OS, aNbKnots);
264   for (i = 1; i <= aNbPoles; i++) {
265     OS << B->Pole(i); // Pnt
266     if (aRational)
267       BinTools::PutReal(OS, B->Weight(i));
268   }
269   
270   for (i = 1; i <= aNbKnots; i++) {
271     BinTools::PutReal(OS, B->Knot(i));
272     BinTools::PutInteger(OS, B->Multiplicity(i));
273   }  
274   return OS;
275 }
276
277 //=======================================================================
278 //function : operator <<(Geom_TrimmedCurve)
279 //purpose  : 
280 //=======================================================================
281
282 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_TrimmedCurve)& C)
283 {
284   OS << (Standard_Byte)TRIMMED;
285   BinTools::PutReal(OS, C->FirstParameter()); 
286   BinTools::PutReal(OS, C->LastParameter());
287   BinTools_CurveSet::WriteCurve(C->BasisCurve(),OS);
288   return OS; 
289 }
290
291 //=======================================================================
292 //function : operator <<(Geom_OffsetCurve)
293 //purpose  : 
294 //=======================================================================
295
296 static Standard_OStream& operator <<(Standard_OStream& OS, const Handle(Geom_OffsetCurve)& C)
297 {
298   OS << (Standard_Byte)OFFSET;
299   BinTools::PutReal(OS,C->Offset());//Offset 
300   OS << C->Direction();
301   BinTools_CurveSet::WriteCurve(C->BasisCurve(),OS);
302   return OS; 
303 }
304
305 //=======================================================================
306 //function : 
307 //purpose  : 
308 //=======================================================================
309
310 void BinTools_CurveSet::WriteCurve(const Handle(Geom_Curve)& C,
311                                     Standard_OStream& OS)
312 {
313   Standard_SStream aMsg;
314   Handle(Standard_Type) TheType = C->DynamicType();
315   try {
316     OCC_CATCH_SIGNALS
317     if ( TheType ==STANDARD_TYPE(Geom_Line)) {
318       OS << Handle(Geom_Line)::DownCast(C);
319     }
320     else if ( TheType ==  STANDARD_TYPE(Geom_Circle)) {
321       OS << Handle(Geom_Circle)::DownCast(C);
322     }
323     else if ( TheType == STANDARD_TYPE(Geom_Ellipse)) {
324       OS << Handle(Geom_Ellipse)::DownCast(C);
325     }
326     else if ( TheType == STANDARD_TYPE(Geom_Parabola)) {
327       OS << Handle(Geom_Parabola)::DownCast(C);
328     }
329     else if ( TheType == STANDARD_TYPE(Geom_Hyperbola)) {
330       OS << Handle(Geom_Hyperbola)::DownCast(C);
331     }
332     else if ( TheType == STANDARD_TYPE(Geom_BezierCurve)) {
333       OS << Handle(Geom_BezierCurve)::DownCast(C);
334     }
335     else if ( TheType == STANDARD_TYPE(Geom_BSplineCurve)) {
336       OS << Handle(Geom_BSplineCurve)::DownCast(C);
337     }
338     else if ( TheType == STANDARD_TYPE(Geom_TrimmedCurve)) {
339       OS << Handle(Geom_TrimmedCurve)::DownCast(C);
340     }
341     else if ( TheType == STANDARD_TYPE(Geom_OffsetCurve)) {
342       OS << Handle(Geom_OffsetCurve)::DownCast(C);
343     }
344     else {
345       aMsg << "UNKNOWN CURVE TYPE" <<endl;
346       Standard_Failure::Raise(aMsg);
347     }
348   }
349    catch(Standard_Failure) {
350      aMsg << "EXCEPTION in BinTools_CurveSet::WriteCurve(..)" << endl;
351      Handle(Standard_Failure) anExc = Standard_Failure::Caught();
352      aMsg << anExc << endl;
353      Standard_Failure::Raise(aMsg);
354    }  
355 }
356
357 //=======================================================================
358 //function : Write
359 //purpose  : 
360 //=======================================================================
361
362 void  BinTools_CurveSet::Write(Standard_OStream& OS)const 
363 {
364   Standard_Integer i, nbsurf = myMap.Extent();
365   OS << "Curves "<< nbsurf << "\n";
366   for (i = 1; i <= nbsurf; i++) {
367     WriteCurve(Handle(Geom_Curve)::DownCast(myMap(i)),OS);
368   }
369 }
370
371
372 //=======================================================================
373 //function : ReadPnt
374 //purpose  : 
375 //=======================================================================
376
377 static Standard_IStream& operator>>(Standard_IStream& IS, gp_Pnt& P)
378 {
379   Standard_Real X=0.,Y=0.,Z=0.;
380   BinTools::GetReal(IS, X);
381   BinTools::GetReal(IS, Y);
382   BinTools::GetReal(IS, Z);
383   P.SetCoord(X,Y,Z);
384   return IS;
385 }
386
387 //=======================================================================
388 //function : ReadDir
389 //purpose  : 
390 //=======================================================================
391
392 static Standard_IStream& operator>>(Standard_IStream& IS, gp_Dir& D)
393 {
394   Standard_Real X=0.,Y=0.,Z=0.;
395   BinTools::GetReal(IS, X);
396   BinTools::GetReal(IS, Y);
397   BinTools::GetReal(IS, Z);
398   D.SetCoord(X,Y,Z);
399   return IS;
400 }
401
402
403 //=======================================================================
404 //function : ReadCurve
405 //purpose  : 
406 //=======================================================================
407
408 static Standard_IStream& operator>>(Standard_IStream& IS,
409                                     Handle(Geom_Line)& L)
410 {
411   gp_Pnt P(0.,0.,0.);
412   gp_Dir AX(1.,0.,0.);
413   IS >> P >> AX;
414   L = new Geom_Line(P,AX);
415   return IS;
416 }
417
418 //=======================================================================
419 //function : ReadCurve
420 //purpose  : 
421 //=======================================================================
422
423 static Standard_IStream& operator>>(Standard_IStream& IS,
424                                     Handle(Geom_Circle)& C)
425 {
426   gp_Pnt P(0.,0.,0.);
427   gp_Dir A(1.,0.,0.),AX(1.,0.,0.),AY(1.,0.,0.);
428   Standard_Real R=0.;
429   IS >> P >> A >> AX >> AY;
430   BinTools::GetReal(IS, R);
431   C = new Geom_Circle(gp_Ax2(P,A,AX),R);
432   return IS;
433 }
434
435 //=======================================================================
436 //function : ReadCurve
437 //purpose  : 
438 //=======================================================================
439
440 static Standard_IStream& operator>>(Standard_IStream& IS,
441                                     Handle(Geom_Ellipse)& E)
442 {
443   gp_Pnt P(0.,0.,0.);
444   gp_Dir A(1.,0.,0.),AX(1.,0.,0.),AY(1.,0.,0.);
445   Standard_Real R1=0.,R2=0.;
446   IS >> P >> A >> AX >> AY;
447   BinTools::GetReal(IS, R1);
448   BinTools::GetReal(IS, R2);
449   E = new Geom_Ellipse(gp_Ax2(P,A,AX),R1,R2);
450   return IS;
451 }
452
453 //=======================================================================
454 //function : ReadCurve
455 //purpose  : 
456 //=======================================================================
457
458 static Standard_IStream& operator>>(Standard_IStream& IS,
459                                     Handle(Geom_Parabola)& C)
460 {
461   gp_Pnt P(0.,0.,0.);
462   gp_Dir A(1.,0.,0.),AX(1.,0.,0.),AY(1.,0.,0.);
463   Standard_Real R1=0.;
464   IS >> P >> A >> AX >> AY;
465   BinTools::GetReal(IS, R1);
466   C = new Geom_Parabola(gp_Ax2(P,A,AX),R1);
467   return IS;
468 }
469
470 //=======================================================================
471 //function : ReadCurve
472 //purpose  : 
473 //=======================================================================
474
475 static Standard_IStream& operator>>(Standard_IStream& IS,
476                                     Handle(Geom_Hyperbola)& H)
477 {
478   gp_Pnt P(0.,0.,0.);
479   gp_Dir A(1.,0.,0.),AX(1.,0.,0.),AY(1.,0.,0);
480   Standard_Real R1=0.,R2=0.;
481   IS >> P >> A >> AX >> AY;
482   BinTools::GetReal(IS, R1);
483   BinTools::GetReal(IS, R2);
484   H = new Geom_Hyperbola(gp_Ax2(P,A,AX),R1,R2);
485   return IS;
486 }
487
488 //=======================================================================
489 //function : ReadCurve
490 //purpose  : 
491 //=======================================================================
492
493 static Standard_IStream& operator>>(Standard_IStream& IS,
494                                     Handle(Geom_BezierCurve)& B)
495 {
496   Standard_Boolean rational=Standard_False;
497   BinTools::GetBool(IS, rational);
498
499 // poles and weights
500   Standard_Integer i=0,degree=0;
501 // degree;
502   Standard_ExtCharacter aVal='\0';
503   BinTools::GetExtChar(IS, aVal);
504   degree = (Standard_Integer)aVal;
505
506   TColgp_Array1OfPnt poles(1,degree+1);
507   TColStd_Array1OfReal weights(1,degree+1);
508   
509   for (i = 1; i <= degree+1; i++) {
510     IS >> poles(i);//Pnt
511     if (rational)
512 // weights(i);
513       BinTools::GetReal(IS, weights(i));
514   }
515
516   if (rational)
517     B = new Geom_BezierCurve(poles,weights);
518   else
519     B = new Geom_BezierCurve(poles);
520
521   return IS;
522 }
523
524 //=======================================================================
525 //function : ReadCurve
526 //purpose  : 
527 //=======================================================================
528
529 static Standard_IStream& operator>>(Standard_IStream& IS,
530                                     Handle(Geom_BSplineCurve)& B)
531 {
532
533   Standard_Boolean rational=Standard_False,periodic=Standard_False;
534   BinTools::GetBool(IS, rational);
535   BinTools::GetBool(IS, periodic);
536
537 // poles and weights
538   Standard_Integer i=0,degree=0,nbpoles=0,nbknots=0;
539   Standard_ExtCharacter aVal='\0';
540   BinTools::GetExtChar(IS, aVal);
541   degree = (Standard_Integer)aVal;
542
543   BinTools::GetInteger(IS, nbpoles);
544   
545   BinTools::GetInteger(IS, nbknots);
546
547   TColgp_Array1OfPnt poles(1,nbpoles);
548   TColStd_Array1OfReal weights(1,nbpoles);
549   
550   for (i = 1; i <= nbpoles; i++) {
551     IS >> poles(i);//Pnt
552     if (rational)
553       BinTools::GetReal(IS, weights(i));
554   }
555
556   TColStd_Array1OfReal knots(1,nbknots);
557   TColStd_Array1OfInteger mults(1,nbknots);
558
559   for (i = 1; i <= nbknots; i++) {
560     BinTools::GetReal(IS, knots(i));
561     BinTools::GetInteger(IS, mults(i));
562   }
563
564   if (rational)
565     B = new Geom_BSplineCurve(poles,weights,knots,mults,degree,periodic);
566   else
567     B = new Geom_BSplineCurve(poles,knots,mults,degree,periodic);
568   
569   return IS;
570 }
571
572 //=======================================================================
573 //function : ReadCurve
574 //purpose  : 
575 //=======================================================================
576
577 static Standard_IStream& operator>>(Standard_IStream& IS,
578                                     Handle(Geom_TrimmedCurve)& C)
579 {
580   Standard_Real p1=0.,p2=0.;
581   BinTools::GetReal(IS, p1);//FirstParameter
582   BinTools::GetReal(IS, p2);//LastParameter
583   Handle(Geom_Curve) BC;
584   BinTools_CurveSet::ReadCurve(IS,BC);
585   C = new Geom_TrimmedCurve(BC,p1,p2);
586   return IS;
587 }
588
589 //=======================================================================
590 //function : ReadCurve
591 //purpose  : 
592 //=======================================================================
593
594 static Standard_IStream& operator>>(Standard_IStream& IS,
595                                     Handle(Geom_OffsetCurve)& C)
596 {
597   Standard_Real p=0.;
598   BinTools::GetReal(IS, p);//Offset
599   gp_Dir D(1.,0.,0.);
600   IS >> D;
601   Handle(Geom_Curve) BC;
602   BinTools_CurveSet::ReadCurve(IS,BC);
603   C = new Geom_OffsetCurve(BC,p,D);
604   return IS;
605 }
606
607 //=======================================================================
608 //function : ReadCurve
609 //purpose  : 
610 //=======================================================================
611
612 Standard_IStream& BinTools_CurveSet::ReadCurve(Standard_IStream& IS,
613                                                 Handle(Geom_Curve)& C)
614 {
615   Standard_SStream aMsg;
616   try {
617     OCC_CATCH_SIGNALS
618     const Standard_Byte ctype = (Standard_Byte) IS.get();
619
620     switch (ctype) {
621
622     case LINE :
623       {
624         Handle(Geom_Line) CC;
625         IS >> CC;
626         C = CC;
627       }
628       break;
629
630     case CIRCLE :
631       {
632         Handle(Geom_Circle) CC;
633         IS >> CC;
634         C = CC;
635       }
636       break;
637
638     case ELLIPSE :
639       {
640         Handle(Geom_Ellipse) CC;
641         IS >> CC;
642         C = CC;
643       }
644       break;
645
646     case PARABOLA :
647       {
648         Handle(Geom_Parabola) CC;
649         IS >> CC;
650         C = CC;
651       }
652       break;
653
654     case HYPERBOLA :
655       {
656         Handle(Geom_Hyperbola) CC;
657         IS >> CC;
658         C = CC;
659       }
660       break;
661
662     case BEZIER :
663       {
664         Handle(Geom_BezierCurve) CC;
665         IS >> CC;
666         C = CC;
667       }
668       break;
669
670     case BSPLINE :
671       {
672         Handle(Geom_BSplineCurve) CC;
673         IS >> CC;
674         C = CC;
675       }
676       break;
677
678     case TRIMMED :
679       {
680         Handle(Geom_TrimmedCurve) CC;
681         IS >> CC;
682         C = CC;
683       }
684       break;
685
686     case OFFSET :
687       {
688         Handle(Geom_OffsetCurve) CC;
689         IS >> CC;
690         C = CC;
691       }
692       break;
693       
694     default:
695       {
696         C = NULL;
697         aMsg << "UNKNOWN CURVE TYPE" << endl;
698         Standard_Failure::Raise(aMsg);
699       }
700     }
701   }
702   catch(Standard_Failure) {
703     C = NULL;
704     aMsg <<"EXCEPTION in BinTools_CurveSet::ReadCurve(..)" << endl;
705     Handle(Standard_Failure) anExc = Standard_Failure::Caught();
706     Standard_Failure::Raise(aMsg);
707   }
708   return IS;
709 }
710
711 //=======================================================================
712 //function : Read
713 //purpose  : 
714 //=======================================================================
715
716 void  BinTools_CurveSet::Read(Standard_IStream& IS)
717 {
718   char buffer[255];
719   IS >> buffer;
720   if (IS.fail() || strcmp(buffer,"Curves")) {
721     Standard_SStream aMsg;
722     aMsg << "BinTools_CurveSet::Read:  Not a Curve table"<<endl;
723 #ifdef DEB
724     cout <<"CurveSet buffer: " << buffer << endl;
725 #endif
726     Standard_Failure::Raise(aMsg);
727     return;
728   }
729
730   Handle(Geom_Curve) C;
731   Standard_Integer i, nbcurve;
732   IS >> nbcurve;
733
734   IS.get();//remove <lf>
735   for (i = 1; i <= nbcurve; i++) {
736     BinTools_CurveSet::ReadCurve(IS,C);
737     myMap.Add(C);
738   }
739 }
740
741