/************************************************************************/
/*                                                                      */
/*    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 slice.cc
///
/// \brief create 2D image data from a 3D spline
///
/// build a 3D volume from samples of the RGB colour space
/// build a spline over it and extract a 2D slice, using vspline::transform()
/// In this example, we use an 'array-based' transform, where the coordinates
/// at which the spline is to be evaluated are held in an array of the same
/// extent as the target.
///
/// compile with:
/// clang++ -std=c++11 -march=native -o slice -O3 -pthread -DUSE_VC=1 slice.cc \
/// -lvigraimpex -lVc
/// (with Vc; use -DUSE_HWY and -lhwy for highway, or -std=c++17 and -DUSE_STDSIMD
/// for the std::simd backend)
/// or: clang++ -std=c++11 -march=native -o slice -O3 -pthread slice.cc -lvigraimpex
/// (without a SIMD backend)
/// g++ also works.

#include <iostream>

#include <vspline/vspline.h>

#include <vigra/stdimage.hxx>
#include <vigra/imageinfo.hxx>
#include <vigra/impex.hxx>

int main ( int argc , char * argv[] )
{
  // pixel_type is the result type, an RGB float pixel
  typedef vigra::TinyVector < float , 3 > pixel_type ;
  
  // voxel_type is the source data type - the same as pixel_type
  typedef vigra::TinyVector < float , 3 > voxel_type ;
  
  // coordinate_3d has a 3D coordinate
  typedef vigra::TinyVector < float , 3 > coordinate_3d ;
  
  // warp_type is a 2D array of coordinates
  typedef vigra::MultiArray < 2 , coordinate_3d > warp_type ;
  
  // target_type is a 2D array of pixels  
  typedef vigra::MultiArray < 2 , pixel_type > target_type ;
  
  // we want a b-spline with natural boundary conditions
  vigra::TinyVector < vspline::bc_code , 3 > bcv ( vspline::NATURAL ) ;
  
  // create quintic 3D b-spline object containing voxels
  vspline::bspline < voxel_type , 3 >
    space ( vigra::Shape3 ( 10 , 10 , 10 ) , 5 , bcv ) ;
  
  // fill the b-spline's core with a three-way gradient
  for ( int z = 0 ; z < 10 ; z++ )
  {
    for ( int y = 0 ; y < 10 ; y++ )
    {
      for ( int x = 0 ; x < 10 ; x++ )
      {
        voxel_type & c ( space.core [ vigra::Shape3 ( x , y , z ) ] ) ;
        c[0] = 25.5 * x ;
        c[1] = 25.5 * y ;
        c[2] = 25.5 * z ;
      }
    }
  }
  
  // prefilter the b-spline
  space.prefilter() ;
  
  // get an evaluator for the b-spline
  typedef vspline::evaluator < coordinate_3d , voxel_type > ev_type ;
  ev_type ev ( space ) ;
  
  // now make a 'warp' array with 1920X1080 3D coordinates
  warp_type warp ( vigra::Shape2 ( 1920 , 1080 ) ) ;
  
  // we want the coordinates to follow this scheme:
  // warp(x,y) = (x,1-x,y)
  // scaled appropriately
  
  for ( int y = 0 ; y < 1080 ; y++ )
  {
    for ( int x = 0 ; x < 1920 ; x++ )
    {
      coordinate_3d & c ( warp [ vigra::Shape2 ( x , y ) ] ) ;
      c[0] = float ( x ) / 192.0 ;
      c[1] = 10.0 - c[0] ;
      c[2] = float ( y ) / 108.0 ;
    }
  }
  
  // this is where the result should go:
  target_type target ( vigra::Shape2 ( 1920 , 1080 ) ) ;

  // now we perform the transform, yielding the result
  vspline::transform ( ev , warp , target ) ;

  // store the result with vigra impex
  vigra::ImageExportInfo imageInfo ( "slice.tif" );
  
  vigra::exportImage ( target ,
                      imageInfo
                      .setPixelType("UINT8")
                      .setCompression("100")
                      .setForcedRangeMapping ( 0 , 255 , 0 , 255 ) ) ;
  
  std::cout << "result was written to slice.tif" << std::endl ;
  exit ( 0 ) ;
}
