/************************************************************************/
/*                                                                      */
/*    vspline - a set of generic tools for creation and evaluation      */
/*              of uniform b-splines                                    */
/*                                                                      */
/*            Copyright 2015 - 2023 by Kay F. Jahnke                    */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

/// \file quickstart.cc
///
/// \brief sample code from the documentation
///
/// just the bits of code given in the 'Quickstart' section of the
/// documentation overview
///
/// compile: clang++ -std=c++11 -o quickstart -pthread quickstart.cc

#include <vspline/vspline.h>
#include <iostream>
#include <iomanip>

using namespace std ;
using namespace vigra ;
using namespace vspline ;

int main ( int argc , char * argv[] )
{
  // given a vigra::MultiArray of data

  vigra::MultiArray < 2 , float > a ( 10 , 20 ) ;

  // let's initialize the whole array with 42

  a = 42 ;

  typedef vspline::bspline < float , 2 > spline_type ; // fix the type of the spline
  
  spline_type bspl ( a.shape() ) ; // create bspline object 'bspl' suitable for your data
  
  bspl.core = a ;         // copy the source data into the bspline object's 'core' area
  
  bspl.prefilter() ; // run prefilter() to convert original data to b-spline coefficients

  // for a 2D spline, we want 2D coordinates
  
  typedef vigra::TinyVector < float , 2 > coordinate_type ;
  
  // get the appropriate evaluator type
  
  typedef vspline::evaluator < coordinate_type , float > eval_type ;
  
  // create the evaluator
  
  eval_type ev ( bspl ) ;

  // create variables for input and output: 

  float x = 3 , y = 4 ;
  coordinate_type coordinate ( x , y ) ;
  float result ;

  // use the evaluator to produce the result

  ev.eval ( coordinate , result ) ; // evaluate at (x,y)

  auto r = ev ( coordinate ) ;     // alternative evaluation as a functor

  assert ( r == result ) ;

  // create a 1D array containing (2D) coordinates into 'a'

  vigra::MultiArray < 1 , coordinate_type > coordinate_array ( 3 ) ;

  // we initialize the coordinate array by hand...

  coordinate_array[0] = coordinate_array[1] = coordinate_array[2] = coordinate ;

  // create an array to accomodate the result of the remap operation

  vigra::MultiArray < 1 , float > target_array ( 3 ) ;
  
  // perform the remap

  vspline::remap ( a , coordinate_array , target_array ) ;

  auto ic = coordinate_array.begin() ;
  for ( auto k : target_array )
    assert ( k == ev ( *(ic++) ) ) ;

  // instead of the remap, we can use transform, passing the evaluator for
  // the b-spline over 'a' instead of 'a' itself. the result is the same.

  vspline::transform ( ev , coordinate_array , target_array ) ; 

  // create a 2D array for the index-based transform operation

  vigra::MultiArray < 2 , float > target_array_2d ( 3 , 4 ) ;

  // use transform to evaluate the spline for the coordinates of
  // all values in this array

  vspline::transform ( ev , target_array_2d ) ;

  for ( int x = 0 ; x < 3 ; x ++ )
  {
    for ( y = 0 ; y < 4 ; y++ )
    {
      coordinate_type c { float(x) , float(y) } ;
      assert ( target_array_2d [ c ] == ev ( c ) ) ;
    }
  }

  vigra::MultiArray < 2 , float > b ( 10 , 20 ) ;
  vspline::transform ( ev , b ) ;

  auto ia = a.begin() ;
  for ( auto r : b )
    assert ( vigra::closeAtTolerance ( *(ia++) , r , .00001 ) ) ;
  
  vigra::MultiArray < 2 , float > c ( 10 , 20 ) ;
  vspline::restore ( bspl , c ) ; // TODO: problem with g++
  
  auto ib = b.begin() ;
  for ( auto & ic : c )
    assert ( vigra::closeAtTolerance ( *(ib++) , ic , .00001 ) ) ;
}
