GeneralBSpline.h
Go to the documentation of this file.
1 #ifndef _GeneralBSpline_Spline_General_h_
2 #define _GeneralBSpline_Spline_General_h_
3 
4 #include <cmath>
5 #include <vector>
6 #include <algorithm>
7 #include <limits>
8 #include <iostream>
9 #include <utl/AugerException.h>
10 
11 namespace Spline {
12 
13  typedef unsigned char dim_t;
14 
15  template <dim_t ADimension, typename AKnotVector, typename ABasisFunction>
16  class Function;
17 
18  namespace General {
19 
20  class KnotVector {
21  public:
23 
24  KnotVector(const std::vector<double>& data)
25  : fData(data)
26  {
27  const size_t n = GetSize();
28  if (n<2)
29  throw utl::InvalidConfigurationException("size of KnotVector < 2");
30  for (size_t i=0;i<n-1;++i)
31  if (fData[i]>fData[i+1])
32  throw utl::InvalidConfigurationException("knots are not in ascending order");
33  }
34 
35  inline
36  void
37  PushBack(const double x)
38  {
39  fData.push_back(x);
40  }
41 
42  inline
43  double
44  operator()(const int i)
45  const
46  {
47  const size_t n = GetSize();
48 
49  // virtual knots
50  if (i<0)
51  {
52  const double dx = fData[1]-fData[0];
53  return fData[0]+i*dx;
54  }
55 
56  if (i>int(n-1))
57  {
58  const double dx = fData[n-1]-fData[n-2];
59  return fData[n-1]+(i-(n-1))*dx;
60  }
61 
62  // real knots
63  return fData[i];
64  }
65 
66  inline
67  double
68  operator[](const size_t i)
69  const
70  {
71  return fData[i];
72  }
73 
74  inline
75  size_t
76  Locate(const double x)
77  const
78  {
79  const size_t n = GetSize();
80  if (x >= (*this)[n-1])
81  return n-2;
82  else
83  return std::upper_bound(fData.begin(),fData.end(),x)-fData.begin()-1;
84  }
85 
86  inline
87  size_t
88  GetSize()
89  const
90  {
91  return fData.size();
92  }
93 
94  inline
95  double
96  GetStart()
97  const
98  {
99  return fData.front();
100  }
101 
102  inline
103  double
104  GetStop()
105  const
106  {
107  return fData.back();
108  }
109 
110  protected:
111  std::vector<double> fData;
112  };
113 
114 
116  public:
118 
119  BasisFunction(const KnotVector* const xknot, int j)
120  : fKnotPtr(xknot), fIndex(j-3) { }
121 
122  BasisFunction(const BasisFunction& other) { *this = other; }
123 
125  operator=(const BasisFunction& other)
126  {
127  fKnotPtr = other.fKnotPtr;
128  fIndex = other.fIndex;
129  return *this;
130  }
131 
132  double
133  operator()(const double x, const char derivative = 0)
134  const
135  {
136  if (x < GetStart())
137  return 0;
138 
139  if (x > GetStop())
140  return derivative == -1 ? Internal(fKnotPtr->Locate(x), GetStop(), -1) : 0;
141 
142  return Internal(fKnotPtr->Locate(x), x, derivative);
143  }
144 
145  double GetStart() const { return (*fKnotPtr)[std::max(fIndex, 0)]; }
146 
147  double GetStop() const { return (*fKnotPtr)[std::min(fIndex+4, int(fKnotPtr->GetSize())-1)]; }
148 
149  private:
150  double
151  Internal(const size_t i, const double x, const char derivative)
152  const
153  {
154  const KnotVector& xknot = *fKnotPtr;
155 
156  double t0;
157  double t1;
158  double t2;
159  double t3;
160  ComputePolynomialFactors(t0, t1, t2, t3, i - fIndex);
161 
162  switch (derivative) {
163  case -1: {
164  const double a = xknot[i];
165  double result =
166  x*(t0 + x*(t1/2 + x*(t2/3 + x*t3/4))) -
167  a*(t0 + a*(t1/2 + a*(t2/3 + a*t3/4)));
168  for (size_t j = std::max(fIndex, 0); j < i; ++j) {
169  ComputePolynomialFactors(t0, t1, t2, t3, j - fIndex);
170  const double pa = xknot[j];
171  const double pb = xknot[j+1];
172  result +=
173  pb*(t0 + pb*(t1/2 + pb*(t2/3 + pb*t3/4))) -
174  pa*(t0 + pa*(t1/2 + pa*(t2/3 + pa*t3/4)));
175  }
176  return result;
177  }
178  case 0:
179  return t0 + x*(t1 + x*(t2 + x*t3));
180  case 1:
181  return t1 + x*(2*t2 + x*3*t3);
182  case 2:
183  return 2*t2 + x*6*t3;
184  case 3:
185  return 6*t3;
186  default:
187  return 0;
188  }
189  }
190 
191  void
192  ComputePolynomialFactors(double& t0, double& t1, double& t2, double& t3, const size_t i)
193  const
194  {
195  const KnotVector& xknot = *fKnotPtr;
196 
197  t0 = 0;
198  t1 = 0;
199  t2 = 0;
200  t3 = 0;
201 
202  #define SPLINE_BASIS_POLYNOMAL_FACTORS(ia0, ia1, ia2, ib0, ib1, ib2, ic0, ic1, ic2) \
203  t0 += -xknot(fIndex+ia0)*xknot(fIndex+ia1)*xknot(fIndex+ia2)/((xknot(fIndex+ib0)-xknot(fIndex+ic0))*(xknot(fIndex+ib1)-xknot(fIndex+ic1))*(xknot(fIndex+ib2)-xknot(fIndex+ic2))); \
204  t1 += (xknot(fIndex+ia0)*xknot(fIndex+ia1)+xknot(fIndex+ia0)*xknot(fIndex+ia2)+xknot(fIndex+ia1)*xknot(fIndex+ia2))/((xknot(fIndex+ib0)-xknot(fIndex+ic0))*(xknot(fIndex+ib1)-xknot(fIndex+ic1))*(xknot(fIndex+ib2)-xknot(fIndex+ic2))); \
205  t2 += -(xknot(fIndex+ia0)+xknot(fIndex+ia1)+xknot(fIndex+ia2))/((xknot(fIndex+ib0)-xknot(fIndex+ic0))*(xknot(fIndex+ib1)-xknot(fIndex+ic1))*(xknot(fIndex+ib2)-xknot(fIndex+ic2))); \
206  t3 += 1.0/((xknot(fIndex+ib0)-xknot(fIndex+ic0))*(xknot(fIndex+ib1)-xknot(fIndex+ic1))*(xknot(fIndex+ib2)-xknot(fIndex+ic2)));
207 
208  switch (i) {
209  case 0:
210  SPLINE_BASIS_POLYNOMAL_FACTORS(0,0,0,1,2,3,0,0,0);
211  break;
212  case 1:
213  SPLINE_BASIS_POLYNOMAL_FACTORS(0,0,2,2,3,1,0,0,2);
214  SPLINE_BASIS_POLYNOMAL_FACTORS(0,1,3,3,2,1,0,1,3);
215  SPLINE_BASIS_POLYNOMAL_FACTORS(1,1,4,2,3,1,1,1,4);
216  break;
217  case 2:
218  SPLINE_BASIS_POLYNOMAL_FACTORS(0,3,3,3,1,2,0,3,3);
219  SPLINE_BASIS_POLYNOMAL_FACTORS(1,4,3,3,1,2,1,4,3);
220  SPLINE_BASIS_POLYNOMAL_FACTORS(2,4,4,3,1,2,2,4,4);
221  break;
222  case 3:
223  SPLINE_BASIS_POLYNOMAL_FACTORS(4,4,4,1,2,3,4,4,4);
224  break;
225  }
226 
227  #undef SPLINE_BASIS_POLYNOMAL_FACTORS
228  }
229 
230  const KnotVector* fKnotPtr = nullptr;
231  int fIndex = 0;
232 
233  template <dim_t ADimension, typename AKnotVector, typename ABasisFunction>
234  friend class ::Spline::Function;
235  };
236 
237  }
238 
239 }
240 
241 
242 #endif
double operator[](const size_t i) const
ComputePolynomialFactors(t0, t1, t2, t3, i-fIndex)
Base class for exceptions arising because configuration data are not valid.
std::vector< double > fData
KnotVector(const std::vector< double > &data)
#define max(a, b)
BasisFunction(const KnotVector *const xknot, int j)
const Data result[]
unsigned char dim_t
#define SPLINE_BASIS_POLYNOMAL_FACTORS(ia0, ia1, ia2, ib0, ib1, ib2, ic0, ic1, ic2)
BasisFunction & operator=(const BasisFunction &other)
void PushBack(const double x)
double operator()(const double x, const char derivative=0) const
uint16_t * data
Definition: dump1090.h:228
else return std::upper_bound(fData.begin(), fData.end(), x)-fData.begin()-1
BasisFunction(const BasisFunction &other)
double operator()(const int i) const

, generated on Tue Sep 26 2023.