CalcMySky  v0.3.1
spline-interpolation.hpp
1 #ifndef INCLUDE_ONCE_F820C110_1DC9_40B4_8442_EDD0227CB7E8
2 #define INCLUDE_ONCE_F820C110_1DC9_40B4_8442_EDD0227CB7E8
3 
4 #include <Eigen/Dense>
5 #include <cassert>
6 #include <vector>
7 
8 template<typename Number, typename Vec2>
10 {
11 public:
12  struct Chunk
13  {
14  Number xMax; // right border of the chunk's domain of definition
15  Number a, b, c; // a x^2 + b x + c
16  Chunk(Number xMax, Number a, Number b, Number c)
17  : xMax(xMax)
18  , a(a), b(b), c(c)
19  {}
20  };
22  SplineOrder2InterpolationFunction(std::vector<Chunk>&& chunks) : chunks(chunks) {}
23  Number sample(Number const x) const
24  {
25  assert(!chunks.empty());
26 
27  std::size_t chunkIndex;
28  for(chunkIndex=0; chunkIndex<chunks.size() && x > chunks[chunkIndex].xMax; ++chunkIndex);
29 
30  if(chunkIndex==chunks.size())
31  throw std::out_of_range("Too large x");
32 
33  const auto a = chunks[chunkIndex].a;
34  const auto b = chunks[chunkIndex].b;
35  const auto c = chunks[chunkIndex].c;
36  return a*x*x + b*x + c;
37  }
38 private:
39  std::vector<Chunk> chunks;
40 };
41 
42 template<typename Vec2, typename Number=typename std::remove_cv<typename std::remove_reference<decltype(Vec2().x)>::type>::type>
43 SplineOrder2InterpolationFunction<Number,Vec2> splineInterpolationOrder2(Vec2 const*const points, const std::size_t pointCount)
44 {
45  assert(pointCount>=3);
46  assert(std::is_sorted(points,points+pointCount,[](Vec2 const& a, Vec2 const& b){return a.x<b.x;}));
47 
48  const auto sqr=[](Number x){ return x*x; };
49  enum { A=0, B=1, C=2 };
50 
51  const int n=pointCount;
52  const int N=3*(n-2);
53 
54  using namespace Eigen;
55  using Matrix=Eigen::Matrix<Number, Dynamic, Dynamic>;
56  using Vector=Eigen::Matrix<Number, Dynamic, 1>;
57  Matrix M=Matrix::Zero(N, N);
58  Vector R=Vector::Zero(N);
59 
60  // All indices in the comments are 1-based, the equations are written in Wolfram Language
61 
62  // Values of first and last functions at endpoints must equal ordinates of corresponding endpoint.
63  // This gives two equations. First:
64  // a[1] points[[1, 1]]^2 + b[1] points[[1, 1]] + c[1] == points[[1, 2]]
65  /*a[1]*/M(0, 3*0+A)=sqr(points[0].x);
66  /*b[1]*/M(0, 3*0+B)= points[0].x ;
67  /*c[1]*/M(0, 3*0+C)=1;
68  /*RHS*/ R(0)=points[0].y;
69  // And second:
70  // a[n - 2] points[[n, 1]]^2 + b[n - 2] points[[n, 1]] + c[n - 2] == points[[n, 2]]
71  /*a[n-2]*/M(1, 3*(n-2-1)+A)=sqr(points[n-1].x);
72  /*b[n-2]*/M(1, 3*(n-2-1)+B)= points[n-1].x ;
73  /*c[n-2]*/M(1, 3*(n-2-1)+C)=1;
74  /* RHS */ R(1)=points[n-1].y;
75 
76  // Value of ith function at (i + 1)th point must be equal to the point ordinate.
77  // This gives (n-2) equations:
78  // Table[a[i] points[[i + 1, 1]]^2 + b[i] points[[i + 1, 1]] + c[i] == points[[i + 1, 2]], {i, n - 2}]
79  for(int i=0; i<n-2; ++i)
80  {
81  /*a[i]*/M(2+i, 3*i+A)=sqr(points[i+1].x);
82  /*b[i]*/M(2+i, 3*i+B)= points[i+1].x ;
83  /*c[i]*/M(2+i, 3*i+C)=1;
84  /*RHS*/ R(2+i)=points[i+1].y;
85  }
86 
87  // Value of ith function at midpoint between points (i + 1) and (i + 2) must agree with that of (i + 1)th function
88  // This gives (n-3) equations:
89  // Table[a[i] ((points[[i + 1, 1]] + points[[i + 2, 1]])/2)^2 + b[i] (points[[i + 1, 1]] + points[[i + 2, 1]])/2 + c[i] ==
90  // a[i + 1] ((points[[i + 1, 1]] + points[[i + 2, 1]])/2)^2 + b[i + 1] (points[[i + 1, 1]] + points[[i + 2, 1]])/2 + c[i + 1]
91  // , {i, n - 3}]
92  for(int i=0; i<n-3; ++i)
93  {
94  /*a[i]*/ M(n+i, 3*i+A) = sqr(0.5*(points[i+1].x+points[i+2].x));
95  /*b[i]*/ M(n+i, 3*i+B) = 0.5*(points[i+1].x+points[i+2].x) ;
96  /*c[i]*/ M(n+i, 3*i+C) = 1;
97  /*a[i+1]*/M(n+i, 3*(i+1)+A) = -sqr(0.5*(points[i+1].x+points[i+2].x));
98  /*b[i+1]*/M(n+i, 3*(i+1)+B) = - 0.5*(points[i+1].x+points[i+2].x) ;
99  /*c[i+1]*/M(n+i, 3*(i+1)+C) = -1;
100  }
101 
102  // Same for derivatives at midpoints, giving us another (n-3) equations:
103  // Table[2 a[i] (points[[i + 1, 1]] + points[[i + 2, 1]])/2 + b[i] == 2 a[i + 1] (points[[i + 1, 1]] + points[[i + 2, 1]])/2 + b[i + 1]
104  // , {i, n - 3}]
105  for(int i=0; i<n-3; ++i)
106  {
107  /*a[i]*/ M(2*n-3+i, 3*i+A) = points[i+1].x+points[i+2].x;
108  /*b[i]*/ M(2*n-3+i, 3*i+B) = 1;
109  /*a[i+1]*/M(2*n-3+i, 3*(i+1)+A) = -(points[i+1].x+points[i+2].x);
110  /*b[i+1]*/M(2*n-3+i, 3*(i+1)+B) = -1;
111  }
112 
113  const Vector ABCs = M.colPivHouseholderQr().solve(R);
114 
115  std::vector<typename SplineOrder2InterpolationFunction<Number,Vec2>::Chunk> coefs;
116 
117  // Left endpoint
118  coefs.emplace_back((points[1].x+points[2].x)/2,
119  ABCs(A), ABCs(B), ABCs(C));
120 
121  // Internal points
122  for(int i=1; i<n-3; ++i)
123  coefs.emplace_back((points[i+1].x+points[i+2].x)/2,
124  ABCs(3*i+A), ABCs(3*i+B), ABCs(3*i+C));
125 
126  // Right endpoint
127  coefs.emplace_back(points[n-1].x,
128  ABCs(3*(n-3)+A), ABCs(3*(n-3)+B), ABCs(3*(n-3)+C));
129 
130  return coefs;
131 }
132 
133 #endif
Definition: spline-interpolation.hpp:12
Definition: spline-interpolation.hpp:9