PCL
CubicSplineInterpolation.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/CubicSplineInterpolation.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_CubicSplineInterpolation_h
53 #define __PCL_CubicSplineInterpolation_h
54 
56 
57 #include <pcl/Defs.h>
58 #include <pcl/Diagnostics.h>
59 
61 
62 namespace pcl
63 {
64 
65 // ----------------------------------------------------------------------------
66 
67 #define m_x this->m_x
68 #define m_y this->m_y
69 
80 template <typename T = double>
82 {
83 public:
84 
85  using vector_type = typename UnidimensionalInterpolation<T>::vector_type;
86 
92 
97 
102 
107  {
108  }
109 
119  void GetBoundaryConditions( double& y1, double& yn ) const
120  {
121  y1 = m_dy1;
122  yn = m_dyn;
123  }
124 
134  void SetBoundaryConditions( double y1, double yn )
135  {
136  Clear();
137  m_dy1 = y1;
138  m_dyn = yn;
139  }
140 
160  void Initialize( const vector_type& x, const vector_type& y ) override
161  {
162  if ( y.Length() < 2 )
163  throw Error( "CubicSplineInterpolation::Initialize(): Less than two data points specified." );
164 
165  try
166  {
167  Clear();
169 
170  int n = this->Length();
171  m_dy2 = DVector( n );
172  m_current = -1; // prepare for 1st interpolation
173  DVector w( n ); // working vector
174 
175  if ( m_x )
176  {
177  /*
178  * Cubic splines with explicit x[i] for i = {0,...,n-1}.
179  */
180  if ( m_dy1 == 0 && m_dyn == 0 )
181  {
182  /*
183  * Natural cubic spline.
184  */
185  m_dy2[0] = m_dy2[n-1] = w[0] = 0;
186 
187  for ( int i = 1; i < n-1; ++i )
188  {
189  double s = (double( m_x[i] ) - double( m_x[i-1] )) / (double( m_x[i+1] ) - double( m_x[i-1] ));
190  double p = s*m_dy2[i-1] + 2;
191  m_dy2[i] = (s - 1)/p;
192  w[i] = (double( m_y[i+1] ) - double( m_y[i ] )) / (double( m_x[i+1] ) - double( m_x[i ] ))
193  - (double( m_y[i ] ) - double( m_y[i-1] )) / (double( m_x[i ] ) - double( m_x[i-1] ));
194  w[i] = (6*w[i]/(double( m_x[i+1] ) - double( m_x[i-1] )) - s*w[i-1])/p;
195  }
196 
197  for ( int i = n-2; i > 0; --i ) // N.B. w[0] is not defined
198  m_dy2[i] = m_dy2[i]*m_dy2[i+1] + w[i];
199  }
200  else
201  {
202  /*
203  * Cubic spline with prescribed end point derivatives.
204  */
205  w[0] = 3/(double( m_x[1] ) - double( m_x[0] ))
206  * ((double( m_y[1] ) - double( m_y[0] ))/(double( m_x[1] ) - double( m_x[0] )) - m_dy1);
207 
208  m_dy2[0] = -0.5;
209 
210  for ( int i = 1; i < n-1; ++i )
211  {
212  double s = (double( m_x[i] ) - double( m_x[i-1] )) / (double( m_x[i+1] ) - double( m_x[i-1] ));
213  double p = s*m_dy2[i-1] + 2;
214  m_dy2[i] = (s - 1)/p;
215  w[i] = (double( m_y[i+1] ) - double( m_y[i ] )) / (double( m_x[i+1] ) - double( m_x[i ] ))
216  - (double( m_y[i ] ) - double( m_y[i-1] )) / (double( m_x[i ] ) - double( m_x[i-1] ));
217  w[i] = (6*w[i]/(double( m_x[i+1] ) - double( m_x[i-1] )) - s*w[i-1])/p;
218  }
219 
220  m_dy2[n-1] = (3/(double( m_x[n-1] ) - double( m_x[n-2] ))
221  * (m_dyn - (double( m_y[n-1] ) - double( m_y[n-2] ))/(double( m_x[n-1] ) - double( m_x[n-2] ))) - w[n-2]/2)
222  / (1 + m_dy2[n-2]/2);
223 
224  for ( int i = n-2; i >= 0; --i )
225  m_dy2[i] = m_dy2[i]*m_dy2[i+1] + w[i];
226  }
227  }
228  else
229  {
230  /*
231  * Natural cubic spline with
232  * implicit x[i] = i for i = {0,1,...,n-1}.
233  */
234  m_dy2[0] = m_dy2[n-1] = w[0] = 0;
235 
236  for ( int i = 1; i < n-1; ++i )
237  {
238  double p = m_dy2[i-1]/2 + 2;
239  m_dy2[i] = -0.5/p;
240  w[i] = double( m_y[i+1] ) - 2*double( m_y[i] ) + double( m_y[i-1] );
241  w[i] = (3*w[i] - w[i-1]/2)/p;
242  }
243 
244  for ( int i = n-2; i > 0; --i ) // N.B. w[0] is not defined
245  m_dy2[i] = m_dy2[i]*m_dy2[i+1] + w[i];
246  }
247  }
248  catch ( ... )
249  {
250  Clear();
251  throw;
252  }
253  }
254 
259  double operator()( double x ) const override
260  {
261  PCL_PRECONDITION( IsValid() )
262 
263  int n = this->Length();
264 
265  if ( m_x )
266  {
267  /*
268  * Cubic spline with explicit x[i] for i = {0,...,n-1}.
269  */
270 
271  /*
272  * Bracket the evaluation point x by binary search of the closest
273  * pair of data points, if needed. m_current < 0 signals first-time
274  * evaluation since initialization.
275  */
276  int j0 = m_current, j1;
277  if ( j0 < 0 || x < m_x[j0] || m_x[j0+1] < x )
278  for ( j0 = 0, j1 = n-1; j1-j0 > 1; )
279  {
280  int m = (j0 + j1) >> 1;
281  if ( x < m_x[m] )
282  j1 = m;
283  else
284  j0 = m;
285  }
286  else
287  j1 = j0 + 1;
288  m_current = j0;
289 
290  /*
291  * Distance h between the closest neighbors. Will be zero (or
292  * insignificant) if two or more x values are equal with respect to
293  * the machine epsilon for type T.
294  */
295  double h = double( m_x[j1] ) - double( m_x[j0] );
296  if ( 1 + h == 1 )
297  return 0.5*(double( m_y[j0] ) + double( m_y[j1] ));
298 
299  double a = (double( m_x[j1] ) - x)/h;
300  double b = (x - double( m_x[j0] ))/h;
301  return a*double( m_y[j0] )
302  + b*double( m_y[j1] )
303  + ((a*a*a - a)*m_dy2[j0] + (b*b*b - b)*m_dy2[j1])*h*h/6;
304  }
305  else
306  {
307  /*
308  * Natural cubic spline with implicit x[i] = i for i = {0,1,...,n-1}.
309  */
310  int j0 = pcl::Range( pcl::TruncInt( x ), 0, n-1 );
311  int j1 = pcl::Min( n-1, j0+1 );
312  double a = j1 - x;
313  double b = x - j0;
314  return a*double( m_y[j0] )
315  + b*double( m_y[j1] )
316  + ((a*a*a - a)*m_dy2[j0] + (b*b*b - b)*m_dy2[j1])/6;
317  }
318  }
319 
324  void Clear() override
325  {
327  m_dy2.Clear();
328  }
329 
334  bool IsValid() const override
335  {
336  return m_dy2;
337  }
338 
339 private:
340 
341  double m_dy1 = 0; // 1st derivative of spline at the first data point
342  double m_dyn = 0; // 1st derivative of spline at the last data point
343  DVector m_dy2; // second derivatives of the interpolating function at x[i]
344  mutable int m_current = -1; // index of the current interpolation segment
345 };
346 
347 #undef m_x
348 #undef m_y
349 
350 // ----------------------------------------------------------------------------
351 
352 } // pcl
353 
354 #endif // __PCL_CubicSplineInterpolation_h
355 
356 // ----------------------------------------------------------------------------
357 // EOF pcl/CubicSplineInterpolation.h - Released 2024-06-18T15:48:54Z
Generic interpolating cubic spline.
double operator()(double x) const override
void SetBoundaryConditions(double y1, double yn)
void Initialize(const vector_type &x, const vector_type &y) override
CubicSplineInterpolation(CubicSplineInterpolation &&)=default
void GetBoundaryConditions(double &y1, double &yn) const
CubicSplineInterpolation(const CubicSplineInterpolation &)=default
A simple exception with an associated error message.
Definition: Exception.h:239
Generic vector of arbitrary length.
Definition: Vector.h:107
A generic interface to one-dimensional interpolation algorithms.
virtual void Initialize(const vector_type &x, const vector_type &y)
int TruncInt(T x) noexcept
Definition: Math.h:1132
constexpr const T & Min(const T &a, const T &b) noexcept
Definition: Utility.h:90
constexpr const T & Range(const T &x, const T &a, const T &b) noexcept
Definition: Utility.h:190
PCL root namespace.
Definition: AbstractImage.h:77