b311480e |
1 | // Created on: 1997-11-04 |
2 | // Created by: Roman BORISOV / Igor FEOKTISTOV |
3 | // Copyright (c) 1997-1999 Matra Datavision |
973c2be1 |
4 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
b311480e |
5 | // |
973c2be1 |
6 | // This file is part of Open CASCADE Technology software library. |
b311480e |
7 | // |
973c2be1 |
8 | // This library is free software; you can redistribute it and / or modify it |
9 | // under the terms of the GNU Lesser General Public 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. |
b311480e |
13 | // |
973c2be1 |
14 | // Alternatively, this file may be used under the terms of Open CASCADE |
15 | // commercial license or contractual agreement. |
7fd59977 |
16 | |
17 | #define No_Standard_RangeError |
18 | #define No_Standard_OutOfRange |
19 | |
20 | #include <FEmTool_Curve.ixx> |
21 | #include <PLib.hxx> |
22 | #include <PLib_JacobiPolynomial.hxx> |
23 | #include <PLib_HermitJacobi.hxx> |
24 | |
25 | //======================================================================= |
26 | //function : FEmTool_Curve |
27 | //purpose : |
28 | //======================================================================= |
29 | FEmTool_Curve::FEmTool_Curve(const Standard_Integer Dimension, |
258ff83b |
30 | const Standard_Integer NbElements, |
31 | const Handle(PLib_Base)& TheBase, |
32 | const Standard_Real) : |
7fd59977 |
33 | myNbElements(NbElements), myDimension(Dimension), |
7fd59977 |
34 | myBase(TheBase), myDegree(1, myNbElements), |
35 | myCoeff(1, myDimension*myNbElements*(myBase->WorkDegree() + 1)), |
36 | myPoly(1, myDimension*myNbElements*(myBase->WorkDegree() + 1)), |
37 | myDeri(1, myDimension*myNbElements*(myBase->WorkDegree())), |
38 | myDsecn(1, myDimension*myNbElements*(myBase->WorkDegree() - 1)), |
39 | HasPoly(1, myNbElements), HasDeri(1, myNbElements), |
40 | HasSecn(1, myNbElements), myLength(1, myNbElements), |
41 | myIndex(0) |
42 | { |
43 | myKnots = new TColStd_HArray1OfReal(1, myNbElements + 1); |
44 | myDegree.Init(myBase->WorkDegree()); |
45 | HasPoly.Init(0); |
46 | HasDeri.Init(0); |
47 | HasSecn.Init(0); |
48 | myLength.Init(-1); |
49 | } |
50 | |
51 | TColStd_Array1OfReal& FEmTool_Curve::Knots() const |
52 | { |
53 | return myKnots->ChangeArray1(); |
54 | } |
55 | |
56 | |
57 | |
58 | //======================================================================= |
59 | //function : SetElement |
60 | //purpose : |
61 | //======================================================================= |
62 | void FEmTool_Curve::SetElement(const Standard_Integer IndexOfElement, |
63 | const TColStd_Array2OfReal& Coeffs) |
64 | { |
65 | Standard_Integer i, j, degBase, deg; |
66 | if (IndexOfElement > myNbElements || IndexOfElement < 1) Standard_OutOfRange::Raise(); |
67 | degBase = myBase->WorkDegree(); |
68 | deg = myDegree(IndexOfElement); |
69 | Standard_Integer iBase = (IndexOfElement - 1)*(degBase + 1)*myDimension, |
70 | i1 = iBase-myDimension, i2 = Coeffs.LowerRow() - 1, |
71 | j1 = Coeffs.LowerCol() - 1; |
72 | for(i = 1; i <= deg + 1; i++) { |
73 | i1 += myDimension; i2++; |
74 | for(j = 1; j <= myDimension; j++) |
75 | myCoeff(i1 + j) = Coeffs(i2, j1 + j); |
76 | } |
77 | |
78 | Standard_Real stenor = (myKnots->Value(IndexOfElement + 1) - myKnots->Value(IndexOfElement)) / 2., |
79 | mfact; |
80 | Handle(PLib_HermitJacobi) myHermitJacobi = (*((Handle(PLib_HermitJacobi)*)&myBase)); |
81 | |
82 | i1 = iBase; |
83 | i2 = iBase + (myHermitJacobi->NivConstr() + 1) * myDimension; |
84 | for(i = 1; i <= myHermitJacobi->NivConstr(); i++) { |
85 | i1 += myDimension; i2 += myDimension; |
86 | mfact = Pow(stenor, i); |
87 | for(j = 1; j <= myDimension; j++) { |
88 | myCoeff(i1 + j) *= mfact; |
89 | myCoeff(i2 + j) *= mfact; |
90 | } |
91 | } |
92 | |
93 | HasPoly(IndexOfElement) = HasDeri(IndexOfElement) = HasSecn(IndexOfElement) = 0; |
94 | myLength(IndexOfElement) = - 1; |
95 | } |
96 | |
97 | |
98 | //======================================================================= |
99 | //function : GetElement |
100 | //purpose : |
101 | //======================================================================= |
102 | void FEmTool_Curve::GetElement(const Standard_Integer IndexOfElement, TColStd_Array2OfReal& Coeffs) |
103 | { |
104 | Standard_Integer i, j, degBase, deg; |
105 | if (IndexOfElement > myNbElements || IndexOfElement < 1) Standard_OutOfRange::Raise(); |
106 | degBase = myBase->WorkDegree(); |
107 | deg = myDegree(IndexOfElement); |
108 | Standard_Integer iBase = (IndexOfElement - 1)*(degBase + 1)*myDimension, |
109 | i1 = iBase-myDimension, i2 = Coeffs.LowerRow() - 1, |
110 | j1 = Coeffs.LowerCol() - 1; |
111 | for(i = 1; i <= deg + 1; i++) { |
112 | i1 += myDimension; i2++; |
113 | for(j = 1; j <= myDimension; j++) |
114 | Coeffs(i2, j1 + j) = myCoeff.Value(i1 + j); |
115 | } |
116 | |
117 | Standard_Real stenor = 2. / (myKnots->Value(IndexOfElement + 1) - myKnots->Value(IndexOfElement)), |
118 | mfact; |
119 | |
120 | Handle(PLib_HermitJacobi) myHermitJacobi = (*((Handle(PLib_HermitJacobi)*)&myBase)); |
121 | |
122 | i2 = Coeffs.LowerRow(); |
123 | Standard_Integer i3 = i2 + myHermitJacobi->NivConstr() + 1; |
124 | |
125 | for(i = 1; i <= myHermitJacobi->NivConstr(); i++) { |
126 | mfact = Pow(stenor, i); |
127 | for(j = j1+1; j <= myDimension; j++) { |
128 | Coeffs(i2 + i, j) *= mfact; |
129 | Coeffs(i3 + i, j) *= mfact; |
130 | } |
131 | } |
132 | } |
133 | |
134 | |
135 | //======================================================================= |
136 | //function : GetPolynom |
137 | //purpose : |
138 | //======================================================================= |
139 | void FEmTool_Curve::GetPolynom(TColStd_Array1OfReal& Coeffs) |
140 | |
141 | { |
142 | Standard_Integer IndexOfElement, i, di = Coeffs.Lower() - myPoly.Lower(); |
143 | |
144 | |
145 | for(IndexOfElement = 1; IndexOfElement <= myNbElements; IndexOfElement++) |
146 | if (!HasPoly.Value(IndexOfElement)) Update(IndexOfElement, 0); |
147 | |
148 | for(i = myPoly.Lower(); i <= myPoly.Upper(); i++) |
149 | Coeffs(di + i) = myPoly(i); |
150 | |
151 | } |
152 | |
153 | |
154 | //======================================================================= |
155 | //function : D0 |
156 | //purpose : |
157 | //======================================================================= |
158 | void FEmTool_Curve::D0(const Standard_Real U, TColStd_Array1OfReal& Pnt) |
159 | { |
160 | Standard_Integer deg; |
161 | Standard_Real S; |
162 | |
163 | if (!myIndex || (U<Uf) || (U>Ul) || |
164 | (myKnots->Value(myIndex)!=Uf) || |
165 | (myKnots->Value(myIndex+1)!=Ul)) { |
166 | // Search the span |
167 | if(U <= myKnots->Value(2)) myIndex = 1; |
168 | else { |
169 | for(myIndex = 2; myIndex <= myNbElements; myIndex++) |
170 | if(U >= myKnots->Value(myIndex) && U <= myKnots->Value(myIndex+1)) break; |
171 | if (myIndex > myNbElements) myIndex = myNbElements; |
172 | } |
173 | Uf = myKnots->Value(myIndex); |
174 | Ul = myKnots->Value(myIndex+1); |
175 | Denom = 1. /(Ul-Uf); |
176 | USum = Uf+Ul; |
177 | myPtr = (myIndex - 1)*(myBase->WorkDegree()+ 1)*myDimension + 1; |
178 | } |
179 | |
180 | deg = myDegree(myIndex); |
181 | if (!HasPoly.Value(myIndex)) Update(myIndex, 0); |
182 | |
183 | //Parameter normalization: S [-1, 1] |
184 | S = (2*U - USum)*Denom; |
185 | PLib::NoDerivativeEvalPolynomial(S, deg, myDimension, deg*myDimension, |
186 | myPoly(myPtr), Pnt(Pnt.Lower())); |
187 | } |
188 | |
189 | |
190 | //======================================================================= |
191 | //function : D1 |
192 | //purpose : |
193 | //======================================================================= |
194 | void FEmTool_Curve::D1(const Standard_Real U, TColStd_Array1OfReal& Vec) |
195 | { |
196 | Standard_Integer deg, i; |
197 | Standard_Real S; |
198 | |
199 | if (!myIndex || (U<Uf) || (U>Ul) || |
200 | (myKnots->Value(myIndex)!=Uf) || |
201 | (myKnots->Value(myIndex+1)!=Ul)) { |
202 | // Search the span |
203 | if(U <= myKnots->Value(2)) myIndex = 1; |
204 | else { |
205 | for(myIndex = 2; myIndex <= myNbElements; myIndex++) |
206 | if(U >= myKnots->Value(myIndex) && U <= myKnots->Value(myIndex+1)) break; |
207 | if (myIndex > myNbElements) myIndex = myNbElements; |
208 | } |
209 | Uf = myKnots->Value(myIndex); |
210 | Ul = myKnots->Value(myIndex+1); |
211 | Denom = 1. /(Ul-Uf); |
212 | USum = Uf+Ul; |
213 | myPtr = (myIndex - 1)*(myBase->WorkDegree()+ 1)*myDimension + 1; |
214 | } |
215 | |
216 | deg = myDegree(myIndex); |
217 | if (!HasDeri.Value(myIndex)) Update(myIndex, 1); |
218 | |
219 | //Parameter normalization: S [-1, 1] |
220 | S = (2*U - USum) * Denom; |
221 | PLib::NoDerivativeEvalPolynomial(S, deg-1, myDimension, (deg-1)*myDimension, |
222 | myDeri(1+(myIndex - 1)*myBase->WorkDegree()* |
223 | myDimension), |
224 | Vec(Vec.Lower())); |
225 | |
226 | S = 2*Denom; |
227 | for(i=Vec.Lower(); i<=Vec.Upper(); i++) Vec(i) *= S; |
228 | } |
229 | |
230 | |
231 | |
232 | //======================================================================= |
233 | //function : D2 |
234 | //purpose : |
235 | //======================================================================= |
236 | void FEmTool_Curve::D2(const Standard_Real U, TColStd_Array1OfReal& Vec) |
237 | { |
238 | Standard_Integer deg, i; |
239 | Standard_Real S; |
240 | |
241 | if (!myIndex || (U<Uf) || (U>Ul) || |
242 | (myKnots->Value(myIndex)!=Uf) || |
243 | (myKnots->Value(myIndex+1)!=Ul)) { |
244 | // Search the span |
245 | if(U <= myKnots->Value(2)) myIndex = 1; |
246 | else { |
247 | for(myIndex = 2; myIndex <= myNbElements; myIndex++) |
248 | if(U >= myKnots->Value(myIndex) && U <= myKnots->Value(myIndex+1)) break; |
249 | if (myIndex > myNbElements) myIndex = myNbElements; |
250 | } |
251 | Uf = myKnots->Value(myIndex); |
252 | Ul = myKnots->Value(myIndex+1); |
253 | Denom = 1. /(Ul-Uf); |
254 | USum = Uf+Ul; |
255 | myPtr = (myIndex - 1)*(myBase->WorkDegree()+ 1)*myDimension + 1; |
256 | } |
257 | |
258 | deg = myDegree(myIndex); |
259 | if (!HasSecn.Value(myIndex)) Update(myIndex, 2); |
260 | |
261 | //Parameter normalization: S [-1, 1] |
262 | S = (2*U - USum)*Denom; |
263 | PLib::NoDerivativeEvalPolynomial(S, deg-2, myDimension, (deg-2)*myDimension, |
264 | myDsecn(1+(myIndex - 1)* |
265 | (myBase->WorkDegree() - 1)*myDimension), |
266 | Vec(Vec.Lower())); |
267 | |
268 | S = 4*Denom*Denom; |
269 | for(i=Vec.Lower(); i<=Vec.Upper(); i++) Vec(i) *= S; |
270 | } |
271 | |
272 | |
273 | |
274 | //======================================================================= |
275 | //function : Length |
276 | //purpose : |
277 | //======================================================================= |
278 | void FEmTool_Curve::Length(const Standard_Real FirstU, |
279 | const Standard_Real LastU, |
280 | Standard_Real& Length) |
281 | { |
282 | Standard_Integer Low, High, deg, degBase, i, Ptr; |
283 | if(FirstU > LastU) Standard_OutOfRange::Raise("FEmTool_Curve::Length"); |
284 | |
285 | if(myKnots->Value(1) > FirstU) Low = 1; |
286 | else |
287 | for(Low = 1; Low <= myNbElements; Low++) |
288 | if(FirstU >= myKnots->Value(Low) && FirstU <= myKnots->Value(Low+1)) break; |
289 | if(Low > myNbElements) Low = myNbElements; |
290 | |
291 | if(myKnots->Value(1) > LastU) High = 1; |
292 | else |
293 | for(High = Low; High <= myNbElements; High++) |
294 | if(LastU >= myKnots->Value(High) && LastU <= myKnots->Value(High+1)) break; |
295 | if(myKnots->Value(myNbElements + 1) < LastU) High = myNbElements; |
296 | |
297 | Standard_Real Li; |
298 | degBase = myBase->WorkDegree(); |
299 | Length = 0; |
300 | |
301 | Standard_Real FirstS, LastS; |
302 | FirstS = (2*FirstU - myKnots->Value(Low) - myKnots->Value(Low + 1))/ |
303 | (myKnots->Value(Low + 1) - myKnots->Value(Low)); |
304 | LastS = (2*LastU - myKnots->Value(High) - myKnots->Value(High + 1))/ |
305 | (myKnots->Value(High + 1) - myKnots->Value(High)); |
306 | |
307 | if(Low == High) { |
308 | |
309 | Ptr = (Low - 1)*(degBase + 1)*myDimension + 1; |
310 | deg = myDegree(Low); |
311 | |
312 | if(!HasPoly(Low)) Update(Low, 0); |
313 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), |
314 | FirstS, LastS, Length); |
315 | return; |
316 | } |
317 | |
318 | deg = myDegree(Low); |
319 | Ptr = (Low - 1)*(degBase + 1)*myDimension + 1; |
320 | |
321 | if(!HasPoly(Low)) Update(Low, 0); |
322 | if(FirstS < -1.) { |
323 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), FirstS, -1., Li); |
324 | Length += Li; |
325 | if(myLength(Low) < 0.) { |
326 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., 1.,Li); |
327 | myLength(Low) = Li; |
328 | } |
329 | Length += myLength(Low); |
330 | } |
331 | else { |
332 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), FirstS, 1., Li); |
333 | Length += Li; |
334 | } |
335 | |
336 | deg = myDegree(High); |
337 | Ptr = (High - 1)*(degBase + 1)*myDimension + 1; |
338 | |
339 | if(!HasPoly(High)) Update(High, 0); |
340 | if(LastS > 1.) { |
341 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), 1., LastS, Li); |
342 | Length += Li; |
343 | if(myLength(High) < 0.) { |
344 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., 1., Li); |
345 | myLength(High) = Li; |
346 | } |
347 | Length += myLength(High); |
348 | } |
349 | else { |
350 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., LastS, Li); |
351 | Length += Li; |
352 | } |
353 | |
354 | |
355 | for(i = Low + 1; i < High; i++) { |
356 | if (myLength.Value(i) < 0) { |
357 | Ptr = (i - 1)*(degBase + 1)*myDimension + 1; |
358 | deg = myDegree(i); |
359 | if(!HasPoly(i)) Update(i, 0); |
360 | PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., 1., Li); |
361 | myLength(i) = Li; |
362 | } |
363 | Length += myLength(i); |
364 | } |
365 | } |
366 | |
367 | Standard_Integer FEmTool_Curve::NbElements() const |
368 | { |
369 | return myNbElements; |
370 | } |
371 | |
372 | Standard_Integer FEmTool_Curve::Dimension() const |
373 | { |
374 | return myDimension; |
375 | } |
376 | |
377 | Handle(PLib_Base) FEmTool_Curve::Base() const |
378 | { |
379 | return myBase; |
380 | } |
381 | |
382 | Standard_Integer FEmTool_Curve::Degree(const Standard_Integer IndexOfElement) const |
383 | { |
384 | return myDegree.Value(IndexOfElement); |
385 | } |
386 | |
387 | |
388 | //======================================================================= |
389 | //function : SetDegree |
390 | //purpose : |
391 | //======================================================================= |
392 | void FEmTool_Curve::SetDegree(const Standard_Integer IndexOfElement, |
393 | const Standard_Integer Degree) |
394 | { |
395 | if (Degree <= myBase->WorkDegree()) { |
396 | myDegree(IndexOfElement) = Degree; |
397 | HasPoly(IndexOfElement) = HasDeri(IndexOfElement) = HasSecn(IndexOfElement) = 0; |
398 | myLength(IndexOfElement) = -1; |
399 | } |
400 | else if(Degree > myBase->WorkDegree()) Standard_OutOfRange::Raise("FEmTool_Curve::SetDegree"); |
401 | } |
402 | |
403 | |
404 | |
405 | //======================================================================= |
406 | //function : ReduceDegree |
407 | //purpose : |
408 | //======================================================================= |
409 | void FEmTool_Curve::ReduceDegree(const Standard_Integer IndexOfElement, |
410 | const Standard_Real Tol, |
411 | Standard_Integer& NewDegree, |
412 | Standard_Real& MaxError) |
413 | { |
414 | Standard_Integer deg = myDegree(IndexOfElement); |
415 | |
416 | Standard_Integer Ptr = (IndexOfElement - 1)* |
417 | (myBase->WorkDegree() + 1)*myDimension + 1; |
418 | |
419 | myBase->ReduceDegree(myDimension, deg, Tol, myCoeff.ChangeValue(Ptr), NewDegree, MaxError); |
420 | Handle(PLib_HermitJacobi) myHermitJacobi = (*((Handle(PLib_HermitJacobi)*)&myBase)); |
421 | |
422 | NewDegree = Max(NewDegree, 2 * myHermitJacobi->NivConstr() + 1); |
423 | |
424 | if (NewDegree < deg) { |
425 | myDegree(IndexOfElement) = NewDegree; |
426 | HasPoly(IndexOfElement) = HasDeri(IndexOfElement) = HasSecn(IndexOfElement) = 0; |
427 | myLength(IndexOfElement) = -1; |
428 | } |
429 | } |
430 | |
431 | //======================================================================= |
432 | //function : Update |
433 | //purpose : |
434 | //======================================================================= |
435 | void FEmTool_Curve::Update(const Standard_Integer Index, |
436 | const Standard_Integer Order) |
437 | { |
438 | Standard_Integer degBase = myBase->WorkDegree(), deg = myDegree(Index); |
439 | |
440 | if (!HasPoly(Index)) { |
441 | Standard_Integer Ptr = (Index - 1)*(degBase + 1)*myDimension + 1; |
442 | |
443 | TColStd_Array1OfReal Coeff(myPoly.ChangeValue(Ptr), 0, myDimension*(deg + 1) - 1); |
444 | TColStd_Array1OfReal BaseCoeff(myCoeff.ChangeValue(Ptr), 0, myDimension*(deg + 1) - 1); |
445 | |
446 | myBase->ToCoefficients(myDimension, deg, BaseCoeff, Coeff); |
447 | HasPoly(Index) = 1; |
448 | } |
449 | |
450 | if (Order >=1) { |
451 | Standard_Integer i1 = (Index - 1)*(degBase)*myDimension - myDimension, |
452 | i2 = (Index - 1)*(degBase + 1)*myDimension; |
453 | Standard_Integer i,j; |
454 | if (!HasDeri.Value(Index)) { |
455 | for(i = 1; i <= deg; i++) { |
456 | i1 += myDimension; i2 += myDimension; |
457 | for(j = 1; j<= myDimension; j++) |
458 | myDeri(i1 + j) = i*myPoly.Value(i2 + j); |
459 | } |
460 | HasDeri(Index) = 1; |
461 | } |
462 | if ((Order>=2) &&!HasSecn.Value(Index)) { |
463 | i1 = (Index - 1)*(degBase-1)*myDimension - myDimension, |
464 | i2 = (Index - 1)*(degBase)*myDimension; |
465 | for(i = 1; i < deg; i++) { |
466 | i1 += myDimension; i2 += myDimension; |
467 | for(j = 1; j<= myDimension; j++) |
468 | myDsecn(i1 + j) = i*myDeri.Value(i2 + j); |
469 | } |
470 | HasSecn(Index) = 1; |
471 | } |
472 | } |
473 | } |