1 // Created on: 1997-11-04
2 // Created by: Roman BORISOV / Igor FEOKTISTOV
3 // Copyright (c) 1997-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #define No_Standard_RangeError
18 #define No_Standard_OutOfRange
21 #include <FEmTool_Curve.hxx>
23 #include <PLib_Base.hxx>
24 #include <PLib_HermitJacobi.hxx>
25 #include <PLib_JacobiPolynomial.hxx>
26 #include <Standard_DimensionError.hxx>
27 #include <Standard_Type.hxx>
29 IMPLEMENT_STANDARD_RTTIEXT(FEmTool_Curve,Standard_Transient)
31 //=======================================================================
32 //function : FEmTool_Curve
34 //=======================================================================
35 FEmTool_Curve::FEmTool_Curve(const Standard_Integer Dimension,
36 const Standard_Integer NbElements,
37 const Handle(PLib_Base)& TheBase,
38 const Standard_Real) :
39 myNbElements(NbElements), myDimension(Dimension),
40 myBase(TheBase), myDegree(1, myNbElements),
41 myCoeff(1, myDimension*myNbElements*(myBase->WorkDegree() + 1)),
42 myPoly(1, myDimension*myNbElements*(myBase->WorkDegree() + 1)),
43 myDeri(1, myDimension*myNbElements*(myBase->WorkDegree())),
44 myDsecn(1, myDimension*myNbElements*(myBase->WorkDegree() - 1)),
45 HasPoly(1, myNbElements), HasDeri(1, myNbElements),
46 HasSecn(1, myNbElements), myLength(1, myNbElements),
49 myKnots = new TColStd_HArray1OfReal(1, myNbElements + 1);
50 myDegree.Init(myBase->WorkDegree());
57 TColStd_Array1OfReal& FEmTool_Curve::Knots() const
59 return myKnots->ChangeArray1();
64 //=======================================================================
65 //function : SetElement
67 //=======================================================================
68 void FEmTool_Curve::SetElement(const Standard_Integer IndexOfElement,
69 const TColStd_Array2OfReal& Coeffs)
71 Standard_Integer i, j, degBase, deg;
72 if (IndexOfElement > myNbElements || IndexOfElement < 1) throw Standard_OutOfRange();
73 degBase = myBase->WorkDegree();
74 deg = myDegree(IndexOfElement);
75 Standard_Integer iBase = (IndexOfElement - 1)*(degBase + 1)*myDimension,
76 i1 = iBase-myDimension, i2 = Coeffs.LowerRow() - 1,
77 j1 = Coeffs.LowerCol() - 1;
78 for(i = 1; i <= deg + 1; i++) {
79 i1 += myDimension; i2++;
80 for(j = 1; j <= myDimension; j++)
81 myCoeff(i1 + j) = Coeffs(i2, j1 + j);
84 Standard_Real stenor = (myKnots->Value(IndexOfElement + 1) - myKnots->Value(IndexOfElement)) / 2.,
86 Handle(PLib_HermitJacobi) myHermitJacobi = Handle(PLib_HermitJacobi)::DownCast (myBase);
89 i2 = iBase + (myHermitJacobi->NivConstr() + 1) * myDimension;
90 for(i = 1; i <= myHermitJacobi->NivConstr(); i++) {
91 i1 += myDimension; i2 += myDimension;
92 mfact = Pow(stenor, i);
93 for(j = 1; j <= myDimension; j++) {
94 myCoeff(i1 + j) *= mfact;
95 myCoeff(i2 + j) *= mfact;
99 HasPoly(IndexOfElement) = HasDeri(IndexOfElement) = HasSecn(IndexOfElement) = 0;
100 myLength(IndexOfElement) = - 1;
104 //=======================================================================
105 //function : GetElement
107 //=======================================================================
108 void FEmTool_Curve::GetElement(const Standard_Integer IndexOfElement, TColStd_Array2OfReal& Coeffs)
110 Standard_Integer i, j, degBase, deg;
111 if (IndexOfElement > myNbElements || IndexOfElement < 1) throw Standard_OutOfRange();
112 degBase = myBase->WorkDegree();
113 deg = myDegree(IndexOfElement);
114 Standard_Integer iBase = (IndexOfElement - 1)*(degBase + 1)*myDimension,
115 i1 = iBase-myDimension, i2 = Coeffs.LowerRow() - 1,
116 j1 = Coeffs.LowerCol() - 1;
117 for(i = 1; i <= deg + 1; i++) {
118 i1 += myDimension; i2++;
119 for(j = 1; j <= myDimension; j++)
120 Coeffs(i2, j1 + j) = myCoeff.Value(i1 + j);
123 Standard_Real stenor = 2. / (myKnots->Value(IndexOfElement + 1) - myKnots->Value(IndexOfElement)),
126 Handle(PLib_HermitJacobi) myHermitJacobi = Handle(PLib_HermitJacobi)::DownCast (myBase);
128 i2 = Coeffs.LowerRow();
129 Standard_Integer i3 = i2 + myHermitJacobi->NivConstr() + 1;
131 for(i = 1; i <= myHermitJacobi->NivConstr(); i++) {
132 mfact = Pow(stenor, i);
133 for(j = j1+1; j <= myDimension; j++) {
134 Coeffs(i2 + i, j) *= mfact;
135 Coeffs(i3 + i, j) *= mfact;
141 //=======================================================================
142 //function : GetPolynom
144 //=======================================================================
145 void FEmTool_Curve::GetPolynom(TColStd_Array1OfReal& Coeffs)
148 Standard_Integer IndexOfElement, i, di = Coeffs.Lower() - myPoly.Lower();
151 for(IndexOfElement = 1; IndexOfElement <= myNbElements; IndexOfElement++)
152 if (!HasPoly.Value(IndexOfElement)) Update(IndexOfElement, 0);
154 for(i = myPoly.Lower(); i <= myPoly.Upper(); i++)
155 Coeffs(di + i) = myPoly(i);
160 //=======================================================================
163 //=======================================================================
164 void FEmTool_Curve::D0(const Standard_Real U, TColStd_Array1OfReal& Pnt)
166 Standard_Integer deg;
169 if (!myIndex || (U<Uf) || (U>Ul) ||
170 (myKnots->Value(myIndex)!=Uf) ||
171 (myKnots->Value(myIndex+1)!=Ul)) {
173 if(U <= myKnots->Value(2)) myIndex = 1;
175 for(myIndex = 2; myIndex <= myNbElements; myIndex++)
176 if(U >= myKnots->Value(myIndex) && U <= myKnots->Value(myIndex+1)) break;
177 if (myIndex > myNbElements) myIndex = myNbElements;
179 Uf = myKnots->Value(myIndex);
180 Ul = myKnots->Value(myIndex+1);
183 myPtr = (myIndex - 1)*(myBase->WorkDegree()+ 1)*myDimension + 1;
186 deg = myDegree(myIndex);
187 if (!HasPoly.Value(myIndex)) Update(myIndex, 0);
189 //Parameter normalization: S [-1, 1]
190 S = (2*U - USum)*Denom;
191 PLib::NoDerivativeEvalPolynomial(S, deg, myDimension, deg*myDimension,
192 myPoly(myPtr), Pnt(Pnt.Lower()));
196 //=======================================================================
199 //=======================================================================
200 void FEmTool_Curve::D1(const Standard_Real U, TColStd_Array1OfReal& Vec)
202 Standard_Integer deg, i;
205 if (!myIndex || (U<Uf) || (U>Ul) ||
206 (myKnots->Value(myIndex)!=Uf) ||
207 (myKnots->Value(myIndex+1)!=Ul)) {
209 if(U <= myKnots->Value(2)) myIndex = 1;
211 for(myIndex = 2; myIndex <= myNbElements; myIndex++)
212 if(U >= myKnots->Value(myIndex) && U <= myKnots->Value(myIndex+1)) break;
213 if (myIndex > myNbElements) myIndex = myNbElements;
215 Uf = myKnots->Value(myIndex);
216 Ul = myKnots->Value(myIndex+1);
219 myPtr = (myIndex - 1)*(myBase->WorkDegree()+ 1)*myDimension + 1;
222 deg = myDegree(myIndex);
223 if (!HasDeri.Value(myIndex)) Update(myIndex, 1);
225 //Parameter normalization: S [-1, 1]
226 S = (2*U - USum) * Denom;
227 PLib::NoDerivativeEvalPolynomial(S, deg-1, myDimension, (deg-1)*myDimension,
228 myDeri(1+(myIndex - 1)*myBase->WorkDegree()*
233 for(i=Vec.Lower(); i<=Vec.Upper(); i++) Vec(i) *= S;
238 //=======================================================================
241 //=======================================================================
242 void FEmTool_Curve::D2(const Standard_Real U, TColStd_Array1OfReal& Vec)
244 Standard_Integer deg, i;
247 if (!myIndex || (U<Uf) || (U>Ul) ||
248 (myKnots->Value(myIndex)!=Uf) ||
249 (myKnots->Value(myIndex+1)!=Ul)) {
251 if(U <= myKnots->Value(2)) myIndex = 1;
253 for(myIndex = 2; myIndex <= myNbElements; myIndex++)
254 if(U >= myKnots->Value(myIndex) && U <= myKnots->Value(myIndex+1)) break;
255 if (myIndex > myNbElements) myIndex = myNbElements;
257 Uf = myKnots->Value(myIndex);
258 Ul = myKnots->Value(myIndex+1);
261 myPtr = (myIndex - 1)*(myBase->WorkDegree()+ 1)*myDimension + 1;
264 deg = myDegree(myIndex);
265 if (!HasSecn.Value(myIndex)) Update(myIndex, 2);
267 //Parameter normalization: S [-1, 1]
268 S = (2*U - USum)*Denom;
269 PLib::NoDerivativeEvalPolynomial(S, deg-2, myDimension, (deg-2)*myDimension,
270 myDsecn(1+(myIndex - 1)*
271 (myBase->WorkDegree() - 1)*myDimension),
275 for(i=Vec.Lower(); i<=Vec.Upper(); i++) Vec(i) *= S;
280 //=======================================================================
283 //=======================================================================
284 void FEmTool_Curve::Length(const Standard_Real FirstU,
285 const Standard_Real LastU,
286 Standard_Real& Length)
288 Standard_Integer Low, High, deg, degBase, i, Ptr;
289 if(FirstU > LastU) throw Standard_OutOfRange("FEmTool_Curve::Length");
291 if(myKnots->Value(1) > FirstU) Low = 1;
293 for(Low = 1; Low <= myNbElements; Low++)
294 if(FirstU >= myKnots->Value(Low) && FirstU <= myKnots->Value(Low+1)) break;
295 if(Low > myNbElements) Low = myNbElements;
297 if(myKnots->Value(1) > LastU) High = 1;
299 for(High = Low; High <= myNbElements; High++)
300 if(LastU >= myKnots->Value(High) && LastU <= myKnots->Value(High+1)) break;
301 if(myKnots->Value(myNbElements + 1) < LastU) High = myNbElements;
304 degBase = myBase->WorkDegree();
307 Standard_Real FirstS, LastS;
308 FirstS = (2*FirstU - myKnots->Value(Low) - myKnots->Value(Low + 1))/
309 (myKnots->Value(Low + 1) - myKnots->Value(Low));
310 LastS = (2*LastU - myKnots->Value(High) - myKnots->Value(High + 1))/
311 (myKnots->Value(High + 1) - myKnots->Value(High));
315 Ptr = (Low - 1)*(degBase + 1)*myDimension + 1;
318 if(!HasPoly(Low)) Update(Low, 0);
319 PLib::EvalLength(deg, myDimension, myPoly(Ptr),
320 FirstS, LastS, Length);
325 Ptr = (Low - 1)*(degBase + 1)*myDimension + 1;
327 if(!HasPoly(Low)) Update(Low, 0);
329 PLib::EvalLength(deg, myDimension, myPoly(Ptr), FirstS, -1., Li);
331 if(myLength(Low) < 0.) {
332 PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., 1.,Li);
335 Length += myLength(Low);
338 PLib::EvalLength(deg, myDimension, myPoly(Ptr), FirstS, 1., Li);
342 deg = myDegree(High);
343 Ptr = (High - 1)*(degBase + 1)*myDimension + 1;
345 if(!HasPoly(High)) Update(High, 0);
347 PLib::EvalLength(deg, myDimension, myPoly(Ptr), 1., LastS, Li);
349 if(myLength(High) < 0.) {
350 PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., 1., Li);
353 Length += myLength(High);
356 PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., LastS, Li);
361 for(i = Low + 1; i < High; i++) {
362 if (myLength.Value(i) < 0) {
363 Ptr = (i - 1)*(degBase + 1)*myDimension + 1;
365 if(!HasPoly(i)) Update(i, 0);
366 PLib::EvalLength(deg, myDimension, myPoly(Ptr), -1., 1., Li);
369 Length += myLength(i);
373 Standard_Integer FEmTool_Curve::NbElements() const
378 Standard_Integer FEmTool_Curve::Dimension() const
383 Handle(PLib_Base) FEmTool_Curve::Base() const
388 Standard_Integer FEmTool_Curve::Degree(const Standard_Integer IndexOfElement) const
390 return myDegree.Value(IndexOfElement);
394 //=======================================================================
395 //function : SetDegree
397 //=======================================================================
398 void FEmTool_Curve::SetDegree(const Standard_Integer IndexOfElement,
399 const Standard_Integer Degree)
401 if (Degree <= myBase->WorkDegree()) {
402 myDegree(IndexOfElement) = Degree;
403 HasPoly(IndexOfElement) = HasDeri(IndexOfElement) = HasSecn(IndexOfElement) = 0;
404 myLength(IndexOfElement) = -1;
406 else if(Degree > myBase->WorkDegree()) throw Standard_OutOfRange("FEmTool_Curve::SetDegree");
411 //=======================================================================
412 //function : ReduceDegree
414 //=======================================================================
415 void FEmTool_Curve::ReduceDegree(const Standard_Integer IndexOfElement,
416 const Standard_Real Tol,
417 Standard_Integer& NewDegree,
418 Standard_Real& MaxError)
420 Standard_Integer deg = myDegree(IndexOfElement);
422 Standard_Integer Ptr = (IndexOfElement - 1)*
423 (myBase->WorkDegree() + 1)*myDimension + 1;
425 myBase->ReduceDegree(myDimension, deg, Tol, myCoeff.ChangeValue(Ptr), NewDegree, MaxError);
426 Handle(PLib_HermitJacobi) myHermitJacobi = Handle(PLib_HermitJacobi)::DownCast (myBase);
428 NewDegree = Max(NewDegree, 2 * myHermitJacobi->NivConstr() + 1);
430 if (NewDegree < deg) {
431 myDegree(IndexOfElement) = NewDegree;
432 HasPoly(IndexOfElement) = HasDeri(IndexOfElement) = HasSecn(IndexOfElement) = 0;
433 myLength(IndexOfElement) = -1;
437 //=======================================================================
440 //=======================================================================
441 void FEmTool_Curve::Update(const Standard_Integer Index,
442 const Standard_Integer Order)
444 Standard_Integer degBase = myBase->WorkDegree(), deg = myDegree(Index);
446 if (!HasPoly(Index)) {
447 Standard_Integer Ptr = (Index - 1)*(degBase + 1)*myDimension + 1;
449 TColStd_Array1OfReal Coeff(myPoly.ChangeValue(Ptr), 0, myDimension*(deg + 1) - 1);
450 TColStd_Array1OfReal BaseCoeff(myCoeff.ChangeValue(Ptr), 0, myDimension*(deg + 1) - 1);
452 myBase->ToCoefficients(myDimension, deg, BaseCoeff, Coeff);
457 Standard_Integer i1 = (Index - 1)*(degBase)*myDimension - myDimension,
458 i2 = (Index - 1)*(degBase + 1)*myDimension;
459 Standard_Integer i,j;
460 if (!HasDeri.Value(Index)) {
461 for(i = 1; i <= deg; i++) {
462 i1 += myDimension; i2 += myDimension;
463 for(j = 1; j<= myDimension; j++)
464 myDeri(i1 + j) = i*myPoly.Value(i2 + j);
468 if ((Order>=2) &&!HasSecn.Value(Index)) {
469 i1 = (Index - 1)*(degBase-1)*myDimension - myDimension,
470 i2 = (Index - 1)*(degBase)*myDimension;
471 for(i = 1; i < deg; i++) {
472 i1 += myDimension; i2 += myDimension;
473 for(j = 1; j<= myDimension; j++)
474 myDsecn(i1 + j) = i*myDeri.Value(i2 + j);