0025256: Small optimization in Convert comp bezier to BSpline
[occt.git] / src / Convert / Convert_CompBezierCurvesToBSplineCurve.cxx
1 // Created on: 1993-10-20
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1993-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 #include <Convert_CompBezierCurvesToBSplineCurve.ixx>
18
19 #include <Precision.hxx>
20 #include <BSplCLib.hxx>
21 #include <PLib.hxx>
22 #include <gp_Pnt.hxx>
23 #include <gp.hxx>
24 #include <gp_Vec.hxx>
25 #include <TColgp_HArray1OfPnt.hxx>
26
27
28 //=======================================================================
29 //function : Convert_CompBezierCurvesToBSplineCurve
30 //purpose  : 
31 //=======================================================================
32
33
34 Convert_CompBezierCurvesToBSplineCurve::
35 Convert_CompBezierCurvesToBSplineCurve(
36                   const Standard_Real AngularTolerance) :
37                   myAngular(AngularTolerance),
38                   myDone(Standard_False)
39 {
40 }
41
42
43 //=======================================================================
44 //function : AddCurve
45 //purpose  : 
46 //=======================================================================
47
48 void  Convert_CompBezierCurvesToBSplineCurve::AddCurve
49   (const TColgp_Array1OfPnt& Poles)
50 {
51   if ( !mySequence.IsEmpty()) {
52     gp_Pnt P1,P2;
53     P1 = mySequence.Last()->Value(mySequence.Last()->Upper());
54     P2 = Poles(Poles.Lower());
55
56     // NYI
57   if ( !P1.IsEqual(P2,Precision::Confusion()))
58       cout << "Convert_CompBezierCurvesToBSplineCurve::Addcurve" << endl;;
59   }
60   myDone = Standard_False;
61   Handle(TColgp_HArray1OfPnt) HPoles = 
62     new TColgp_HArray1OfPnt(Poles.Lower(),Poles.Upper());
63   HPoles->ChangeArray1() = Poles;
64   mySequence.Append(HPoles);
65 }
66
67
68 //=======================================================================
69 //function : Degree
70 //purpose  : 
71 //=======================================================================
72
73 Standard_Integer  Convert_CompBezierCurvesToBSplineCurve::Degree() const
74 {
75   return myDegree;
76 }
77
78
79 //=======================================================================
80 //function : NbPoles
81 //purpose  : 
82 //=======================================================================
83
84 Standard_Integer  Convert_CompBezierCurvesToBSplineCurve::NbPoles() const
85 {
86   return CurvePoles.Length();
87 }
88
89
90 //=======================================================================
91 //function : Poles
92 //purpose  : 
93 //=======================================================================
94
95 void  Convert_CompBezierCurvesToBSplineCurve::Poles
96   (TColgp_Array1OfPnt& Poles) const
97 {
98   Standard_Integer i, Lower = Poles.Lower(), Upper = Poles.Upper();
99   Standard_Integer k = 1;
100   for (i = Lower; i <= Upper; i++) {
101     Poles(i) = CurvePoles(k++);
102   }
103 }
104
105
106 //=======================================================================
107 //function : NbKnots
108 //purpose  : 
109 //=======================================================================
110
111 Standard_Integer  Convert_CompBezierCurvesToBSplineCurve::NbKnots() const
112 {
113   return CurveKnots.Length();
114 }
115
116
117 //=======================================================================
118 //function : KnotsAndMults
119 //purpose  : 
120 //=======================================================================
121
122 void  Convert_CompBezierCurvesToBSplineCurve::KnotsAndMults
123   (TColStd_Array1OfReal&    Knots, 
124    TColStd_Array1OfInteger& Mults ) const
125 {
126   Standard_Integer i, LowerK = Knots.Lower(), UpperK = Knots.Upper();
127   Standard_Integer LowerM = Mults.Lower(), UpperM = Mults.Upper();
128   Standard_Integer k = 1;
129   for (i = LowerK; i <= UpperK; i++) {
130     Knots(i) = CurveKnots(k++);
131   }
132   k = 1;
133   for (i = LowerM; i <= UpperM; i++) {
134     Mults(i) = KnotsMultiplicities(k++);
135   }
136 }
137
138
139
140 //=======================================================================
141 //function : Perform
142 //purpose  : 
143 //=======================================================================
144
145 void Convert_CompBezierCurvesToBSplineCurve::Perform() 
146 {
147   myDone = Standard_True;
148   CurvePoles.Clear();
149   CurveKnots.Clear();
150   KnotsMultiplicities.Clear();
151   Standard_Integer LowerI     = 1;
152   Standard_Integer UpperI     = mySequence.Length();
153   Standard_Integer NbrCurv    = UpperI-LowerI+1;
154 //  Standard_Integer NbKnotsSpl = NbrCurv + 1 ;
155   TColStd_Array1OfReal     CurveKnVals         (1,NbrCurv);
156
157   Standard_Integer i;
158   myDegree = 0;
159   for ( i = 1; i <= mySequence.Length(); i++) {
160     myDegree = Max( myDegree, (mySequence(i))->Length() -1);
161   }
162
163   Standard_Real Det=0;
164   gp_Pnt P1, P2, P3;
165   Standard_Integer Deg, Inc, MaxDegree = myDegree;
166   TColgp_Array1OfPnt Points(1, myDegree+1);
167
168   for (i = LowerI ; i <= UpperI ; i++) {
169     // 1- Raise the Bezier curve to the maximum degree.
170     Deg = mySequence(i)->Length()-1;
171     Inc = myDegree - Deg;
172     if ( Inc > 0) {
173       BSplCLib::IncreaseDegree(myDegree, 
174                                mySequence(i)->Array1(), PLib::NoWeights(), 
175                                Points, PLib::NoWeights());
176     }
177     else {
178       Points = mySequence(i)->Array1();
179     }
180
181     // 2- Process the node of junction between 2 Bezier curves.
182     if (i == LowerI) {
183       // Processing of the initial node of the BSpline.
184       for (Standard_Integer j = 1 ; j <= MaxDegree ; j++) {
185         CurvePoles.Append(Points(j));
186       }
187       CurveKnVals(1)         = 1.; // To begin the series.
188       KnotsMultiplicities.Append(MaxDegree+1);
189       Det = 1.;
190     }
191
192
193     if (i != LowerI) {
194       P2 = Points(1);
195       P3 = Points(2);
196       gp_Vec V1(P1, P2), V2(P2, P3);
197
198       // Processing of the tangency between Bezier and the previous.
199       // This allows to guarantee at least a C1 continuity if the tangents are  
200       // coherent.
201       
202       Standard_Real D1 = V1.SquareMagnitude();
203       Standard_Real D2 = V2.SquareMagnitude();
204       if (D1 > gp::Resolution() && D2 > gp::Resolution() && V1.IsParallel(V2, myAngular )) {
205           Standard_Real Lambda = Sqrt(D2/D1);
206           if(CurveKnVals(i-1) * Lambda > 10. * Epsilon(Det)) {
207             KnotsMultiplicities.Append(MaxDegree-1);
208             CurveKnVals(i) = CurveKnVals(i-1) * Lambda;
209             Det += CurveKnVals(i);
210           }
211           else {
212             CurvePoles.Append(Points(1));
213             KnotsMultiplicities.Append(MaxDegree);
214             CurveKnVals(i) = 1.0 ;
215             Det += CurveKnVals(i) ;
216           }
217       }
218       else {
219         CurvePoles.Append(Points(1));
220         KnotsMultiplicities.Append(MaxDegree);
221         CurveKnVals(i) = 1.0 ;
222         Det += CurveKnVals(i) ;
223       }
224
225       // Store the poles.
226       for (Standard_Integer j = 2 ; j <= MaxDegree ; j++) {
227         CurvePoles.Append(Points(j));
228       }
229
230     }
231
232
233     if (i == UpperI) {
234       // Processing of the end node of the BSpline.
235       CurvePoles.Append(Points(MaxDegree+1));
236       KnotsMultiplicities.Append(MaxDegree+1);
237     }
238     P1 = Points(MaxDegree);
239   }
240
241   // Correct nodal values to make them variable within [0.,1.].
242   CurveKnots.Append(0.0);
243 //  cout << "Convert : Det = " << Det << endl;
244   for (i = 2 ; i <= NbrCurv ; i++) {
245     CurveKnots.Append(CurveKnots(i-1) + (CurveKnVals(i-1)/Det));
246   }
247   CurveKnots.Append(1.0);
248 }
249
250