Author Topic: PCL source preview: pcl/AkimaInterpolation.h  (Read 7853 times)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
PCL source preview: pcl/AkimaInterpolation.h
« on: 2007 August 25 11:04:10 »
This is the new pcl/AkimaInterpolation.h header that will be released in the next version of the PCL framework. It implements Akima subspline interpolation, which is used in the new CurvesTransform and ColorSaturation processes and interfaces (see this thread on the Announcements section.

Since the AkimaInterpolation class is completely implemented in this header, it can be readily incorporated into existing installations and will work without problems.

Code: [Select]
// ----------------------------------------------------------------------------
// PixInsight Class Library - PCL 01.00.15.0125
// Copyright (c) 2003-2007 Pleiades Software. All Rights Reserved.
// ----------------------------------------------------------------------------
// pcl/AkimaInterpolation.h - Released 2007/08/18 18:53:15 UTC
// ----------------------------------------------------------------------------
// This file is part of the PCL. The PCL is an ISO C++ API for development of
// PixInsight modules. The PCL is provided in the hope that it will be useful,
// but it is distributed "AS IS" WITHOUT ANY WARRANTY; without even the
// warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------

#ifndef __PCL_AkimaInterpolation_h
#define __PCL_AkimaInterpolation_h

/// \file pcl/AkimaInterpolation.h

#ifndef __PCL_Defs_h
#include <pcl/Defs.h>
#endif

#ifndef __PCL_Diagnostics_h
#include <pcl/Diagnostics.h>
#endif

#ifndef __PCL_UnidimensionalInterpolation_h
#include <pcl/UnidimensionalInterpolation.h>
#endif

#ifndef __PCL_Math_h
#include <pcl/Math.h>
#endif

#ifndef __PCL_Search_h
#include <pcl/Search.h>
#endif

#ifndef __PCL_StatusMonitor_h
#include <pcl/StatusMonitor.h>
#endif

namespace pcl
{

// ----------------------------------------------------------------------------

#define n   this->n
#define xv  this->xv
#define yv  this->yv
   
// ----------------------------------------------------------------------------

/*! \class AkimaInterpolation
    \brief Akima subspline interpolation algorithm
   
   Reference:
   Hiroshi Akima, A new method of interpolation and smooth curve fitting
   based on local procedures, Journal of the ACM, Vol. 17, No. 4, October 1970,
   pages 589-602.

   Our implementation is based on the book Numerical Algorithms with C, by
   G. Engeln-Müllges and F. Uhlig (Springer, 1996), section 13.1. We properly
   represent corners when a data point lies between two adjacent straight lines
   with different slopes. This means that our implementation does not impose
   continuous differentiability, which deviates from the original work by
   Akima. Supporting the accurate representation of corners has several
   practical advantages in our opinion; one of them is the enhanced flexibility
   for the application of Akima interpolation to graphical representations of
   curves given by a set of prescribed x,y data points.
*/
template <class T>
class AkimaInterpolation : public UnidimensionalInterpolation<T>
{
public:

   /*!
      Constructs an %AkimaInterpolation object.
   */
   AkimaInterpolation() : UnidimensionalInterpolation<T>(), b( 0 ), c( 0 ), d( 0 )
   {
   }

   /*!
      Destroys an %AkimaInterpolation object.
   */
   virtual ~AkimaInterpolation()
   {
   }

   /*!
      Initializes a new interpolation.

      \param xData      Vector of x-values:

               <ul>
               <li>If xData != 0: Must be a set of monotonically increasing,
                                  distinct values: x[0] < x[1] < ... < x[n-1].</li>

               <li>If xData == 0: The interpolation will use implicit
                                  x[i] = i for i = {0,1,2,3,...,n-1}.</li>
               </ul>

      \param yData      Vector of function values for i = {0,1,2,3,...,n-1}.

      \param nelem      Number of data elements. Must be >= 5. This is because
                        Akima interpolation requires at least 4 subintervals.

      \param monitor    Optional address of a status monitoring object. Derived
                        classes may use this object to report status
                        information during initialization.
   */
   virtual void Initialize( const T* xData, const T* yData, size_type nelem, StatusMonitor* monitor = 0 )
   {
      PCL_PRECONDITION( nelem >= 5 )
     
      if ( nelem < 5 )
         throw Error( "Need five or more data items for AkimaInterpolation" );

      Clear();
      UnidimensionalInterpolation<T>::Initialize( xData, yData, nelem, monitor );

      size_type N = n-1; // Number of subintervals
      T* m0 = 0;         // Chordal slopes
      T* tL = 0;         // Akima left-hand slopes to support corners
     
      try
      {
         b = new T[ N ];
         c = new T[ N ];
         d = new T[ N ];
         
         m0 = new T[ N + 4 ]; // Room for 4 additional prescribed slopes
         T* m = m0 + 2;       // Allow negative subscripts m[-1] and m[-2]

         tL = new T[ n ];
         
         // Calculate chordal slopes for each subinterval
         for ( size_type i = 0; i < N; ++i )
            m[i] = (yv[i+1] - yv[i])/(xv[i+1] - xv[i]);

         // Prescribed slopes at ending locations
         m[-2 ] = 3*m[  0] - 2*m[  1];
         m[-1 ] = 2*m[  0] -   m[  1];
         m[ N ] = 2*m[N-1] -   m[N-2];
         m[N+1] = 3*m[N-1] - 2*m[N-2];

         // Akima left-hand and right-hand slopes
         // Right-hand slopes are just the interpolation coefficients bi.
         for ( int i = 0; size_type( i ) < n; ++i )
         {
            T f = Abs( m[i-1] - m[i-2] );
            T e = Abs( m[i+1] - m[i] ) + f;
            if ( 1 + e != 1 )
            {
               tL[i] = m[i-1] + f*(m[i] - m[i-1])/e;
               if ( size_type( i ) < N )
                  b[i] = tL[i];
            }
            else
            {
               tL[i] = m[i-1];
               if ( size_type( i ) < N )
                  b[i] = m[i];
            }
         
            if ( monitor != 0 )
               ++*monitor;
         }

         // Interpolation coefficients b[i], c[i], d[i]. a[i] coefficients are
         // the yv[i] ordinate values.
         for ( size_type i = 0; i < N; ++i )
         {
            c[i] = 3*m[i] - 2*b[i] - tL[i+1];
            d[i] = b[i] + tL[i+1] - 2*m[i];
            if ( xv != 0 )
            {
               T h = xv[i+1] - xv[i];
               c[i] /= h;
               d[i] /= h*h;
            }
         }

         delete [] tL, tL = 0;
         delete [] m0, m0 = 0;
      }

      catch ( ... )
      {
         if ( tL != 0 )
            delete [] tL;
         if ( m0 != 0 )
            delete [] m0;
         Clear();
         throw;
      }
   }

   /*!
      Returns an interpolated function value at \a x location.
   */
   virtual double operator()( double x ) const
   {
      PCL_PRECONDITION( b != 0 && c != 0 && d != 0 )

      // Find the subinterval i such that xv[i] <= x < xv[i+1]
      // Find the distance dx = x - xv[i], or dx = x - i for implicit x = {0,1,2,3,...n-1}
      size_type i;
      T dx;
      if ( xv != 0 )
      {
         if ( x <= *xv )
            return *yv;
         if ( x >= xv[n-1] )
            return yv[n-1];
         i = InsertionPoint( xv, xv+n, x ) - xv - 1; // -1 because i is a *subinterval* index
         dx = x - xv[i];
      }
      else
      {
         if ( x <= 0 )
            return *yv;
         if ( x >= n-1 )
            return yv[n-1];
         i = size_type( x );
         dx = x - i;
      }

      // Use a Horner scheme to calculate b[i]*dx + c[i]*dx^2 + d[i]*dx^3.
      return yv[i] + dx*(b[i] + dx*(c[i] + dx*d[i]));
   }

   /*!
      Frees internal data structures in this AkimaInterpolation object.
   */
   virtual void Clear()
   {
      if ( b != 0 )
         delete [] b, b = 0;      
      if ( c != 0 )
         delete [] c, c = 0;
      if ( d != 0 )
         delete [] d, d = 0;
      UnidimensionalInterpolation<T>::Clear();
   }

   // -------------------------------------------------------------------------

protected:

   // Interpolating coefficients for each subinterval.
   // The coefficients for dx^0 are the input ordinate values in the yv vector.
   T* b; // coefficients for dx^1
   T* c; // coefficients for dx^2
   T* d; // coefficients for dx^3
};

// ----------------------------------------------------------------------------

#undef n
#undef xv
#undef yv

// ----------------------------------------------------------------------------

} // pcl

#endif  // __PCL_AkimaInterpolation_h

// ----------------------------------------------------------------------------
// EOF pcl/AkimaInterpolation.h - Released 2007/08/18 18:53:15 UTC
Juan Conejero
PixInsight Development Team
http://pixinsight.com/