0023178: Intersection of cylinders fails to produce results
[occt.git] / src / Geom2dConvert / Geom2dConvert.cxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 //Jean-Claude Vauthier Novembre 1991
16 //Passage sur C1 Aout 1992 et ajout transformation Bezier->BSpline
17
18 #include <BSplCLib.hxx>
19 #include <Convert_CircleToBSplineCurve.hxx>
20 #include <Convert_ConicToBSplineCurve.hxx>
21 #include <Convert_EllipseToBSplineCurve.hxx>
22 #include <Convert_HyperbolaToBSplineCurve.hxx>
23 #include <Convert_ParabolaToBSplineCurve.hxx>
24 #include <Geom2d_BezierCurve.hxx>
25 #include <Geom2d_BSplineCurve.hxx>
26 #include <Geom2d_Circle.hxx>
27 #include <Geom2d_Conic.hxx>
28 #include <Geom2d_Curve.hxx>
29 #include <Geom2d_Ellipse.hxx>
30 #include <Geom2d_Geometry.hxx>
31 #include <Geom2d_Hyperbola.hxx>
32 #include <Geom2d_Line.hxx>
33 #include <Geom2d_OffsetCurve.hxx>
34 #include <Geom2d_Parabola.hxx>
35 #include <Geom2d_TrimmedCurve.hxx>
36 #include <Geom2dConvert.hxx>
37 #include <Geom2dConvert_ApproxCurve.hxx>
38 #include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
39 #include <GeomAbs_Shape.hxx>
40 #include <gp.hxx>
41 #include <gp_Circ2d.hxx>
42 #include <gp_Dir2d.hxx>
43 #include <gp_Elips2d.hxx>
44 #include <gp_Hypr2d.hxx>
45 #include <gp_Lin.hxx>
46 #include <gp_Parab2d.hxx>
47 #include <gp_Pnt2d.hxx>
48 #include <gp_Trsf2d.hxx>
49 #include <gp_Vec2d.hxx>
50 #include <Hermit.hxx>
51 #include <PLib.hxx>
52 #include <Precision.hxx>
53 #include <Standard_ConstructionError.hxx>
54 #include <Standard_DomainError.hxx>
55 #include <Standard_OutOfRange.hxx>
56 #include <TColgp_Array1OfPnt2d.hxx>
57 #include <TColStd_Array1OfBoolean.hxx>
58 #include <TColStd_Array1OfInteger.hxx>
59 #include <TColStd_Array1OfReal.hxx>
60 #include <TColStd_HArray1OfReal.hxx>
61
62 typedef gp_Circ2d  Circ2d;
63 typedef gp_Elips2d Elips2d;
64 typedef gp_Hypr2d  Hypr2d;
65 typedef gp_Parab2d Parab2d;
66 typedef gp_Pnt2d   Pnt2d;
67 typedef gp_Trsf2d  Trsf2d;
68 typedef Geom2d_Curve                Curve;
69 typedef Geom2d_BSplineCurve         BSplineCurve;
70 typedef TColStd_Array1OfReal                 Array1OfReal;
71 typedef TColStd_Array1OfInteger              Array1OfInteger;
72 typedef TColgp_Array1OfPnt2d                 Array1OfPnt2d;
73
74 //=======================================================================
75 //function : BSplineCurveBuilder
76 //purpose  : 
77 //=======================================================================
78
79 static Handle(Geom2d_BSplineCurve) BSplineCurveBuilder (
80
81 const Handle(Geom2d_Conic)&                TheConic,
82 const Convert_ConicToBSplineCurve&  Convert
83 ) {
84
85    Handle(Geom2d_BSplineCurve) TheCurve;
86    Standard_Integer NbPoles = Convert.NbPoles();
87    Standard_Integer NbKnots = Convert.NbKnots();
88    Array1OfPnt2d   Poles   (1, NbPoles);
89    Array1OfReal    Weights (1, NbPoles);
90    Array1OfReal    Knots   (1, NbKnots);
91    Array1OfInteger Mults   (1, NbKnots);
92    Standard_Integer i;
93    for (i = 1; i <= NbPoles; i++) {
94      Poles   (i) = Convert.Pole (i);
95      Weights (i) = Convert.Weight (i);         
96    }
97    for (i = 1; i <= NbKnots; i++) {
98      Knots (i) = Convert.Knot (i);
99      Mults (i) = Convert.Multiplicity (i);
100    }
101    TheCurve = new BSplineCurve (
102                   Poles, Weights, Knots, Mults, 
103                   Convert.Degree(), Convert.IsPeriodic());
104
105    gp_Ax22d Axis = TheConic->Position();
106    if ( ( Axis.XDirection() ^ Axis.YDirection()) < 0.) {
107      // Then the axis is left-handed, apply a symetry to the curve.
108      gp_Trsf2d Sym;
109      Sym.SetMirror(gp::OX2d());
110      TheCurve->Transform(Sym);
111    }
112
113    Trsf2d T;
114    T.SetTransformation (TheConic->XAxis(), gp::OX2d());
115    Handle(Geom2d_BSplineCurve) Cres = 
116      Handle(Geom2d_BSplineCurve)::DownCast(TheCurve->Transformed (T));
117    return Cres;
118 }
119
120
121 //=======================================================================
122 //function : SplitBSplineCurve
123 //purpose  : 
124 //=======================================================================
125
126 Handle(Geom2d_BSplineCurve) Geom2dConvert::SplitBSplineCurve (
127
128 const Handle(Geom2d_BSplineCurve)& C,
129 const Standard_Integer               FromK1, 
130 const Standard_Integer               ToK2,
131 const Standard_Boolean               SameOrientation
132 ) {
133
134   Standard_Integer TheFirst = C->FirstUKnotIndex ();
135   Standard_Integer TheLast  = C->LastUKnotIndex  ();
136   if (FromK1 == ToK2)  Standard_DomainError::Raise();
137   Standard_Integer FirstK = Min (FromK1, ToK2);
138   Standard_Integer LastK  = Max (FromK1, ToK2);
139   if (FirstK < TheFirst || LastK > TheLast) Standard_OutOfRange::Raise();
140
141   Handle(Geom2d_BSplineCurve) NewCurve = Handle(Geom2d_BSplineCurve)::DownCast(C->Copy());
142
143   NewCurve->Segment(C->Knot(FirstK),C->Knot(LastK));
144
145   if (C->IsPeriodic()) {
146     if (!SameOrientation) NewCurve->Reverse();
147   }
148   else {
149     if (FromK1 > ToK2)    NewCurve->Reverse();
150   }
151   return NewCurve;
152 }
153
154
155 //=======================================================================
156 //function : SplitBSplineCurve
157 //purpose  : 
158 //=======================================================================
159
160 Handle(Geom2d_BSplineCurve) Geom2dConvert::SplitBSplineCurve (
161
162 const Handle(Geom2d_BSplineCurve)& C, 
163 const Standard_Real                  FromU1, 
164 const Standard_Real                  ToU2,
165 const Standard_Real, // ParametricTolerance,
166 const Standard_Boolean               SameOrientation
167
168 {
169   Standard_Real FirstU = Min( FromU1, ToU2);
170   Standard_Real LastU  = Max( FromU1, ToU2);
171   
172   Handle (Geom2d_BSplineCurve) C1 
173     = Handle(Geom2d_BSplineCurve)::DownCast(C->Copy());
174
175   C1->Segment(FirstU, LastU);
176
177   if (C->IsPeriodic()) {
178      if (!SameOrientation) C1->Reverse();
179    }
180   else {
181     if (FromU1 > ToU2)    C1->Reverse();
182   }
183
184   return C1;
185 }
186
187
188 //=======================================================================
189 //function : CurveToBSplineCurve
190 //purpose  : 
191 //=======================================================================
192
193 Handle(Geom2d_BSplineCurve)  Geom2dConvert::CurveToBSplineCurve (
194
195 const Handle(Geom2d_Curve)& C,
196 const Convert_ParameterisationType  Parameterisation) 
197 {
198     
199   Handle (BSplineCurve) TheCurve;
200     
201   if (C->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
202     Handle (Curve) Curv;
203     Handle(Geom2d_TrimmedCurve) Ctrim = Handle(Geom2d_TrimmedCurve)::DownCast(C);
204     Curv = Ctrim->BasisCurve();
205     Standard_Real U1 = Ctrim->FirstParameter();
206     Standard_Real U2 = Ctrim->LastParameter();
207
208     // Si la courbe n'est pas vraiment restreinte, on ne risque pas 
209     // le Raise dans le BS->Segment.
210     if (!Curv->IsPeriodic()) {     
211       if (U1 < Curv->FirstParameter())
212         U1 =  Curv->FirstParameter();
213       if (U2 > Curv->LastParameter())
214         U2 = Curv->LastParameter();
215     } 
216     
217     if (Curv->IsKind(STANDARD_TYPE(Geom2d_Line))) {
218       gp_Pnt2d Pdeb = Ctrim->StartPoint();
219       gp_Pnt2d Pfin = Ctrim->EndPoint();
220       Array1OfPnt2d Poles (1, 2);
221       Poles (1) = Pdeb;
222       Poles (2) = Pfin;
223       Array1OfReal Knots (1, 2);
224       Knots (1) = Ctrim->FirstParameter ();
225       Knots (2) = Ctrim->LastParameter();
226       Array1OfInteger Mults (1, 2);
227       Mults (1) = 2;
228       Mults (2) = 2;
229       Standard_Integer Degree = 1;
230       TheCurve = new Geom2d_BSplineCurve (Poles, Knots, Mults, Degree);
231     }
232     
233     else if (Curv->IsKind(STANDARD_TYPE(Geom2d_Circle))) {
234       Handle(Geom2d_Circle) TheConic= Handle(Geom2d_Circle)::DownCast(Curv);
235       Circ2d C2d (gp::OX2d(), TheConic->Radius());
236       if(Parameterisation != Convert_RationalC1) {
237         Convert_CircleToBSplineCurve Convert (C2d,
238                                               U1, 
239                                               U2, 
240                                               Parameterisation);
241         TheCurve = BSplineCurveBuilder (TheConic, Convert);
242       }
243       else {
244         if(U2 - U1 < 6.) {
245           Convert_CircleToBSplineCurve Convert (C2d, 
246                                                 U1, 
247                                                 U2, 
248                                                 Parameterisation);
249           TheCurve = BSplineCurveBuilder (TheConic, Convert);
250         }
251         else { // split circle to avoide numerical 
252                // overflow when U2 - U1 =~ 2*PI
253
254           Standard_Real Umed = (U1 + U2) * .5;
255           Convert_CircleToBSplineCurve Convert1 (C2d, 
256                                                  U1, 
257                                                  Umed, 
258                                                  Parameterisation);
259
260           Handle (BSplineCurve) TheCurve1 = BSplineCurveBuilder (TheConic, Convert1);
261
262           Convert_CircleToBSplineCurve Convert2 (C2d, 
263                                                  Umed, 
264                                                  U2, 
265                                                  Parameterisation);
266
267           Handle (BSplineCurve) TheCurve2 = BSplineCurveBuilder (TheConic, Convert2);
268
269           Geom2dConvert_CompCurveToBSplineCurve CCTBSpl(TheCurve1,
270                                                         Parameterisation);
271
272           CCTBSpl.Add(TheCurve2, Precision::PConfusion(), Standard_True);
273           
274           
275           TheCurve = CCTBSpl.BSplineCurve();
276         }
277       }
278     }
279     
280     else if (Curv->IsKind(STANDARD_TYPE(Geom2d_Ellipse))) {
281       Handle(Geom2d_Ellipse) TheConic = Handle(Geom2d_Ellipse)::DownCast(Curv);
282       
283       Elips2d E2d (gp::OX2d(),
284                    TheConic->MajorRadius(),
285                    TheConic->MinorRadius());
286       if(Parameterisation != Convert_RationalC1) {
287         Convert_EllipseToBSplineCurve Convert (E2d, 
288                                                U1, 
289                                                U2,
290                                                Parameterisation);
291         TheCurve = BSplineCurveBuilder (TheConic, Convert);
292       }
293       else {
294         if(U2 - U1 < 6.) {
295           Convert_EllipseToBSplineCurve Convert (E2d, 
296                                                  U1, 
297                                                  U2,
298                                                  Parameterisation);
299           TheCurve = BSplineCurveBuilder (TheConic, Convert);
300         }       
301         else { // split ellipse to avoide numerical 
302                // overflow when U2 - U1 =~ 2*PI
303
304           Standard_Real Umed = (U1 + U2) * .5;
305           Convert_EllipseToBSplineCurve Convert1 (E2d, 
306                                                   U1, 
307                                                   Umed, 
308                                                   Parameterisation);
309
310           Handle (BSplineCurve) TheCurve1 = BSplineCurveBuilder (TheConic, Convert1);
311
312           Convert_EllipseToBSplineCurve Convert2 (E2d, 
313                                                   Umed, 
314                                                   U2, 
315                                                   Parameterisation);
316
317           Handle (BSplineCurve) TheCurve2 = BSplineCurveBuilder (TheConic, Convert2);
318
319           Geom2dConvert_CompCurveToBSplineCurve CCTBSpl(TheCurve1,
320                                                         Parameterisation);
321
322           CCTBSpl.Add(TheCurve2, Precision::PConfusion(), Standard_True);
323
324           
325           TheCurve = CCTBSpl.BSplineCurve();
326         }
327       }
328     }
329     
330     else if (Curv->IsKind(STANDARD_TYPE(Geom2d_Hyperbola))) {
331       Handle(Geom2d_Hyperbola) TheConic = Handle(Geom2d_Hyperbola)::DownCast(Curv);
332       
333       Hypr2d H2d (gp::OX2d(),
334                   TheConic->MajorRadius(), TheConic->MinorRadius());
335       Convert_HyperbolaToBSplineCurve Convert (H2d, U1, U2);
336       TheCurve = BSplineCurveBuilder (TheConic, Convert);
337     }
338     
339     else if (Curv->IsKind(STANDARD_TYPE(Geom2d_Parabola))) {
340       Handle(Geom2d_Parabola) TheConic = Handle(Geom2d_Parabola)::DownCast(Curv);
341       
342       Parab2d Prb2d (gp::OX2d(), TheConic->Focal());
343       Convert_ParabolaToBSplineCurve Convert (Prb2d, U1, U2);
344       TheCurve = BSplineCurveBuilder (TheConic, Convert);
345     }
346     
347     else if (Curv->IsKind (STANDARD_TYPE(Geom2d_BezierCurve))) {
348       
349       Handle(Geom2d_BezierCurve) CBez = Handle(Geom2d_BezierCurve)::DownCast(Curv->Copy());
350       
351       CBez->Segment (U1, U2);
352       Standard_Integer NbPoles = CBez->NbPoles();
353       Standard_Integer Degree  = CBez->Degree();
354       Array1OfPnt2d     Poles   (1, NbPoles);
355       Array1OfReal    Knots   (1, 2);
356       Array1OfInteger Mults   (1, 2);
357       Knots (1) = 0.0;
358       Knots (2) = 1.0;
359       Mults (1) = Degree + 1;
360       Mults (2) = Degree + 1;
361       CBez->Poles (Poles);
362       if (CBez->IsRational()) {    
363         Array1OfReal    Weights (1, NbPoles);
364         CBez->Weights (Weights);
365         TheCurve = new BSplineCurve (Poles, Weights, Knots, Mults, Degree);
366       }
367       else {
368         TheCurve = new BSplineCurve (Poles, Knots, Mults, Degree);
369       }
370     }
371     
372     else if (Curv->IsKind (STANDARD_TYPE(Geom2d_BSplineCurve))) {
373       TheCurve = Handle(Geom2d_BSplineCurve)::DownCast(Curv->Copy());
374       TheCurve->Segment(U1,U2);
375     }
376     
377     else if (Curv->IsKind (STANDARD_TYPE(Geom2d_OffsetCurve))) {
378       
379       Standard_Real Tol2d = 1.e-4;
380       GeomAbs_Shape Order = GeomAbs_C2;
381       Standard_Integer MaxSegments = 16, MaxDegree = 14; 
382       Geom2dConvert_ApproxCurve ApprCOffs(C, Tol2d, Order, 
383                                           MaxSegments, MaxDegree);
384       if (ApprCOffs.HasResult())
385         TheCurve = ApprCOffs.Curve();
386       else  Standard_ConstructionError::Raise();
387     }
388
389     else { Standard_DomainError::Raise("No such curve"); }
390     
391   }
392   
393   
394   else { 
395     
396     if (C->IsKind(STANDARD_TYPE(Geom2d_Ellipse))) {
397       Handle(Geom2d_Ellipse) TheConic = Handle(Geom2d_Ellipse)::DownCast(C);
398       
399       Elips2d E2d (gp::OX2d(),
400                    TheConic->MajorRadius(), TheConic->MinorRadius());
401       Convert_EllipseToBSplineCurve Convert (E2d,
402                                              Parameterisation);
403       TheCurve = BSplineCurveBuilder (TheConic, Convert);
404       TheCurve->SetPeriodic();
405     }
406     
407     else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) {
408       Handle(Geom2d_Circle) TheConic = Handle(Geom2d_Circle)::DownCast(C);
409       
410       Circ2d C2d (gp::OX2d(), TheConic->Radius());
411       Convert_CircleToBSplineCurve Convert (C2d,
412                                             Parameterisation);
413       TheCurve = BSplineCurveBuilder (TheConic, Convert);
414       TheCurve->SetPeriodic();
415     }
416     
417     else if (C->IsKind (STANDARD_TYPE(Geom2d_BezierCurve))) {
418       Handle(Geom2d_BezierCurve) CBez = Handle(Geom2d_BezierCurve)::DownCast(C);
419       
420       Standard_Integer NbPoles = CBez->NbPoles();
421       Standard_Integer Degree  = CBez->Degree();
422       Array1OfPnt2d     Poles   (1, NbPoles);
423       Array1OfReal    Knots   (1, 2);
424       Array1OfInteger Mults   (1, 2);
425       Knots (1) = 0.0;
426       Knots (2) = 1.0;
427       Mults (1) = Degree + 1;
428       Mults (2) = Degree + 1;
429       CBez->Poles (Poles);
430       if (CBez->IsRational()) {    
431         Array1OfReal    Weights (1, NbPoles);
432         CBez->Weights (Weights);
433         TheCurve = new BSplineCurve (Poles, Weights, Knots, Mults, Degree);
434       }
435       else {
436         TheCurve = new BSplineCurve (Poles, Knots, Mults, Degree);
437       }
438     }
439     else if (C->IsKind (STANDARD_TYPE(Geom2d_BSplineCurve))) {
440       TheCurve = Handle(Geom2d_BSplineCurve)::DownCast(C->Copy());
441     }
442
443     else if (C->IsKind (STANDARD_TYPE(Geom2d_OffsetCurve))) {
444       
445       Standard_Real Tol2d = 1.e-4;
446       GeomAbs_Shape Order = GeomAbs_C2;
447       Standard_Integer MaxSegments = 16, MaxDegree = 14; 
448       Geom2dConvert_ApproxCurve ApprCOffs(C, Tol2d, Order, 
449                                           MaxSegments, MaxDegree);
450       if (ApprCOffs.HasResult())
451         TheCurve = ApprCOffs.Curve();
452       else  Standard_ConstructionError::Raise();
453     }
454
455     else { Standard_DomainError::Raise(); }
456   }
457   
458   return TheCurve;
459 }
460
461  //=======================================================================
462 //class : law_evaluator
463 //purpose  : 
464 //=======================================================================
465
466 class Geom2dConvert_law_evaluator : public BSplCLib_EvaluatorFunction
467 {
468
469 public:
470
471   Geom2dConvert_law_evaluator (const Handle(Geom2d_BSplineCurve)& theAncore)
472   : myAncore (theAncore) {}
473
474   virtual void Evaluate (const Standard_Integer theDerivativeRequest,
475                          const Standard_Real*   theStartEnd,
476                          const Standard_Real    theParameter,
477                          Standard_Real&         theResult,
478                          Standard_Integer&      theErrorCode) const
479   {
480     theErrorCode = 0;
481     if (!myAncore.IsNull() && 
482         theParameter >= theStartEnd[0] &&
483         theParameter <= theStartEnd[1] && 
484         theDerivativeRequest == 0)
485     {
486       gp_Pnt2d aPoint;
487       myAncore->D0 (theParameter, aPoint);
488       theResult = aPoint.Coord (2);
489     }
490     else
491       theErrorCode = 1;
492   }
493
494 private:
495
496   Handle(Geom2d_BSplineCurve) myAncore;
497
498 };
499
500
501 //=======================================================================
502 //function : MultNumandDenom
503 //purpose  : Multiply two BSpline curves to make one
504 //=======================================================================
505
506
507 static Handle(Geom2d_BSplineCurve) MultNumandDenom(const Handle(Geom2d_BSplineCurve)& a ,
508                                                    const Handle(Geom2d_BSplineCurve)& BS )
509      
510 { TColStd_Array1OfReal               aKnots(1,a->NbKnots());
511   TColStd_Array1OfReal               BSKnots(1,BS->NbKnots());
512   TColStd_Array1OfReal               BSFlatKnots(1,BS->NbPoles()+BS->Degree()+1);
513   TColStd_Array1OfReal               BSWeights(1,BS->NbPoles()); 
514   TColStd_Array1OfInteger            aMults(1,a->NbKnots());
515   TColStd_Array1OfInteger            BSMults(1,BS->NbKnots());
516   TColgp_Array1OfPnt2d               aPoles(1,a->NbPoles());
517   TColgp_Array1OfPnt2d               BSPoles(1,BS->NbPoles());
518   Handle(Geom2d_BSplineCurve)        res;
519   Handle(TColStd_HArray1OfReal)      resKnots;
520   Handle(TColStd_HArray1OfInteger)   resMults; 
521   Standard_Real                      start_value,end_value;
522   Standard_Real                      tolerance=Precision::Confusion();
523   Standard_Integer                   resNbPoles,degree,
524                                      ii,jj,
525                                      Status;
526   
527   BS->Knots(BSKnots);                            
528   BS->Multiplicities(BSMults);
529   BS->Poles(BSPoles);
530   BS->Weights(BSWeights);
531   BS->KnotSequence(BSFlatKnots);
532   start_value = BSKnots(1);
533   end_value = BSKnots(BS->NbKnots());
534
535   a->Knots(aKnots);
536   a->Poles(aPoles);
537   a->Multiplicities(aMults);
538   BSplCLib::Reparametrize(BS->FirstParameter(),BS->LastParameter(),aKnots);
539   Handle(Geom2d_BSplineCurve) anAncore = new Geom2d_BSplineCurve (aPoles, aKnots, aMults, a->Degree());
540
541   BSplCLib::MergeBSplineKnots(tolerance,start_value,end_value,
542                               a->Degree(),aKnots,aMults,
543                               BS->Degree(),BSKnots,BSMults,
544                               resNbPoles,resKnots,resMults);
545   degree=BS->Degree()+a->Degree();
546   TColgp_Array1OfPnt2d resNumPoles(1,resNbPoles);
547   TColStd_Array1OfReal resDenPoles(1,resNbPoles);
548   TColgp_Array1OfPnt2d resPoles(1,resNbPoles);
549   TColStd_Array1OfReal resFlatKnots(1,resNbPoles+degree+1);
550   BSplCLib::KnotSequence(resKnots->Array1(),resMults->Array1(),resFlatKnots);
551   for (ii=1;ii<=BS->NbPoles();ii++)
552     for (jj=1;jj<=2;jj++)
553       BSPoles(ii).SetCoord(jj,BSPoles(ii).Coord(jj)*BSWeights(ii));
554 //POP pour NT
555   Geom2dConvert_law_evaluator ev (anAncore);
556   BSplCLib::FunctionMultiply(ev,
557                              BS->Degree(),
558                              BSFlatKnots,
559                              BSPoles,
560                              resFlatKnots,
561                              degree,
562                              resNumPoles,
563                              Status);
564   BSplCLib::FunctionMultiply(ev,
565                              BS->Degree(),
566                              BSFlatKnots,
567                              BSWeights,
568                              resFlatKnots,
569                              degree,
570                              resDenPoles,
571                              Status);
572 //  BSplCLib::FunctionMultiply(law_evaluator,
573 //                           BS->Degree(),
574 //                           BSFlatKnots,
575 //                           BSPoles,
576 //                           resFlatKnots,
577 //                           degree,
578 //                           resNumPoles,
579 //                           Status);
580 //  BSplCLib::FunctionMultiply(law_evaluator,
581 //                           BS->Degree(),
582 //                           BSFlatKnots,
583 //                           BSWeights,
584 //                           resFlatKnots,
585 //                           degree,
586 //                           resDenPoles,
587 //                           Status);
588   for (ii=1;ii<=resNbPoles;ii++)
589     for(jj=1;jj<=2;jj++) 
590       resPoles(ii).SetCoord(jj,resNumPoles(ii).Coord(jj)/resDenPoles(ii));
591   res = new Geom2d_BSplineCurve(resPoles,resDenPoles,resKnots->Array1(),resMults->Array1(),degree);
592   return res;
593 }
594
595 //=======================================================================
596 //function : Pretreatment 
597 //purpose  : Put the two first and two last weigths at one if they are 
598 //           equal
599 //=======================================================================
600
601 static void Pretreatment(TColGeom2d_Array1OfBSplineCurve& tab)
602
603 {Standard_Integer i,j;
604  Standard_Real a;
605
606  for (i=0;i<=(tab.Length()-1);i++){
607    if (tab(i)->IsRational()) {
608      a=tab(i)->Weight(1) ;
609      if ((tab(i)->Weight(2)==a)&&
610          (tab(i)->Weight(tab(i)->NbPoles()-1)==a) &&
611          (tab(i)->Weight(tab(i)->NbPoles())==a))
612        
613        for (j=1;j<=tab(i)->NbPoles();j++)
614          tab(i)->SetWeight(j,tab(i)->Weight(j)/a) ;
615    } 
616  }
617 }
618
619 //=======================================================================
620 //function : NeedToBeTreated
621 //purpose  : Say if the BSpline is rationnal and if the two first and two
622 //           last weigths are different
623 //=======================================================================    
624
625 static Standard_Boolean NeedToBeTreated(const Handle(Geom2d_BSplineCurve)& BS)
626
627 {
628   TColStd_Array1OfReal  tabWeights(1,BS->NbPoles());
629   if (BS->IsRational()) {
630     BS->Weights(tabWeights);
631     if ((BSplCLib::IsRational(tabWeights,1,BS->NbPoles()))&&
632         ((BS->Weight(1)<(1-Precision::Confusion()))||
633          (BS->Weight(1)>(1+Precision::Confusion()))||
634          (BS->Weight(2)<(1-Precision::Confusion()))||
635          (BS->Weight(2)>(1+Precision::Confusion()))||
636          (BS->Weight(BS->NbPoles()-1)<(1-Precision::Confusion()))||
637          (BS->Weight(BS->NbPoles()-1)>(1+Precision::Confusion()))||
638          (BS->Weight(BS->NbPoles())<(1-Precision::Confusion()))||
639          (BS->Weight(BS->NbPoles())>(1+Precision::Confusion()))))
640       return Standard_True;
641     else
642       return Standard_False;
643   }
644   else 
645     return Standard_False ;
646
647 }
648
649 //=======================================================================
650 //function : Need2DegRepara
651 //purpose  : in the case of wire closed G1 it says if you will to use a 
652 //           two degree reparametrisation to close it C1
653 //=======================================================================
654
655 static Standard_Boolean Need2DegRepara(const TColGeom2d_Array1OfBSplineCurve& tab)
656
657 {Standard_Integer        i;
658  gp_Vec2d                Vec1,Vec2;
659  gp_Pnt2d                Pint;
660  Standard_Real           Rapport=1.0e0;
661
662  for (i=0;i<=tab.Length()-2;i++){
663    tab(i+1)->D1(tab(i+1)->FirstParameter(),Pint,Vec1);
664    tab(i)->D1(tab(i)->LastParameter(),Pint,Vec2);
665    Rapport=Rapport*Vec2.Magnitude()/Vec1.Magnitude();
666  }
667  if ((Rapport<=(1.0e0 +Precision::Confusion()))&&(Rapport>=(1.0e0-Precision::Confusion())))
668    return Standard_False;
669  else
670    return Standard_True;
671 }
672          
673 //=======================================================================
674 //function : Indexmin
675 //purpose  : Give the index of the curve which has the lowest degree
676 //=======================================================================
677
678 static Standard_Integer Indexmin(const TColGeom2d_Array1OfBSplineCurve& tab)
679 {
680   Standard_Integer i,index=0,degree;
681   
682   degree=tab(0)->Degree();
683   for (i=0;i<=tab.Length()-1;i++)
684     if (tab(i)->Degree()<=degree){
685       degree=tab(i)->Degree();
686       index=i;
687     }
688   return index;
689 }
690
691 //=======================================================================
692 //function : NewTabClosedG1
693 //purpose  : 
694 //=======================================================================
695
696 static void ReorderArrayOfG1(TColGeom2d_Array1OfBSplineCurve&    ArrayOfCurves, 
697                            TColStd_Array1OfReal&         ArrayOfToler,
698                            TColStd_Array1OfBoolean&            tabG1,
699                            const Standard_Integer              StartIndex,
700                            const Standard_Real                 ClosedTolerance)
701
702 {Standard_Integer i;
703  TColGeom2d_Array1OfBSplineCurve  ArraybisOfCurves(0,ArrayOfCurves.Length()-1);
704  TColStd_Array1OfReal             ArraybisOfToler(0,ArrayOfToler.Length()-1);
705  TColStd_Array1OfBoolean          tabbisG1(0,tabG1.Length()-1);
706
707  for (i=0;i<=ArrayOfCurves.Length()-1;i++){
708    if (i!=ArrayOfCurves.Length()-1){
709      ArraybisOfCurves(i)=ArrayOfCurves(i);
710      ArraybisOfToler(i)=ArrayOfToler(i);
711      tabbisG1(i)=tabG1(i);
712    }
713    else
714      ArraybisOfCurves(i)=ArrayOfCurves(i);
715  }
716
717  for (i=0;i<=(ArrayOfCurves.Length()-(StartIndex+2));i++){
718    ArrayOfCurves(i)=ArraybisOfCurves(i+StartIndex+1);
719    if (i!=(ArrayOfCurves.Length()-(StartIndex+2))){
720      ArrayOfToler(i)=ArraybisOfToler(i+StartIndex+1);
721      tabG1(i)=tabbisG1(i+StartIndex+1);
722    }
723  }
724
725  ArrayOfToler(ArrayOfCurves.Length()-(StartIndex+2))=ClosedTolerance;
726  tabG1(ArrayOfCurves.Length()-(StartIndex+2))=Standard_True;
727
728  for (i=(ArrayOfCurves.Length()-(StartIndex+1));i<=(ArrayOfCurves.Length()-1);i++){
729    if (i!=ArrayOfCurves.Length()-1){
730      ArrayOfCurves(i)=ArraybisOfCurves(i-(ArrayOfCurves.Length()-(StartIndex+1)));
731      ArrayOfToler(i)=ArraybisOfToler(i-(ArrayOfCurves.Length()-(StartIndex+1)));
732      tabG1(i)=tabbisG1(i-(ArrayOfCurves.Length()-(StartIndex+1)));
733    }
734    else
735      ArrayOfCurves(i)=ArraybisOfCurves(i-(ArrayOfCurves.Length()-(StartIndex+1)));
736  }
737 }
738
739 //=======================================================================
740 //function : GeomAbsToInteger
741 //purpose  : 
742 //=======================================================================
743
744 static Standard_Integer GeomAbsToInteger(const GeomAbs_Shape  gcont) 
745 {
746   Standard_Integer cont=0 ;
747   switch (gcont) {
748   case GeomAbs_C0 :
749       cont = 0 ;
750       break ;
751   case GeomAbs_G1 :
752       cont = 1 ;
753       break ;
754   case GeomAbs_C1 :
755       cont = 2 ;
756       break ;
757   case GeomAbs_G2 :
758       cont = 3 ;
759       break ;
760   case GeomAbs_C2 :
761       cont = 4 ;
762       break ;
763   case GeomAbs_C3 :
764       cont = 5 ;
765       break ;
766   case GeomAbs_CN :
767       cont = 6 ;
768       break ; 
769   } 
770  return cont ;
771 }
772 //=======================================================================
773 //function : Continuity
774 //purpose  : 
775 //=======================================================================
776
777 static GeomAbs_Shape Continuity(const Handle(Geom2d_Curve)& C1, 
778                                 const Handle(Geom2d_Curve)& C2, 
779                                 const Standard_Real u1, 
780                                 const Standard_Real u2,
781                                 const Standard_Boolean r1, 
782                                 const Standard_Boolean r2,
783                                 const Standard_Real tl,
784                                 const Standard_Real ta)
785 {
786   GeomAbs_Shape cont = GeomAbs_C0;
787   Standard_Integer index1,
788                    index2 ;
789   Standard_Real  tolerance,value ;
790 //  Standard_Boolean fini = Standard_False;
791   gp_Vec2d d1,d2;
792 //  gp_Dir2d dir1,dir2;
793   gp_Pnt2d point1, point2 ;
794   Standard_Integer cont1, cont2 ;
795   GeomAbs_Shape gcont1 = C1->Continuity(), gcont2 = C2->Continuity();
796   cont1 = GeomAbsToInteger(gcont1) ;
797   cont2 = GeomAbsToInteger(gcont2) ;
798          
799   Handle(Geom2d_Curve) aCurve1 = C1 ;
800   Handle(Geom2d_Curve) aCurve2 = C2 ;
801   if (C1->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))){
802     Handle(Geom2d_TrimmedCurve) aTrimmed = Handle(Geom2d_TrimmedCurve) ::DownCast(aCurve1) ;
803     aCurve1 = aTrimmed->BasisCurve() ;
804   }
805   if (C2->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))){
806     Handle(Geom2d_TrimmedCurve) aTrimmed = Handle(Geom2d_TrimmedCurve) ::DownCast(aCurve2) ;
807     aCurve2 = aTrimmed->BasisCurve() ;
808   }
809   if (aCurve1->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))){
810     Handle(Geom2d_BSplineCurve) BSplineCurve = Handle(Geom2d_BSplineCurve)::DownCast(aCurve1) ;
811     BSplineCurve->Resolution(tl,
812                              tolerance) ;
813     BSplineCurve->LocateU(u1,
814                           tolerance,
815                           index1,
816                           index2) ;
817     
818     if (index1 > 1 && index2 < BSplineCurve->NbKnots() && index1 == index2) {
819        cont1 = BSplineCurve->Degree() - BSplineCurve->Multiplicity(index1) ;
820     }
821     else {
822       cont1 = 5 ;
823     }
824   }
825   if (aCurve2->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))){
826     Handle(Geom2d_BSplineCurve) BSplineCurve = Handle(Geom2d_BSplineCurve)::DownCast(aCurve2) ;
827     BSplineCurve->Resolution(tl,
828                              tolerance) ;
829     BSplineCurve->LocateU(u2,
830                           tolerance,
831                           index1,
832                           index2) ;
833     
834     if (index1 > 1 && index2 < BSplineCurve->NbKnots() && index1 == index2) {
835       cont2 = BSplineCurve->Degree() - BSplineCurve->Multiplicity(index1) ;
836     }
837     else {
838       cont2 = 5 ;
839     }
840   }
841   aCurve1->D1(u1,
842               point1,
843               d1) ;
844   aCurve2->D1(u2,
845               point2,
846               d2) ;
847   if (point1.SquareDistance(point2) <= tl * tl) {
848     if (cont1 != 0 &&
849         cont2 != 0) {
850       
851       if (d1.SquareMagnitude() >= tl * tl &&
852           d2.SquareMagnitude() >= tl * tl) {
853         if (r1) {
854           d1.SetCoord(-d1.X(),-d1.Y()) ;
855         }
856         if (r2) {
857           d2.SetCoord(-d2.X(),-d2.Y()) ;
858         }
859         value = d1.Dot(d2) ;
860         if ((d1.Magnitude()<=(d2.Magnitude()+tl))&&
861             (d1.Magnitude()>=(d2.Magnitude()-tl))&&
862             (value/(d1.Magnitude()*d2.Magnitude()) >= 1.0e0 - ta * ta)) {
863           cont = GeomAbs_C1 ;
864         }
865         else {
866           d1.Normalize() ;
867           d2.Normalize() ;
868           value = Abs(d1.Dot(d2)) ;
869           if (value >= 1.0e0 - ta * ta) {
870             cont = GeomAbs_G1 ;
871           }
872         }
873         
874       }
875     }
876   }
877   else
878     Standard_Failure::Raise("Courbes non jointives");
879   return cont ;
880 }
881
882 //=======================================================================
883 //function : Continuity
884 //purpose  : 
885 //=======================================================================
886
887 static GeomAbs_Shape Continuity(const Handle(Geom2d_Curve)& C1, 
888                                 const Handle(Geom2d_Curve)& C2, 
889                                 const Standard_Real u1, 
890                                 const Standard_Real u2,
891                                 const Standard_Boolean r1, 
892                                 const Standard_Boolean r2)
893 {
894   return Continuity(C1,C2,u1,u2,r1,r2,
895                     Precision::Confusion(),Precision::Angular());
896 }
897
898 //=======================================================================
899 //class :reparameterise_evaluator 
900 //purpose  : 
901 //=======================================================================
902
903 class Geom2dConvert_reparameterise_evaluator : public BSplCLib_EvaluatorFunction
904 {
905
906 public:
907
908   Geom2dConvert_reparameterise_evaluator (const Standard_Real thePolynomialCoefficient[3])
909   {
910     memcpy(myPolynomialCoefficient, thePolynomialCoefficient, sizeof(myPolynomialCoefficient));
911   }
912
913   virtual void Evaluate (const Standard_Integer theDerivativeRequest,
914                          const Standard_Real*   /*theStartEnd*/,
915                          const Standard_Real    theParameter,
916                          Standard_Real&         theResult,
917                          Standard_Integer&      theErrorCode) const
918   {
919     theErrorCode = 0;
920     PLib::EvalPolynomial (theParameter,
921                           theDerivativeRequest,
922                           2,
923                           1,
924                           *((Standard_Real* )myPolynomialCoefficient), // function really only read values from this array
925                           theResult);
926   }
927
928 private:
929
930   Standard_Real myPolynomialCoefficient[3];
931
932 };
933
934 //=======================================================================
935 //function : ConcatG1
936 //purpose  : 
937 //=======================================================================
938
939 void  Geom2dConvert::ConcatG1(TColGeom2d_Array1OfBSplineCurve&           ArrayOfCurves, 
940                               const TColStd_Array1OfReal&                ArrayOfToler,
941                               Handle(TColGeom2d_HArray1OfBSplineCurve) & ArrayOfConcatenated,
942                               const Standard_Boolean                     ClosedFlag,
943                               const Standard_Real                        ClosedTolerance) 
944
945 {Standard_Integer             nb_curve=ArrayOfCurves.Length(),
946                               nb_vertexG1,
947                               nb_group=0,
948                               index=0,i,ii,j,jj,
949                               indexmin,
950                               nb_vertex_group0=0;
951  Standard_Real                lambda,                      //coeff de raccord G1
952                               First,PreLast=0;
953  gp_Vec2d                     Vec1,Vec2;                   //vecteurs tangents consecutifs
954  gp_Pnt2d                     Pint;
955  Handle(Geom2d_BSplineCurve)  Curve1,Curve2;                       
956  TColStd_Array1OfBoolean      tabG1(0,nb_curve-2);         //tableau de continuite G1 aux raccords
957  TColStd_Array1OfReal         local_tolerance(0,
958                                               ArrayOfToler.Length()-1) ;
959  
960  for (i= 0; i < ArrayOfToler.Length() ; i++) {
961    local_tolerance(i) = ArrayOfToler(i) ;
962  }
963  for (i=0 ;i<nb_curve; i++){
964    if (i >= 1){
965      First=ArrayOfCurves(i)->FirstParameter();
966      if (Continuity(ArrayOfCurves(i-1),
967                     ArrayOfCurves(i),
968                     PreLast,First,
969                     Standard_True,
970                     Standard_True)<GeomAbs_C0)
971        Standard_ConstructionError::Raise("Geom2dConvert curves not C0") ;                //renvoi d'une erreur
972      else{
973        if (Continuity(ArrayOfCurves(i-1),
974                       ArrayOfCurves(i),
975                       PreLast,First,
976                       Standard_True,
977                       Standard_True)>=GeomAbs_G1)
978          tabG1(i-1)=Standard_True;                   //True=Continuite G1
979        else 
980          tabG1(i-1)=Standard_False;
981      }
982    }
983    PreLast=ArrayOfCurves(i)->LastParameter();     
984  }
985  
986
987  while (index<=nb_curve-1){                                 //determination des caracteristiques du Wire
988    nb_vertexG1=0;
989    while(((index+nb_vertexG1)<=nb_curve-2)&&(tabG1(index+nb_vertexG1)==Standard_True))
990      nb_vertexG1++;
991    nb_group++;
992    if (index==0)
993      nb_vertex_group0=nb_vertexG1;
994    index=index+1+nb_vertexG1;
995  }
996  
997  if ((ClosedFlag)&&(nb_group!=1)){                            //rearrangement du tableau
998    nb_group--;
999    ReorderArrayOfG1(ArrayOfCurves,
1000                   local_tolerance,
1001                   tabG1,
1002                   nb_vertex_group0,
1003                   ClosedTolerance);
1004  }
1005
1006  ArrayOfConcatenated = new 
1007    TColGeom2d_HArray1OfBSplineCurve(0,nb_group-1);
1008
1009  Standard_Boolean       fusion;
1010 // Standard_Integer       k=0;
1011  index=0;
1012  Pretreatment(ArrayOfCurves);
1013
1014  Standard_Real aPolynomialCoefficient[3];
1015
1016  if ((nb_group==1) && (ClosedFlag)){                       //traitement d'un cas particulier
1017    indexmin=Indexmin(ArrayOfCurves);
1018    if (indexmin!=(ArrayOfCurves.Length()-1))
1019      ReorderArrayOfG1(ArrayOfCurves,
1020                     local_tolerance,
1021                     tabG1,
1022                     indexmin,
1023                     ClosedTolerance);
1024    Curve2=ArrayOfCurves(0);
1025    for (j=1;j<=nb_curve-1;j++){                //boucle secondaire a l'interieur de chaque groupe
1026      Curve1=ArrayOfCurves(j);
1027      if ( (j==(nb_curve-1)) &&(Need2DegRepara(ArrayOfCurves))){ 
1028        const Standard_Integer aNewCurveDegree = Min(2 * Curve1->Degree(), Geom2d_BSplineCurve::MaxDegree());
1029        Curve2->D1(Curve2->LastParameter(),Pint,Vec1);
1030        Curve1->D1(Curve1->FirstParameter(),Pint,Vec2);
1031        lambda=Vec2.Magnitude()/Vec1.Magnitude();
1032        TColStd_Array1OfReal KnotC1 (1, Curve1->NbKnots());
1033        Curve1->Knots(KnotC1);
1034        Curve1->D1(Curve1->LastParameter(),Pint,Vec2);
1035        ArrayOfCurves(0)->D1(ArrayOfCurves(0)->FirstParameter(),Pint,Vec1);
1036        Standard_Real lambda2=Vec1.Magnitude()/Vec2.Magnitude();
1037        Standard_Real tmax,a,b,c,
1038        umin=Curve1->FirstParameter(),umax=Curve1->LastParameter();
1039        tmax=2*lambda*(umax-umin)/(1+lambda*lambda2);
1040        a=(lambda*lambda2-1)/(2*lambda*tmax);
1041        aPolynomialCoefficient[2] = a;              
1042        b=(1/lambda); 
1043        aPolynomialCoefficient[1] = b;
1044        c=umin;
1045        aPolynomialCoefficient[0] = c;
1046        TColStd_Array1OfReal  Curve1FlatKnots(1,Curve1->NbPoles()+Curve1->Degree()+1);
1047        TColStd_Array1OfInteger  KnotC1Mults(1,Curve1->NbKnots());
1048        Curve1->Multiplicities(KnotC1Mults);
1049        BSplCLib::KnotSequence(KnotC1,KnotC1Mults,Curve1FlatKnots);
1050        KnotC1(1)=0.0;
1051        for (ii=2;ii<=KnotC1.Length();ii++) {
1052 //       KnotC1(ii)=(-b+Abs(a)/a*Sqrt(b*b-4*a*(c-KnotC1(ii))))/(2*a);
1053          KnotC1(ii)=(-b+Sqrt(b*b-4*a*(c-KnotC1(ii))))/(2*a); //ifv 17.05.00 buc60667
1054        }
1055        TColgp_Array1OfPnt2d Curve1Poles(1,Curve1->NbPoles());
1056        Curve1->Poles(Curve1Poles);
1057        
1058        for (ii=1;ii<=Curve1->NbKnots();ii++)
1059          KnotC1Mults(ii)=(Curve1->Degree()+KnotC1Mults(ii));
1060        
1061        TColStd_Array1OfReal FlatKnots(1,Curve1FlatKnots.Length()+(Curve1->Degree()*Curve1->NbKnots()));
1062        
1063        BSplCLib::KnotSequence(KnotC1,KnotC1Mults,FlatKnots);
1064        TColgp_Array1OfPnt2d NewPoles(1,FlatKnots.Length()-(2*Curve1->Degree()+1));
1065        Standard_Integer      Status;
1066        TColStd_Array1OfReal Curve1Weights(1,Curve1->NbPoles());
1067        Curve1->Weights(Curve1Weights);
1068        for (ii=1;ii<=Curve1->NbPoles();ii++)
1069          for (jj=1;jj<=2;jj++)
1070            Curve1Poles(ii).SetCoord(jj,Curve1Poles(ii).Coord(jj)*Curve1Weights(ii));
1071 //POP pour NT
1072        Geom2dConvert_reparameterise_evaluator ev (aPolynomialCoefficient);
1073        BSplCLib::FunctionReparameterise(ev,
1074                                         Curve1->Degree(),
1075                                         Curve1FlatKnots,
1076                                         Curve1Poles,
1077                                         FlatKnots,
1078                                         aNewCurveDegree,
1079                                         NewPoles,
1080                                         Status
1081                                         );
1082        TColStd_Array1OfReal NewWeights(1,FlatKnots.Length()-(2*Curve1->Degree()+1));
1083        BSplCLib::FunctionReparameterise(ev,
1084                                         Curve1->Degree(),
1085                                         Curve1FlatKnots,
1086                                         Curve1Weights,
1087                                         FlatKnots,
1088                                         aNewCurveDegree,
1089                                         NewWeights,
1090                                         Status
1091                                         );
1092 //      BSplCLib::FunctionReparameterise(reparameterise_evaluator,
1093 //                                      Curve1->Degree(),
1094 //                                      Curve1FlatKnots,
1095 //                                      Curve1Poles,
1096 //                                      FlatKnots,
1097 //                                      2*Curve1->Degree(),
1098 //                                      NewPoles,
1099 //                                      Status
1100 //                                      );
1101 //       TColStd_Array1OfReal NewWeights(1,FlatKnots.Length()-(2*Curve1->Degree()+1));
1102 //       BSplCLib::FunctionReparameterise(reparameterise_evaluator,
1103 //                                      Curve1->Degree(),
1104 //                                      Curve1FlatKnots,
1105 //                                      Curve1Weights,
1106 //                                      FlatKnots,
1107 //                                      2*Curve1->Degree(),
1108 //                                      NewWeights,
1109 //                                      Status
1110 //                                      );
1111        for (ii=1;ii<=NewPoles.Length();ii++)
1112          for (jj=1;jj<=2;jj++)
1113            NewPoles(ii).SetCoord(jj,NewPoles(ii).Coord(jj)/NewWeights(ii));
1114        Curve1 = new Geom2d_BSplineCurve(NewPoles, NewWeights, KnotC1, KnotC1Mults, aNewCurveDegree);
1115      }
1116      Geom2dConvert_CompCurveToBSplineCurve C(Curve2);
1117      fusion=C.Add(Curve1,
1118                   local_tolerance(j-1));          //fusion de deux courbes adjacentes               
1119      if (fusion==Standard_False)
1120        Standard_ConstructionError::Raise("Geom2dConvert Concatenation Error") ;
1121      Curve2=C.BSplineCurve();
1122    }
1123    Curve2->SetPeriodic();      //1 seule courbe C1
1124    Curve2->RemoveKnot(Curve2->LastUKnotIndex(),
1125                          Curve2->Multiplicity(Curve2->LastUKnotIndex())-1,
1126                          Precision::Confusion());
1127    ArrayOfConcatenated->SetValue(0,Curve2);
1128  }
1129  
1130  else
1131    for (i=0;i<=nb_group-1;i++){                             //boucle principale sur chaque groupe de 
1132      nb_vertexG1=0;                                         //continuite interne G1
1133      
1134      while (((index+nb_vertexG1)<=nb_curve-2)&&(tabG1(index+nb_vertexG1)==Standard_True))
1135        nb_vertexG1++;
1136       
1137      for (j=index;j<=index+nb_vertexG1;j++){                //boucle secondaire a l'interieur de chaque groupe
1138        Curve1=ArrayOfCurves(j);
1139        
1140        if (index==j)                                      //initialisation en debut de groupe
1141          ArrayOfConcatenated->SetValue(i,Curve1);
1142        else{
1143          Geom2dConvert_CompCurveToBSplineCurve  C(ArrayOfConcatenated->Value(i));
1144          fusion=C.Add(Curve1,ArrayOfToler(j-1));          //fusion de deux courbes adjacentes               
1145          if (fusion==Standard_False)
1146            Standard_ConstructionError::Raise("Geom2dConvert Concatenation Error") ;
1147          ArrayOfConcatenated->SetValue(i,C.BSplineCurve());
1148        }
1149      }
1150      index=index+1+nb_vertexG1;
1151    }
1152 }  
1153 //=======================================================================
1154 //function : ConcatC1
1155 //purpose  : 
1156 //=======================================================================
1157
1158 void  Geom2dConvert::ConcatC1(TColGeom2d_Array1OfBSplineCurve&           ArrayOfCurves, 
1159                               const TColStd_Array1OfReal&                ArrayOfToler,
1160                               Handle(TColStd_HArray1OfInteger)&          ArrayOfIndices,
1161                               Handle(TColGeom2d_HArray1OfBSplineCurve) & ArrayOfConcatenated,
1162                               const Standard_Boolean                     ClosedFlag,
1163                               const Standard_Real                        ClosedTolerance) 
1164 {
1165  ConcatC1(ArrayOfCurves,
1166           ArrayOfToler,
1167           ArrayOfIndices,
1168           ArrayOfConcatenated,
1169           ClosedFlag,
1170           ClosedTolerance,
1171           Precision::Angular()) ;
1172 }
1173 //=======================================================================
1174 //function : ConcatC1
1175 //purpose  : 
1176 //=======================================================================
1177
1178 void  Geom2dConvert::ConcatC1(TColGeom2d_Array1OfBSplineCurve&           ArrayOfCurves, 
1179                               const TColStd_Array1OfReal&                ArrayOfToler,
1180                               Handle(TColStd_HArray1OfInteger)&          ArrayOfIndices,
1181                               Handle(TColGeom2d_HArray1OfBSplineCurve) & ArrayOfConcatenated,
1182                               const Standard_Boolean                     ClosedFlag,
1183                               const Standard_Real                        ClosedTolerance,
1184                               const Standard_Real                        AngularTolerance) 
1185
1186 {Standard_Integer             nb_curve=ArrayOfCurves.Length(),
1187                               nb_vertexG1,
1188                               nb_group=0,
1189                               index=0,i,ii,j,jj,
1190                               indexmin,
1191                               nb_vertex_group0=0;
1192  Standard_Real                lambda,                      //coeff de raccord G1
1193                               First,PreLast=0;
1194  gp_Vec2d                     Vec1,Vec2;                   //vecteurs tangents consecutifs
1195  gp_Pnt2d                     Pint;
1196  Handle(Geom2d_BSplineCurve)  Curve1,Curve2;                       
1197  TColStd_Array1OfBoolean      tabG1(0,nb_curve-2);         //tableau de continuite G1 aux raccords
1198  TColStd_Array1OfReal         local_tolerance(0,
1199                                               ArrayOfToler.Length()-1) ;
1200
1201
1202  
1203  for (i=0 ; i < ArrayOfToler.Length() ; i++) {
1204    local_tolerance(i) = ArrayOfToler(i) ;
1205  }
1206  for (i=0 ;i<nb_curve; i++){
1207    if (i >= 1){
1208      First=ArrayOfCurves(i)->FirstParameter();
1209      if (Continuity(ArrayOfCurves(i-1),
1210                     ArrayOfCurves(i),
1211                     PreLast,First,
1212                     Standard_True,
1213                     Standard_True,
1214                     ArrayOfToler(i-1),
1215                     AngularTolerance)<GeomAbs_C0)
1216        Standard_ConstructionError::Raise("Geom2dConvert curves not C0") ;                //renvoi d'une erreur
1217      else{
1218        if (Continuity(ArrayOfCurves(i-1),
1219                       ArrayOfCurves(i),
1220                       PreLast,
1221                       First,
1222                       Standard_True,
1223                       Standard_True,
1224                       ArrayOfToler(i-1),
1225                       AngularTolerance)>=GeomAbs_G1)
1226          tabG1(i-1)=Standard_True;                   //True=Continuite G1
1227        else 
1228          tabG1(i-1)=Standard_False;
1229      }                               
1230    }
1231    PreLast=ArrayOfCurves(i)->LastParameter();     
1232  }
1233  
1234
1235  while (index<=nb_curve-1){                                 //determination des caracteristiques du Wire
1236    nb_vertexG1=0;
1237    while(((index+nb_vertexG1)<=nb_curve-2)&&(tabG1(index+nb_vertexG1)==Standard_True))
1238      nb_vertexG1++;
1239    nb_group++;
1240    if (index==0)
1241      nb_vertex_group0=nb_vertexG1;
1242    index=index+1+nb_vertexG1;
1243  }
1244
1245  if ((ClosedFlag)&&(nb_group!=1)){                            //rearrangement du tableau
1246    nb_group--;
1247    ReorderArrayOfG1(ArrayOfCurves,
1248                   local_tolerance,
1249                   tabG1,
1250                   nb_vertex_group0,
1251                   ClosedTolerance);
1252  }
1253
1254  ArrayOfIndices = new TColStd_HArray1OfInteger(0,nb_group);
1255  ArrayOfConcatenated = new TColGeom2d_HArray1OfBSplineCurve(0,nb_group-1);
1256
1257  Standard_Boolean       fusion;
1258  Standard_Integer       k=0;
1259  index=0;
1260  Pretreatment(ArrayOfCurves);
1261  Standard_Real aPolynomialCoefficient[3];
1262
1263  if ((nb_group==1) && (ClosedFlag)){                       //traitement d'un cas particulier
1264    ArrayOfIndices->SetValue(0,0);
1265    ArrayOfIndices->SetValue(1,0);
1266    indexmin=Indexmin(ArrayOfCurves);
1267    if (indexmin!=(ArrayOfCurves.Length()-1))
1268      ReorderArrayOfG1(ArrayOfCurves,
1269                     local_tolerance,
1270                     tabG1,
1271                     indexmin,
1272                     ClosedTolerance);
1273    for (j=0;j<=nb_curve-1;j++){                //boucle secondaire a l'interieur de chaque groupe
1274      if (NeedToBeTreated(ArrayOfCurves(j))) {
1275        Curve1=MultNumandDenom(Hermit::Solution(ArrayOfCurves(j)),ArrayOfCurves(j));
1276      }
1277      else
1278        Curve1=ArrayOfCurves(j);
1279      
1280      const Standard_Integer aNewCurveDegree = Min(2 * Curve1->Degree(), Geom2d_BSplineCurve::MaxDegree());
1281
1282      if (j==0)                                      //initialisation en debut de groupe
1283        Curve2=Curve1;
1284      else{
1285        if ( (j==(nb_curve-1)) &&(Need2DegRepara(ArrayOfCurves))){ 
1286          Curve2->D1(Curve2->LastParameter(),Pint,Vec1);
1287          Curve1->D1(Curve1->FirstParameter(),Pint,Vec2);
1288          lambda=Vec2.Magnitude()/Vec1.Magnitude();
1289          TColStd_Array1OfReal KnotC1 (1, Curve1->NbKnots());
1290          Curve1->Knots(KnotC1);
1291          Curve1->D1(Curve1->LastParameter(),Pint,Vec2);
1292          ArrayOfCurves(0)->D1(ArrayOfCurves(0)->FirstParameter(),Pint,Vec1);
1293          Standard_Real lambda2=Vec1.Magnitude()/Vec2.Magnitude();
1294          Standard_Real tmax,a,b,c,
1295          umin=Curve1->FirstParameter(),umax=Curve1->LastParameter();
1296          tmax=2*lambda*(umax-umin)/(1+lambda*lambda2);
1297          a=(lambda*lambda2-1)/(2*lambda*tmax);
1298          aPolynomialCoefficient[2] = a;
1299          b=(1/lambda); 
1300          aPolynomialCoefficient[1] = b;
1301          c=umin;
1302          aPolynomialCoefficient[0] = c;
1303          TColStd_Array1OfReal  Curve1FlatKnots(1,Curve1->NbPoles()+Curve1->Degree()+1);
1304          TColStd_Array1OfInteger  KnotC1Mults(1,Curve1->NbKnots());
1305          Curve1->Multiplicities(KnotC1Mults);
1306          BSplCLib::KnotSequence(KnotC1,KnotC1Mults,Curve1FlatKnots);
1307          KnotC1(1)=0.0;
1308          for (ii=2;ii<=KnotC1.Length();ii++) {
1309 //         KnotC1(ii)=(-b+Abs(a)/a*Sqrt(b*b-4*a*(c-KnotC1(ii))))/(2*a);
1310            KnotC1(ii)=(-b+Sqrt(b*b-4*a*(c-KnotC1(ii))))/(2*a); //ifv 17.05.00 buc60667
1311          }
1312          TColgp_Array1OfPnt2d  Curve1Poles(1,Curve1->NbPoles());
1313          Curve1->Poles(Curve1Poles);
1314          
1315          for (ii=1;ii<=Curve1->NbKnots();ii++)
1316            KnotC1Mults(ii)=(Curve1->Degree()+KnotC1Mults(ii));
1317          
1318          TColStd_Array1OfReal FlatKnots(1,Curve1FlatKnots.Length()+(Curve1->Degree()*Curve1->NbKnots()));
1319          
1320          BSplCLib::KnotSequence(KnotC1,KnotC1Mults,FlatKnots);
1321          TColgp_Array1OfPnt2d  NewPoles(1, FlatKnots.Length() - (aNewCurveDegree + 1));
1322          Standard_Integer      Status;
1323          TColStd_Array1OfReal Curve1Weights(1,Curve1->NbPoles());
1324          Curve1->Weights(Curve1Weights);
1325          for (ii=1;ii<=Curve1->NbPoles();ii++)
1326            for (jj=1;jj<=2;jj++)
1327              Curve1Poles(ii).SetCoord(jj,Curve1Poles(ii).Coord(jj)*Curve1Weights(ii));
1328 //POP pour NT
1329          Geom2dConvert_reparameterise_evaluator ev (aPolynomialCoefficient);
1330 //       BSplCLib::FunctionReparameterise(reparameterise_evaluator,
1331          BSplCLib::FunctionReparameterise(ev,
1332                                           Curve1->Degree(),
1333                                           Curve1FlatKnots,
1334                                           Curve1Poles,
1335                                           FlatKnots,
1336                                           aNewCurveDegree,
1337                                           NewPoles,
1338                                           Status
1339                                           );
1340          TColStd_Array1OfReal NewWeights(1, FlatKnots.Length() - (aNewCurveDegree + 1));
1341 //       BSplCLib::FunctionReparameterise(reparameterise_evaluator,
1342          BSplCLib::FunctionReparameterise(ev,
1343                                           Curve1->Degree(),
1344                                           Curve1FlatKnots,
1345                                           Curve1Weights,
1346                                           FlatKnots,
1347                                           aNewCurveDegree,
1348                                           NewWeights,
1349                                           Status
1350                                           );
1351          for (ii=1;ii<=NewPoles.Length();ii++) {
1352            for (jj=1;jj<=2;jj++)
1353              NewPoles(ii).SetCoord(jj,NewPoles(ii).Coord(jj)/NewWeights(ii));
1354          }
1355          Curve1 = new Geom2d_BSplineCurve(NewPoles, NewWeights, KnotC1, KnotC1Mults, aNewCurveDegree);
1356        }
1357        Geom2dConvert_CompCurveToBSplineCurve C(Curve2);
1358        fusion=C.Add(Curve1,
1359                     local_tolerance(j-1));          //fusion de deux courbes adjacentes               
1360        if (fusion==Standard_False)
1361          Standard_ConstructionError::Raise("Geom2dConvert Concatenation Error") ;
1362        Curve2=C.BSplineCurve();
1363      }
1364    }
1365    Curve2->SetPeriodic();      //1 seule courbe C1
1366    Curve2->RemoveKnot(Curve2->LastUKnotIndex(),
1367                          Curve2->Multiplicity(Curve2->LastUKnotIndex())-1,
1368                          Precision::Confusion());
1369    ArrayOfConcatenated->SetValue(0,Curve2);
1370  }
1371  
1372  else
1373    for (i=0;i<=nb_group-1;i++){                             //boucle principale sur chaque groupe de 
1374      nb_vertexG1=0;                                         //continuite interne G1
1375       
1376      while (((index+nb_vertexG1)<=nb_curve-2)&&(tabG1(index+nb_vertexG1)==Standard_True))
1377        nb_vertexG1++;
1378       
1379      if ((!ClosedFlag)||(nb_group==1)){                        //remplissage du tableau des indices conserves
1380        k++;
1381        ArrayOfIndices->SetValue(k-1,index);
1382        if (k==nb_group)
1383          ArrayOfIndices->SetValue(k,0);
1384      }
1385      else{
1386        k++;
1387        ArrayOfIndices->SetValue(k-1,index+nb_vertex_group0+1);
1388        if (k==nb_group)
1389          ArrayOfIndices->SetValue(k,nb_vertex_group0+1);
1390      }
1391       
1392      for (j=index;j<=index+nb_vertexG1;j++){                //boucle secondaire a l'interieur de chaque groupe
1393        if (NeedToBeTreated(ArrayOfCurves(j)))
1394          Curve1=MultNumandDenom(Hermit::Solution(ArrayOfCurves(j)),ArrayOfCurves(j));
1395        else
1396          Curve1=ArrayOfCurves(j);
1397        
1398        if (index==j)                                      //initialisation en debut de groupe
1399          ArrayOfConcatenated->SetValue(i,Curve1);
1400        else{
1401          Geom2dConvert_CompCurveToBSplineCurve C (ArrayOfConcatenated->Value(i));
1402          fusion=C.Add(Curve1,ArrayOfToler(j-1));          //fusion de deux courbes adjacentes               
1403          if (fusion==Standard_False)
1404            Standard_ConstructionError::Raise("Geom2dConvert Concatenation Error") ;
1405          ArrayOfConcatenated->SetValue(i,C.BSplineCurve());
1406        }
1407      }
1408      index=index+1+nb_vertexG1;
1409    }
1410 }
1411
1412 //=======================================================================
1413 //function : C0BSplineToC1BSplineCurve
1414 //purpose  : 
1415 //=======================================================================
1416
1417 void Geom2dConvert::C0BSplineToC1BSplineCurve(Handle(Geom2d_BSplineCurve)& BS,
1418                                               const Standard_Real          tolerance)
1419
1420 {
1421   TColStd_Array1OfInteger          BSMults(1,BS->NbKnots());
1422  TColStd_Array1OfReal             BSKnots(1,BS->NbKnots());
1423  Standard_Integer                 i,j,nbcurveC1=1;
1424  Standard_Real                    U1,U2;
1425  Standard_Boolean                 closed_flag = Standard_False ;
1426  gp_Pnt2d                         point1, point2;
1427  gp_Vec2d                         V1,V2;
1428  Standard_Boolean                 fusion;
1429
1430  BS->Knots(BSKnots);
1431  BS->Multiplicities(BSMults);
1432  for (i=BS->FirstUKnotIndex() + 1;i<=(BS->LastUKnotIndex()-1);i++){
1433    if (BSMults(i)==BS->Degree())
1434      nbcurveC1++;   
1435  }
1436
1437   nbcurveC1 = Min(nbcurveC1, BS->NbKnots() - 1); 
1438
1439  if (nbcurveC1>1){
1440    TColGeom2d_Array1OfBSplineCurve  ArrayOfCurves(0,nbcurveC1-1);
1441    TColStd_Array1OfReal             ArrayOfToler(0,nbcurveC1-2);
1442    
1443    for (i=0;i<=nbcurveC1-2;i++)
1444      ArrayOfToler(i)=tolerance;
1445    U2=BS->FirstParameter() ;
1446    j=BS->FirstUKnotIndex() + 1 ;
1447    for (i=0;i<nbcurveC1;i++){
1448      U1=U2;
1449
1450      while (j < BS->LastUKnotIndex() && BSMults(j) < BS->Degree())
1451        j++;
1452      
1453      U2=BSKnots(j);
1454      j++;
1455      Handle(Geom2d_BSplineCurve) BSbis=Handle(Geom2d_BSplineCurve)::DownCast(BS->Copy());
1456      BSbis->Segment(U1,U2);
1457      ArrayOfCurves(i)=BSbis;
1458    }
1459
1460    const Standard_Real anAngularToler = 1.0e-7;
1461    Handle(TColStd_HArray1OfInteger) ArrayOfIndices;
1462    Handle(TColGeom2d_HArray1OfBSplineCurve) ArrayOfConcatenated;
1463     
1464    BS->D1(BS->FirstParameter(),point1,V1);  //a verifier
1465    BS->D1(BS->LastParameter(),point2,V2);
1466    
1467    if ((point1.SquareDistance(point2) < gp::Resolution()) &&
1468        (V1.IsParallel(V2, anAngularToler)))
1469    {
1470      closed_flag = Standard_True;
1471    }
1472
1473    Geom2dConvert::ConcatC1(ArrayOfCurves,
1474                            ArrayOfToler,
1475                            ArrayOfIndices,
1476                            ArrayOfConcatenated,
1477                            closed_flag,
1478                            tolerance);
1479     
1480    Geom2dConvert_CompCurveToBSplineCurve C(ArrayOfConcatenated->Value(0));
1481    if (ArrayOfConcatenated->Length()>=2){
1482      for (i=1;i<ArrayOfConcatenated->Length();i++){
1483        fusion=C.Add(ArrayOfConcatenated->Value(i),tolerance);
1484        if (fusion==Standard_False)
1485          Standard_ConstructionError::Raise("Geom2dConvert Concatenation Error") ;
1486      }
1487    }
1488    BS=C.BSplineCurve();
1489  }
1490 }
1491 //=======================================================================
1492 //function : C0BSplineToArrayOfC1BSplineCurve
1493 //purpose  : 
1494 //=======================================================================
1495
1496 void Geom2dConvert::C0BSplineToArrayOfC1BSplineCurve(const Handle(Geom2d_BSplineCurve) &        BS,
1497                                                      Handle(TColGeom2d_HArray1OfBSplineCurve) & tabBS,
1498                                                      const Standard_Real                        tolerance)
1499   {
1500     C0BSplineToArrayOfC1BSplineCurve(BS,
1501                                      tabBS,
1502                                      tolerance,
1503                                      Precision::Angular());
1504   }
1505 //=======================================================================
1506 //function : C0BSplineToArrayOfC1BSplineCurve
1507 //purpose  : 
1508 //=======================================================================
1509
1510 void Geom2dConvert::C0BSplineToArrayOfC1BSplineCurve(const Handle(Geom2d_BSplineCurve) &        BS,
1511                                                      Handle(TColGeom2d_HArray1OfBSplineCurve) & tabBS,
1512                                                      const Standard_Real                        AngularTolerance,
1513                                                      const Standard_Real                        Tolerance) 
1514
1515 {
1516   TColStd_Array1OfInteger          BSMults(1,BS->NbKnots());
1517   TColStd_Array1OfReal             BSKnots(1,BS->NbKnots());
1518   Standard_Integer                 i,j,nbcurveC1=1;
1519   Standard_Real                    U1,U2;
1520   Standard_Boolean                 closed_flag = Standard_False ;
1521   gp_Pnt2d                         point1, point2;
1522   gp_Vec2d                         V1,V2;
1523 //  Standard_Boolean                 fusion;
1524   
1525   BS->Knots(BSKnots);
1526   BS->Multiplicities(BSMults);
1527   for (i=BS->FirstUKnotIndex() ;i<=(BS->LastUKnotIndex()-1);i++){
1528     if (BSMults(i)==BS->Degree())
1529       nbcurveC1++;   
1530   }
1531   
1532   nbcurveC1 = Min(nbcurveC1, BS->NbKnots() - 1); 
1533
1534   if (nbcurveC1>1){
1535     TColGeom2d_Array1OfBSplineCurve  ArrayOfCurves(0,nbcurveC1-1);
1536     TColStd_Array1OfReal             ArrayOfToler(0,nbcurveC1-2);
1537     
1538     for (i=0;i<=nbcurveC1-2;i++)
1539       ArrayOfToler(i)=Tolerance;
1540     U2=BS->FirstParameter() ;
1541     j=BS->FirstUKnotIndex()+ 1 ;
1542     for (i=0;i<nbcurveC1;i++){
1543       U1=U2;
1544       while (j < BS->LastUKnotIndex() && BSMults(j)<BS->Degree())
1545         j++;
1546       U2=BSKnots(j);
1547       j++;
1548       Handle(Geom2d_BSplineCurve) BSbis=Handle(Geom2d_BSplineCurve)::DownCast(BS->Copy());
1549       BSbis->Segment(U1,U2);
1550       ArrayOfCurves(i)=BSbis;
1551     }
1552     
1553     Handle(TColStd_HArray1OfInteger) ArrayOfIndices;
1554     
1555     BS->D1(BS->FirstParameter(),point1,V1);  
1556     BS->D1(BS->LastParameter(),point2,V2);
1557     
1558     if (((point1.SquareDistance(point2) < gp::Resolution())) &&
1559         (V1.IsParallel(V2, AngularTolerance)))
1560     {
1561       closed_flag = Standard_True;
1562     }
1563     
1564     Geom2dConvert::ConcatC1(ArrayOfCurves,
1565                             ArrayOfToler,
1566                             ArrayOfIndices,
1567                             tabBS,
1568                             closed_flag,
1569                             Tolerance,
1570                             AngularTolerance) ;
1571   }
1572   else{
1573     tabBS = new TColGeom2d_HArray1OfBSplineCurve(0,0);
1574     tabBS->SetValue(0,BS);
1575   }
1576 }  
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618