00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef MECHSYS_SPLINE_H
00023 #define MECHSYS_SPLINE_H
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #else
00028 #ifndef REAL
00029 #define REAL double
00030 #endif
00031 #endif
00032
00033 #define H_ZERO 1.0e-4
00034
00035 #include "util/exception.h"
00036 #include "util/numstreams.h"
00037
00038 using Util::_4;
00039 using Util::_6_3;
00040
00041 using std::cout;
00042 using std::endl;
00043
00044 class Spline
00045 {
00046 friend std::ostream & operator<< (std::ostream & os, Spline const & S);
00047 public:
00048
00049 Spline (REAL const X[], REAL const Y[], int Size);
00050 ~Spline ();
00051
00052 REAL Eval (REAL x) const;
00053 bool CheckRange (REAL x) const;
00054 REAL YRange () const;
00055 private:
00056 int _n;
00057 REAL * _x;
00058 REAL * _a;
00059 REAL * _b;
00060 REAL * _c;
00061 REAL * _d;
00062 };
00063
00064
00066
00067
00068 inline Spline::Spline(REAL const X[], REAL const Y[], int Size)
00069 : _n (Size)
00070 {
00071
00072 if (_n<2) throw new Fatal(_("Spline::Spline: The size or arrays (%d) must be 2 or greater"), _n);
00073
00074
00075 _x = new REAL [_n];
00076 _a = new REAL [_n];
00077 _b = new REAL [_n-1];
00078 _c = new REAL [_n];
00079 _d = new REAL [_n-1];
00080
00081
00082 if (X[_n-1]<X[0])
00083 {
00084 for (int i=0; i<_n; ++i)
00085 {
00086 _x[_n-1-i] = X[i];
00087 _a[_n-1-i] = Y[i];
00088 }
00089 }
00090 else
00091 {
00092 for (int i=0; i<_n; ++i)
00093 {
00094 _x[i] = X[i];
00095 _a[i] = Y[i];
00096 }
00097 }
00098
00099
00100 REAL * h = new REAL [_n-1];
00101 REAL * A = new REAL [_n-1];
00102 REAL * l = new REAL [_n ];
00103 REAL * m = new REAL [_n-1];
00104 REAL * z = new REAL [_n ];
00105
00106
00107 A[0] = 0.0;
00108 for (int i=0; i<_n-1; ++i)
00109 {
00110 h[i] = _x[i+1] - _x[i];
00111 if (fabs(h[i])<H_ZERO) throw new Fatal(_("Spline::Spline: h == 0"));
00112 if (i>0)
00113 A[i] = 3.0*(_a[i+1]-_a[i])/h[i] - 3.0*(_a[i]-_a[i-1])/h[i-1];
00114 }
00115
00116
00117 l[0] = 1.0;
00118 m[0] = 0.0;
00119 z[0] = 0.0;
00120 for (int i=1; i<_n-1; ++i)
00121 {
00122 l[i] = 2.0*(_x[i+1]-_x[i-1]) - h[i-1]*m[i-1];
00123 m[i] = h[i]/l[i];
00124 z[i] = (A[i]-h[i-1]*z[i-1])/l[i];
00125 }
00126 l[_n-1] = 1.0;
00127 z[_n-1] = 0.0;
00128 _c[_n-1] = 0.0;
00129 for (int i=_n-2; i>=0; --i)
00130 {
00131 _c[i] = z[i] - m[i]*_c[i+1];
00132 _b[i] = (_a[i+1]-_a[i])/h[i] - h[i]*(_c[i+1]+2.0*_c[i])/3.0;
00133 _d[i] = (_c[i+1]-_c[i])/(3.0*h[i]);
00134 }
00135
00136
00137 delete [] h;
00138 delete [] A;
00139 delete [] l;
00140 delete [] m;
00141 delete [] z;
00142
00143 }
00144
00145 inline Spline::~Spline()
00146 {
00147 delete [] _x;
00148 delete [] _a;
00149 delete [] _b;
00150 delete [] _c;
00151 delete [] _d;
00152 }
00153
00154 inline REAL Spline::Eval(REAL x) const
00155 {
00156
00157 int k;
00158 int lo = 0;
00159 int hi = _n-1;
00160 while (hi-lo>1)
00161 {
00162 k = (hi+lo) >> 1;
00163 if (_x[k]>x) hi = k;
00164 else lo = k;
00165 }
00166
00167
00168
00169 if (x<_x[lo]) throw new Fatal(_("Spline::Eval: Value (x=%.6f < %.6f) is not valid"), x, _x[lo]);
00170 if (x>_x[hi]) throw new Fatal(_("Spline::Eval: Value (x=%.6f > %.6f) is not valid"), x, _x[hi]);
00171
00172
00173 REAL h = x-_x[lo];
00174 return _a[lo] + _b[lo]*h + _c[lo]*h*h + _d[lo]*h*h*h;
00175
00176 }
00177
00178 inline bool Spline::CheckRange(REAL x) const
00179 {
00180 if (x<_x[0] ) return false;
00181 if (x>_x[_n-1]) return false;
00182 return true;
00183 }
00184
00185 inline REAL Spline::YRange() const
00186 {
00187 return _a[_n-1]-_a[0];
00188 }
00189
00190 std::ostream & operator<< (std::ostream & os, Spline const & S)
00191 {
00192 os << _4()<< "i" << _6_3()<< "x" << _6_3()<< "a" << _6_3()<< "b" << _6_3()<< "c" << _6_3()<< "d" << std::endl;
00193 for (int i=0; i<S._n; ++i)
00194 {
00195 os << _4()<< i << _6_3()<< S._x[i] << _6_3()<< S._a[i];
00196 if (i<S._n-1) os << _6_3()<< S._b[i] << _6_3()<< S._c[i] << _6_3()<< S._d[i] << std::endl;
00197 else os << std::endl;
00198 }
00199 return os;
00200 }
00201
00202 #endif // MECHSYS_SPLINE_H
00203
00204