0031682: Visualization - Prs3d_ShadingAspect::SetTransparency() has no effect with...
[occt.git] / src / GeomFill / GeomFill_SweepSectionGenerator.cxx
1 // Created on: 1994-02-28
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1994-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Adaptor3d_HCurve.hxx>
19 #include <ElCLib.hxx>
20 #include <GCPnts_QuasiUniformDeflection.hxx>
21 #include <Geom_BSplineCurve.hxx>
22 #include <Geom_Circle.hxx>
23 #include <Geom_Curve.hxx>
24 #include <Geom_TrimmedCurve.hxx>
25 #include <GeomAdaptor.hxx>
26 #include <GeomAdaptor_Curve.hxx>
27 #include <GeomConvert.hxx>
28 #include <GeomFill_Profiler.hxx>
29 #include <GeomFill_SweepSectionGenerator.hxx>
30 #include <gp_Ax2.hxx>
31 #include <gp_Ax3.hxx>
32 #include <gp_Dir.hxx>
33 #include <gp_Pnt.hxx>
34 #include <gp_Trsf.hxx>
35 #include <gp_Vec.hxx>
36 #include <Precision.hxx>
37 #include <Standard_RangeError.hxx>
38 #include <TColStd_Array1OfReal.hxx>
39
40 #include <stdio.h>
41 #ifdef DRAW
42 #include <DrawTrSurf.hxx>
43 #include <Geom_BSplineCurve.hxx>
44 static Standard_Boolean Affich     = Standard_False;
45 static Standard_Integer NbSECTIONS = 0;
46 #endif
47
48 //=======================================================================
49 //function : GeomFill_SweepSectionGenerator
50 //purpose  : 
51 //=======================================================================
52
53 GeomFill_SweepSectionGenerator::GeomFill_SweepSectionGenerator()
54 : myRadius(0.0),
55   myIsDone(Standard_False),
56   myNbSections(0),
57   myType(-1),
58   myPolynomial(Standard_False)
59 {
60 }
61
62
63 //=======================================================================
64 //function : GeomFill_SweepSectionGenerator
65 //purpose  : 
66 //=======================================================================
67
68 GeomFill_SweepSectionGenerator::GeomFill_SweepSectionGenerator
69   (const Handle(Geom_Curve)& Path,
70    const Standard_Real       Radius)
71 {
72   Init(Path,Radius);
73 }
74
75
76 //=======================================================================
77 //function : GeomFill_SweepSectionGenerator
78 //purpose  : 
79 //=======================================================================
80
81 GeomFill_SweepSectionGenerator::GeomFill_SweepSectionGenerator
82   (const Handle(Geom_Curve)& Path,
83    const Handle(Geom_Curve)& FirstSect)
84 {
85   Init(Path,FirstSect);
86 }
87
88
89 //=======================================================================
90 //function : GeomFill_SweepSectionGenerator
91 //purpose  : 
92 //=======================================================================
93
94 GeomFill_SweepSectionGenerator::GeomFill_SweepSectionGenerator
95   (const Handle(Geom_Curve)& Path,
96    const Handle(Geom_Curve)& FirstSect,
97    const Handle(Geom_Curve)& LastSect  )
98 {
99   Init(Path,FirstSect,LastSect);
100 }
101
102
103 //=======================================================================
104 //function : GeomFill_SweepSectionGenerator
105 //purpose  : 
106 //=======================================================================
107
108 GeomFill_SweepSectionGenerator::GeomFill_SweepSectionGenerator
109   (const Handle(Adaptor3d_HCurve)& Path,
110    const Handle(Adaptor3d_HCurve)& Curve1,
111    const Handle(Adaptor3d_HCurve)& Curve2,
112    const Standard_Real       Radius)
113 {
114   Init(Path,Curve1,Curve2,Radius);
115 }
116
117
118 //=======================================================================
119 //function : Init
120 //purpose  : 
121 //=======================================================================
122
123 void GeomFill_SweepSectionGenerator::Init(const Handle(Geom_Curve)& Path,
124                                           const Standard_Real       Radius)
125 {
126   myIsDone = Standard_False;
127   myRadius = Radius;
128   GeomAdaptor_Curve ThePath(Path);
129
130   if (ThePath.GetType() == GeomAbs_Circle) {
131     
132     myCircPathAxis = ThePath.Circle().Axis();
133     myType = 4;
134   }
135   else myType = 1;
136   if ( Path->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
137     myPath = Handle(Geom_BSplineCurve)::DownCast(Path->Copy());
138   }
139   else {
140     myPath = GeomConvert::CurveToBSplineCurve(Path);
141   }
142 }
143
144
145 //=======================================================================
146 //function : Init
147 //purpose  : 
148 //=======================================================================
149 void GeomFill_SweepSectionGenerator::Init
150   (const Handle(Geom_Curve)& Path,
151    const Handle(Geom_Curve)& FirstSect)
152 {
153   myIsDone = Standard_False;
154   myRadius = 0; 
155   GeomAdaptor_Curve ThePath(Path);
156
157   if (ThePath.GetType() == GeomAbs_Circle) {    
158     myCircPathAxis = ThePath.Circle().Axis();
159     myType = 5;
160   }
161
162   else  myType   = 2;
163   
164   if ( Path->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
165     myPath = Handle(Geom_BSplineCurve)::DownCast(Path->Copy());
166   }
167   else {
168     myPath = GeomConvert::CurveToBSplineCurve(Path);
169   }
170   if ( FirstSect->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
171       myFirstSect = Handle(Geom_BSplineCurve)::DownCast(FirstSect->Copy());
172     }
173   else {
174     // JAG
175     myFirstSect = GeomConvert::CurveToBSplineCurve(FirstSect,
176                                                    Convert_QuasiAngular);
177   }
178   if ( myFirstSect->IsPeriodic()) myFirstSect->SetNotPeriodic();
179 }
180
181
182 //=======================================================================
183 //function : Init
184 //purpose  : 
185 //=======================================================================
186
187 void GeomFill_SweepSectionGenerator::Init
188   (const Handle(Geom_Curve)& Path,
189    const Handle(Geom_Curve)& FirstSect,
190    const Handle(Geom_Curve)& LastSect  )
191 {
192   myIsDone = Standard_False;
193   myRadius = 0;
194   GeomAdaptor_Curve ThePath(Path);
195
196   if (ThePath.GetType() == GeomAbs_Circle) {
197     
198     myCircPathAxis = ThePath.Circle().Axis();
199     myType = 6;
200   }
201   else myType   = 3;
202   
203   if ( Path->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
204     myPath = Handle(Geom_BSplineCurve)::DownCast(Path->Copy());
205   }
206   else {
207     myPath = GeomConvert::CurveToBSplineCurve(Path);
208   }
209   
210   // JAG
211   if ( FirstSect->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
212       myFirstSect = Handle(Geom_BSplineCurve)::DownCast(FirstSect->Copy());
213     }
214   else {
215     myFirstSect = GeomConvert::CurveToBSplineCurve(FirstSect,
216                                                    Convert_QuasiAngular);
217   }
218   if ( LastSect->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
219       myLastSect = Handle(Geom_BSplineCurve)::DownCast(LastSect->Copy());
220     }
221   else {
222     myLastSect = GeomConvert::CurveToBSplineCurve(LastSect,
223                                                    Convert_QuasiAngular);
224   }
225
226   if ( myFirstSect->IsPeriodic()) myFirstSect->SetNotPeriodic();
227   if ( myLastSect->IsPeriodic()) myLastSect->SetNotPeriodic();
228
229
230   // JAG
231
232   GeomFill_Profiler Profil;
233   Profil.AddCurve(myFirstSect);
234   Profil.AddCurve(myLastSect);
235   Profil.Perform(Precision::Confusion());
236   
237   myFirstSect = Handle(Geom_BSplineCurve)::DownCast(Profil.Curve(1));
238   myLastSect  = Handle(Geom_BSplineCurve)::DownCast(Profil.Curve(2));
239 }
240
241
242 //=======================================================================
243 //function : Init
244 //purpose  : 
245 //=======================================================================
246
247 void GeomFill_SweepSectionGenerator::Init
248   (const Handle(Adaptor3d_HCurve)& Path,
249    const Handle(Adaptor3d_HCurve)& Curve1,
250    const Handle(Adaptor3d_HCurve)& Curve2,
251    const Standard_Real       Radius)
252 {
253   myIsDone = Standard_False;
254   myRadius = Radius;
255   myType   = 0;
256
257   Handle(Geom_Curve) CC = GeomAdaptor::MakeCurve(Path->Curve());
258   myPath         = GeomConvert::CurveToBSplineCurve(CC);
259   myAdpPath      = Path;
260   myAdpFirstSect = Curve1;
261   myAdpLastSect  = Curve2;
262 }
263
264
265 //=======================================================================
266 //function : Perform
267 //purpose  : 
268 //=======================================================================
269
270 void GeomFill_SweepSectionGenerator::Perform(const Standard_Boolean Polynomial)
271 {
272   myPolynomial = Polynomial;
273
274   // eval myNbSections.
275   Standard_Integer NSpans = myPath->NbKnots()-1;
276
277   myNbSections = 21 * NSpans;
278
279   Standard_Real U;
280
281   Standard_Real U1 = myPath->FirstParameter();
282   Standard_Real U2 = myPath->LastParameter();
283   
284   GCPnts_QuasiUniformDeflection Samp;
285   // Calcul de la longueur approximative de la courbe
286   GeomAdaptor_Curve AdpPath(myPath);
287   gp_Pnt P1 = AdpPath.Value(U1);
288   gp_Pnt P2 = AdpPath.Value((U1+U2)/2.);
289   gp_Pnt P3 = AdpPath.Value(U2);
290   Standard_Real Length = 
291     P1.Distance(P2) + P2.Distance(P3);
292   Standard_Real Fleche = 1.e-5 * Length;
293   Samp.Initialize(AdpPath,Fleche);
294
295   if ( Samp.IsDone() && (Samp.NbPoints() > myNbSections) ) {
296     myNbSections = Samp.NbPoints();
297   }
298   // the transformations are calculate on differents points of <myPath>
299   // corresponding to the path parameter uniformly reparted.
300   Standard_Real DeltaU = (U2-U1)/(Standard_Real)(myNbSections-1);
301   TColStd_Array1OfReal Parameters(1,myNbSections);
302 //  Parameters(1) = U1;
303 //  for (Standard_Integer i = 2; i < myNbSections; i++) {
304 //    Parameters(i) = U1 + (i-1) * DeltaU;
305 //  }
306 //  Parameters(myNbSections) = U2;
307   
308   Parameters(1) = 0.;
309   for (Standard_Integer i = 2; i < myNbSections; i++) {
310     Parameters(i) = (i-1) * DeltaU;
311   }
312   Parameters(myNbSections) = U2 - U1;
313
314   gp_Vec D1Ref, D1;
315   gp_Pnt PRef , P; 
316   gp_Trsf TR, cumulTR, Trans;
317
318   myPath->D1( U1, PRef, D1Ref); 
319
320   if ( ( myType == 1) || (myType == 4) ) {
321     // We create a circle with radius <myRadius>. This axis is create with
322     // main direction <DRef> (first derivate vector of <myPath> on the first
323     // point <PRef> ). This circle is, after transform to BSpline curve, 
324     // put in <myFirstSect>.
325                               
326     gp_Ax2 CircleAxis (PRef,D1Ref);
327 /*
328     Handle(Geom_Circle) Circ = new Geom_Circle( CircleAxis, myRadius); 
329     
330     myFirstSect = GeomConvert::CurveToBSplineCurve(Circ);
331     // le cercle est segmente car AppBlend_AppSurf ne gere
332     // pas les courbes periodiques.
333     myFirstSect->Segment(0., 2.*M_PI);
334 */
335     Handle(Geom_TrimmedCurve) Circ = 
336       new Geom_TrimmedCurve(new Geom_Circle( CircleAxis, myRadius), 
337                             0., 2.*M_PI); 
338     
339     myFirstSect = GeomConvert::CurveToBSplineCurve(Circ,Convert_QuasiAngular);
340   }
341   
342   if (myType <= 3 && myType >=1 ) {
343     
344     for (Standard_Integer i = 2; i <= myNbSections; i++) {
345
346       U = Parameters(i) + U1;
347       if (i == myNbSections) U = U2;
348
349       myPath->D1( U, P, D1);
350     
351       // Eval the translation between the (i-1) section and the i-th.
352       Trans.SetTranslation(PRef, P);
353
354       gp_Trsf Rot;
355       if (! D1Ref.IsParallel(D1, Precision::Angular())) {
356         // Eval the Rotation between (i-1) section and the i-th.
357         Rot.SetRotation(gp_Ax1(P, gp_Dir(D1Ref^D1)), 
358                         D1Ref.AngleWithRef(D1, D1Ref^D1));
359       }
360       else
361         if (D1Ref.IsOpposite(D1, Precision::Angular()))
362 #ifdef OCCT_DEBUG
363           std::cout <<"Que fais-je ???? " << std::endl;
364 #endif
365
366       // TR is the transformation between (i-1) section and the i-th.
367       TR = Rot * Trans;
368       // cumulTR is the transformation between <myFirstSec> and 
369       // the i-th section.
370       cumulTR = TR * cumulTR;
371
372       myTrsfs.Append(cumulTR);
373       
374       PRef = P;
375       D1Ref = D1;
376     }
377   }
378   else if ( myType != 0) { 
379     for (Standard_Integer i = 2; i<= myNbSections; i++) {
380       cumulTR.SetRotation(myCircPathAxis, Parameters(i));
381       myTrsfs.Append(cumulTR);      
382     }
383   }
384     
385   myIsDone = Standard_True;
386 }
387
388 //=======================================================================
389 //function : GetShape
390 //purpose  : 
391 //=======================================================================
392
393 void GeomFill_SweepSectionGenerator::GetShape
394   (Standard_Integer& NbPoles,
395    Standard_Integer& NbKnots,
396    Standard_Integer& Degree,
397    Standard_Integer& NbPoles2d) const 
398 {
399 /* 
400  if ( myType == 1) {
401     NbPoles   = 7;
402     NbKnots   = 4;
403     Degree    = 2;
404   }
405   else {
406 */
407   if ( myType != 0) {
408     NbPoles = myFirstSect->NbPoles();
409     NbKnots = myFirstSect->NbKnots();
410     Degree  = myFirstSect->Degree();
411   }
412   else { // myType == 0
413     NbPoles   = 7;
414     NbKnots   = 2;
415     Degree    = 6;
416   }
417   NbPoles2d = 0;
418 }
419
420
421 //=======================================================================
422 //function : Knots
423 //purpose  : 
424 //=======================================================================
425
426 void GeomFill_SweepSectionGenerator::Knots(TColStd_Array1OfReal& TKnots) const 
427 {
428 /*
429   if (myType == 1) {
430     Standard_Real U = 2.*M_PI/3.;
431     for ( Standard_Integer i = 1; i <= 4; i++) 
432       TKnots(i) = ( i-1) * U;
433   }
434   else {
435 */
436   if (myType !=0) {
437     myFirstSect->Knots(TKnots);
438   }
439   else {
440     TKnots(1) = 0.;
441     TKnots(2) = 1.;
442   }
443 //  }
444 }
445
446
447 //=======================================================================
448 //function : Mults
449 //purpose  : 
450 //=======================================================================
451
452 void GeomFill_SweepSectionGenerator::Mults(TColStd_Array1OfInteger& TMults)
453   const 
454 {
455 /*
456   if ( myType == 1) {
457     TMults( 1) = TMults( 4) = 3;
458     TMults( 2) = TMults( 3) = 2;
459   }
460   else {
461 */
462   if ( myType != 0) {
463     myFirstSect->Multiplicities(TMults);
464   }
465   else {
466     TMults( 1) = TMults( 2) = 7;
467   }
468 //  }
469 }
470
471
472 //=======================================================================
473 //function : Section
474 //purpose  : 
475 //=======================================================================
476
477 Standard_Boolean GeomFill_SweepSectionGenerator::Section
478   (const Standard_Integer      P,
479          TColgp_Array1OfPnt&   Poles, 
480          TColgp_Array1OfVec&   DPoles,
481          TColgp_Array1OfPnt2d& Poles2d,
482          TColgp_Array1OfVec2d& , //DPoles2d,
483          TColStd_Array1OfReal& Weigths,
484          TColStd_Array1OfReal& DWeigths
485    ) const 
486 {
487   Section( P, Poles, Poles2d, Weigths);
488
489   // pour les tuyaux sur aretes pour l'instant on ne calcule pas les derivees
490   if ( myType == 0 ) return Standard_False; // a voir pour mieux.
491
492   // calcul des derivees sur la surface
493   // on calcule les derivees en approximant le path au voisinage du point
494   // P(u) par le cercle osculateur au path .
495
496   // calcul du cercle osculateur.
497
498   Standard_Real U;
499   if ( P == 1) {
500     U = myPath->FirstParameter();
501   }
502   else if ( P == myNbSections ) {
503     U = myPath->LastParameter();
504   }
505   else
506     return Standard_False;
507     
508   gp_Vec D1, D2;
509   gp_Pnt Pt;
510
511   myPath->D2(U,Pt,D1,D2);
512   Standard_Real l = D1.Magnitude();
513   
514   if ( l < Epsilon(1.))
515     return Standard_False;
516
517   gp_Dir T = D1;
518   Standard_Real m = D2.Dot(T);
519   gp_Vec D = D2 - m * T;
520   Standard_Real c = D.Magnitude() / (l*l);
521   
522   if ( c < Epsilon(1.)) { 
523     // null curvature : equivalent to a translation of the section 
524     for (Standard_Integer i = 1; i <= myFirstSect->NbPoles(); i++) {
525       DPoles(i) = D1;
526     }    
527   }
528   else {
529     gp_Dir N = D;
530     gp_Pnt Q = Pt.Translated( (1./c) * gp_Vec(N));
531     Standard_Real x, y;
532     gp_Vec V;
533     for ( Standard_Integer i = 1; i <= myFirstSect->NbPoles(); i++) {
534       V = gp_Vec(Q, Poles(i));
535       x = V * gp_Vec(T);
536       y = V * gp_Vec(N);
537       DPoles(i) = x * gp_Vec(N) - y * gp_Vec(T);
538       if ( DPoles(i).Magnitude() > Epsilon(1.)) {
539         DPoles(i).Normalize();
540         DPoles(i) *= Sqrt( x*x + y*y);
541       }
542     }
543   }
544   
545   for ( Standard_Integer i = 1; i <= myFirstSect->NbPoles(); i++) {
546     DWeigths(i) = 0.;
547   }
548   
549   return Standard_True;
550 }
551
552
553 //=======================================================================
554 //function : Section
555 //purpose  : 
556 //=======================================================================
557
558 void GeomFill_SweepSectionGenerator::Section
559   (const Standard_Integer      P,
560          TColgp_Array1OfPnt&   Poles,
561          TColgp_Array1OfPnt2d& , //Poles2d, 
562          TColStd_Array1OfReal& Weigths) const 
563 {
564   if (myType != 0) {
565     myFirstSect->Poles(Poles);
566     myFirstSect->Weights(Weigths);
567     gp_Trsf cumulTR;
568     if (P > 1) {
569       cumulTR = myTrsfs(P - 1); 
570       // <cumulTR> transform <myFirstSect> to the P ieme Section. In fact
571       // each points of the array <poles> will be transformed.
572       
573       if ( (myType == 3 ) || (myType == 6) ){
574         for (Standard_Integer i = 1; i <= myFirstSect->NbPoles(); i++) {
575           Poles(i).SetXYZ( (myNbSections - P) * myFirstSect->Pole(i).XYZ() +
576                           (P - 1) * myLastSect->Pole(i).XYZ() );
577           Poles(i).SetXYZ( Poles(i).XYZ() / (myNbSections - 1));
578           
579           Weigths(i) = (myNbSections - P) * myFirstSect->Weight(i) +
580             (P - 1) * myLastSect->Weight(i);
581           Weigths(i) /= myNbSections - 1;
582         }
583       }
584       
585       for (Standard_Integer i = 1; i<=Poles.Length(); i++)
586         Poles(i).Transform(cumulTR);
587     }
588 #ifdef DRAW
589     if ( Affich) {
590       char name[256];
591       sprintf(name,"SECTION_%d",++NbSECTIONS);
592       DrawTrSurf::Set(name,myFirstSect->Transformed(cumulTR));
593     }
594 #endif
595   }
596   else {
597
598     Standard_Real Coef = (P -1. ) / ( myNbSections - 1.);
599     Standard_Real U = 
600       ( 1- Coef) * myAdpPath->FirstParameter() +
601         Coef     * myAdpPath->LastParameter();
602
603     gp_Pnt PPath = myAdpPath->Value(U);
604     
605     Standard_Real Alpha = U - myAdpPath->FirstParameter();
606     Alpha /= myAdpPath->LastParameter() - myAdpPath->FirstParameter();
607     
608     Standard_Real U1 = 
609       ( 1- Alpha) * myAdpFirstSect->FirstParameter() +
610         Alpha     * myAdpFirstSect->LastParameter();
611     
612     gp_Pnt P1 = myAdpFirstSect->Value(U1);
613     
614     Standard_Real U2 = 
615       ( 1- Alpha) * myAdpLastSect->FirstParameter() +
616         Alpha     * myAdpLastSect->LastParameter();
617     
618     gp_Pnt P2 = myAdpLastSect->Value(U2);
619     
620     gp_Ax2 Axis;
621     Standard_Real Angle;
622     if ( P1.Distance(P2) < Precision::Confusion()) {
623       Angle = 0.;
624     }
625     else {
626       Axis = gp_Ax2(PPath, 
627                     gp_Vec(PPath,P1) ^ gp_Vec(PPath,P2),
628                     gp_Vec(PPath,P1));
629       Angle = ElCLib::CircleParameter(Axis,P2);
630     }
631 #ifdef OCCT_DEBUG
632 /*
633     if (Standard_False) {
634       gp_Vec dummyD1 = myAdpPath->DN(U,1);
635       gp_Vec dummyTg = Axis.Direction();
636       Standard_Real Cos = dummyD1.Dot(dummyTg);
637       if ( Cos > 0.) std::cout << "+" ;
638       else           std::cout << "-" ;
639     }
640 */
641 #endif
642     if ( Angle < Precision::Angular()) {
643       for ( Standard_Integer i = 1; i <= Poles.Upper(); i++) {
644         Poles(i) = P1;
645         Weigths(i) = 1;
646       }
647     }
648     else {
649       Handle(Geom_Circle) Circ =
650         new Geom_Circle( Axis, myRadius);
651       Handle(Geom_TrimmedCurve) CT = 
652         new Geom_TrimmedCurve(Circ, 0., Angle);
653       Handle(Geom_BSplineCurve) BS;
654       if ( myPolynomial) 
655         BS = GeomConvert::CurveToBSplineCurve( CT, Convert_Polynomial);
656       else 
657         BS = GeomConvert::CurveToBSplineCurve( CT, Convert_QuasiAngular);
658
659 #ifdef DRAW
660       if ( Affich) {
661         char name[256];
662         sprintf(name,"SECTION_%d",++NbSECTIONS);
663         DrawTrSurf::Set(name,BS);
664       }
665 #endif
666       
667       BS->Poles(Poles);
668       BS->Weights(Weigths);
669     }
670   }
671 }
672
673 //=======================================================================
674 //function : Transformation
675 //purpose  : 
676 //=======================================================================
677 const gp_Trsf& GeomFill_SweepSectionGenerator::Transformation
678   (const Standard_Integer Index) const 
679 {
680   if (Index > myTrsfs.Length())
681     throw Standard_RangeError("GeomFill_SweepSectionGenerator::Transformation");
682   
683   return myTrsfs(Index);
684 }
685
686
687 //=======================================================================
688 //function : Parameter
689 //purpose  : 
690 //=======================================================================
691
692 Standard_Real GeomFill_SweepSectionGenerator::Parameter
693   (const Standard_Integer P) const
694 {
695   if (P == 1) {
696     return myPath->FirstParameter();
697   }
698   else if (P == myNbSections) {
699     return myPath->LastParameter();
700   }
701   else {
702     Standard_Real U1 = myPath->FirstParameter();
703     Standard_Real U2 = myPath->LastParameter();
704     Standard_Real prm = ((myNbSections-P)*U1 + (P-1)*U2)/
705       (Standard_Real)(myNbSections-1);
706     return prm;
707   }
708 }