/************************************************************************/
/*                                                                      */
/*    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 complex.cc
///
/// \brief demonstrate use of b-spline over std::complex data
///
/// vspline handles std::complex data like pairs of the complex
/// type's value_type, and uses a vigra::TinyVector of two
/// simdized value_types as the vectorized type.
/// use examples.sh to compile with g++ and clang++, and all
/// available SIMD back-ends:
/// ./examples.sh complex.cc

#include <iostream>
#include <iomanip>
#include <assert.h>
#include <complex>
#include <vspline/multithread.h>
#include <vspline/vspline.h>

int main ( int argc , char * argv[] )
{
  // nicely formatted output

  std::cout << std::fixed << std::showpoint
            << std::showpos << std::setprecision(6) ;

  // create default b-spline over 100 values

  vspline::bspline < std::complex < float > , 1 > bsp ( 100 ) ;
  
  // get a vigra::MultiArrayView to the spline's 'core'. This is the
  // area corresponding with the original data and is filled with zero.
  
  auto v1 = bsp.core ;
  
  // we only set one single value in the middle of the array

  v1 [ 50 ] = std::complex<float> ( 3.3 , 2.2 ) ;
  
  // now we convert the original data to b-spline coefficients
  // by calling prefilter()
  
  bsp.prefilter() ;

  // and create an evaluator over the spline. Here we pass three
  // template arguments to the evaluator's type declaration:
  // - float for the 'incoming type' (coordinates)
  // - std::complex<float> for the 'outgoing type' (values)
  // - 4 for the vector width, just for this example

  typedef vspline::evaluator < float , std::complex<float> , 4 > ev_type ;
  
  // create the evalator

  auto ev = ev_type ( bsp ) ;
  
  // now we evaluate the spline in the region around the single
  // nonzero value in the input data and print argument and result

  float in ;
  std::complex<float> out ;
  
  for ( int k = -12 ; k < 13 ; k++ )
  {
    in = 50.0 + k * 0.1 ;
    
    // use ev's eval() method:
    ev.eval ( in , out ) ;
    std::cout << "1. ev(" << in << ") = " << out << std::endl ;
    
    // alternatively, use ev as a callable
    std::cout << "2. ev(" << in << ") = " << ev(in) << std::endl ;
    
    // ditto, but feed immediates. note we're passing float explicitly
    std::cout << "3. ev(" << in << ") = " << ev(50.0f + k * 0.1f) << std::endl ;
  }
  
  // repeat the example evaluation with vector data

  for ( int k = -12 ; k < 13 ; k++ )
  {
    // feed the evaluator with vectors. Note how we obtain the
    // type of vectorized data the evaluator will accept from
    // the evaluator, by querying for it's 'in_v' type.
    // in_v will be a vigra::TinyVector of two SIMD vectors,
    // where the type of the SIMD vectors depends on the SIMD
    // back-end. For simplicity's sake, we initialize the
    // vectorized argument to a uniform value.
    // Note how in the output, the different SIMD back-ends
    // produce visibly different output.
    
    typename ev_type::in_v vk ( 50.0 + k * 0.1 ) ;

    std::cout << "ev(" << vk << ") = " << ev(vk) << std::endl ;
  }
}
