libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNCubicSpline.cpp
Go to the documentation of this file.
1 /* Copyright 2011 CoReNum
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNCubicSpline.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <CRNMath/CRNCubicSpline.h>
23 #include <CRNProtocols.h>
24 
25 using namespace crn;
26 
28 void CubicSpline::computeCoeffs()
29 {
30  std::sort(data.begin(), data.end(), Point2DDouble::Comparer(Direction::LEFT));
31  // compute h and b
32  std::vector<double> h(data.size() - 1);
33  std::vector<double> b(h.size());
34  for (size_t tmp = 0; tmp < h.size(); ++tmp)
35  {
36  h[tmp] = data[tmp + 1].X - data[tmp].X;
37  b[tmp] = (data[tmp + 1].Y - data[tmp].Y) / h[tmp];
38  }
39  // Gaussian elimination
40  std::vector<double> u(h.size());
41  std::vector<double> v(h.size());
42  u[1] = 2 * (h[0] + h[1]);
43  v[1] = 6 * (b[1] - b[0]);
44  for (size_t tmp = 2; tmp < u.size(); ++tmp)
45  {
46  u[tmp] = 2 * (h[tmp - 1] + h[tmp]) - crn::Sqr(h[tmp - 1]) / u[tmp - 1];
47  v[tmp] = 6 * (b[tmp] - b[tmp - 1]) - h[tmp - 1] * v[tmp - 1] / u[tmp - 1];
48  }
49  // back substitution
50  z.resize(data.size());
51  z[z.size() - 1] = 0;
52  for (int tmp = int(z.size()) - 2; tmp > 0; --tmp)
53  {
54  z[tmp] = (v[tmp] - h[tmp] * z[tmp + 1]) / u[tmp];
55  }
56  z[0] = 0;
57 }
58 
59 double CubicSpline::operator[](double x) const
60 {
61  if (extrapolation == Extrapolation::LINEAR)
62  {
63  if (x < data.front().X)
64  {
65  double dx = data[1].X - data[0].X;
66  dx /= 10.0;
67  if (dx > 0.01)
68  dx = 0.01;
69  double dy = (*this)[data.front().X + dx] - data.front().Y;
70  double slope = dy / dx;
71  return data.front().Y + slope * (x - data.front().X);
72  }
73  if (x > data.back().X)
74  {
75  double dx = data[data.size() - 1].X - data[data.size() - 2].X;
76  dx /= 10.0;
77  if (dx > 0.01)
78  dx = 0.01;
79  double dy = data.back().Y - (*this)[data.back().X - dx];
80  double slope = dy / dx;
81  return data.back().Y + slope * (x - data.back().X);
82  }
83  }
84  size_t i;
85  if (x >= data.back().X)
86  i = z.size() - 2;
87  else
88  {
89  for (i = 0; i < z.size() - 1; ++i)
90  {
91  if (x <= data[i + 1].X)
92  break;
93  }
94  }
95  double h = data[i + 1].X - data[i].X;
96  double a = data[i].Y;
97  double b = h * z[i + 1] / -6.0 - h * z[i] / 3.0 + (data[i + 1].Y - data[i].Y) / h;
98  double c = z[i] / 2.0;
99  double d = (z[i + 1] - z[i]) / (6.0 * h);
100  double dx = x - data[i].X;
101  return a + dx * (b + dx * (c + dx * d));
102 }
103 
105  Cloner::Register<CubicSpline>();
106 CRN_END_CLASS_CONSTRUCTOR(CubicSpline)
#define CRN_END_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:198
constexpr SumType< T > Sqr(const T &v) noexcept(noexcept(v *v))
Returns the square of a value.
Definition: CRNMath.h:61
virtual double operator[](double x) const override
Gets ordinate at x.
Cubic spline interpolation.
#define CRN_BEGIN_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:185