1 /*****************************************************************************
2 ** This is part of the CTSim program
3 ** Copyright (c) 1983-2001 Kevin Rosenberg
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License (version 2) as
9 ** published by the Free Software Foundation.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ******************************************************************************/
22 #include "ctsupport.h"
23 #include "interpolator.h"
26 CubicPolyInterpolator::CubicPolyInterpolator (const double* const y, const int n)
30 sys_error (ERR_SEVERE, "Too few points (%d) in CubicPolyInterpolator", m_n);
33 CubicPolyInterpolator::~CubicPolyInterpolator ()
39 CubicPolyInterpolator::interpolate (double x)
41 int lo = static_cast<int>(floor(x)) - 1;
46 sys_error (ERR_WARNING, "x=%f, out of range [CubicPolyInterpolator]", x);
49 } else if (lo == -1) // linear interpolate at between x = 0 & 1
50 return m_pdY[0] + x * (m_pdY[1] - m_pdY[0]);
54 sys_error (ERR_WARNING, "x=%f, out of range [CubicPolyInterpolator]", x);
57 } else if (hi == m_n) {// linear interpolate between x = (n-2) and (n-1)
58 double frac = x - (lo + 1);
59 return m_pdY[m_n - 2] + frac * (m_pdY[m_n - 1] - m_pdY[m_n - 2]);
62 // Lagrange formula for N=4 (cubic)
65 double xd_1 = x - (lo + 1);
66 double xd_2 = x - (lo + 2);
67 double xd_3 = x - (lo + 3);
69 static double oneSixth = (1. / 6.);
71 double y = xd_1 * xd_2 * xd_3 * -oneSixth * m_pdY[lo];
72 y += xd_0 * xd_2 * xd_3 * 0.5 * m_pdY[lo+1];
73 y += xd_0 * xd_1 * xd_3 * -0.5 * m_pdY[lo+2];
74 y += xd_0 * xd_1 * xd_2 * oneSixth * m_pdY[lo+3];
81 CubicSplineInterpolator::CubicSplineInterpolator (const double* const y, const int n)
84 // Precalculate 2nd derivative of y and put in m_pdY2
85 // Calculated by solving set of simultaneous CubicSpline spline equations
86 // Only n-2 CubicSpline spline equations, but able to make two more
87 // equations by setting second derivative to 0 at ends
89 m_pdY2 = new double [n];
90 m_pdY2[0] = 0; // second deriviative = 0 at beginning and end
93 double* temp = new double [n - 1];
96 for (i = 1; i < n - 1; i++) {
97 double t = 2 + (0.5 * m_pdY2[i-1]);
98 temp[i] = y[i+1] + y[i-1] - y[i] - y[i];
99 temp[i] = (3 * temp[i] - 0.5 * temp[i-1]) / t;
100 m_pdY2[i] = -0.5 / t;
103 for (i = n - 2; i >= 0; i--)
104 m_pdY2[i] = temp[i] + m_pdY2[i] * m_pdY2[i + 1];
109 CubicSplineInterpolator::~CubicSplineInterpolator ()
116 CubicSplineInterpolator::interpolate (double x)
118 const static double oneSixth = (1. / 6.);
119 int lo = static_cast<int>(floor(x));
122 if (lo < 0 || hi >= m_n) {
124 sys_error (ERR_SEVERE, "x out of bounds [CubicSplineInterpolator::interpolate]");
129 double loFr = hi - x;
130 double hiFr = 1 - loFr;
131 double y = loFr * m_pdY[lo] + hiFr * m_pdY[hi];
132 y += oneSixth * ((loFr*loFr*loFr - loFr) * m_pdY2[lo] + (hiFr*hiFr*hiFr - hiFr) * m_pdY2[hi]);