/*=========================================================================
*
*  Copyright NumFOCUS
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0.txt
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*=========================================================================*/
#ifndef sitkWarpImageFilter_h
#define sitkWarpImageFilter_h

/*
 * WARNING: DO NOT EDIT THIS FILE!
 * THIS FILE IS AUTOMATICALLY GENERATED BY THE SIMPLEITK BUILD PROCESS.
 * Please look at sitkDualImageFilterTemplate.h.in to make changes.
 */

#include <memory>

#include "sitkImageFilter.h"
#include "sitkDualMemberFunctionFactory.h"
#include "sitkBasicFilters.h"

namespace itk::simple {

    /**\class WarpImageFilter
\brief Warps an image using an input displacement field.

WarpImageFilter warps an existing image with respect to a given displacement field.

A displacement field is represented as a image whose pixel type is some vector type with at least N elements, where N is the dimension of the input image. The vector type must support element access via operator [].

The output image is produced by inverse mapping: the output pixels are mapped back onto the input image. This scheme avoids the creation of any holes and overlaps in the output image.

Each vector in the displacement field represent the distance between a geometric point in the input space and a point in the output space such that:

 \f[ p_{in} = p_{out} + d \f] 

Typically the mapped position does not correspond to an integer pixel position in the input image. Interpolation via an image function is used to compute values at non-integer positions. The default interpolation typed used is the LinearInterpolateImageFunction . The user can specify a particular interpolation function via SetInterpolator() . Note that the input interpolator must derive from base class InterpolateImageFunction .

Position mapped to outside of the input image buffer are assigned a edge padding value.

The LargestPossibleRegion for the output is inherited from the input displacement field. The output image spacing, origin and orientation may be set via SetOutputSpacing, SetOutputOrigin and SetOutputDirection. The default are respectively a vector of 1's, a vector of 0's and an identity matrix.

This class is templated over the type of the input image, the type of the output image and the type of the displacement field.

The input image is set via SetInput. The input displacement field is set via SetDisplacementField.

This filter is implemented as a multithreaded filter.

\warning This filter assumes that the input type, output type and displacement field type all have the same number of dimensions.
\sa itk::simple::Warp for the procedural interface
\sa itk::WarpImageFilter for the Doxygen on the original ITK class.
     */
    class SITKBasicFilters_EXPORT WarpImageFilter : public ImageFilter {
    public:
      using Self = WarpImageFilter;

      /** Destructor */
      virtual ~WarpImageFilter();

      /** Default Constructor that takes no arguments and initializes
       * default parameters */
      WarpImageFilter();

      /** Define the pixels types supported by this filter */
      using PixelIDTypeList = BasicPixelIDTypeList;

\

      /**
       * Get/Set the interpolator function.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetInterpolator ( InterpolatorEnum Interpolator ) { this->m_Interpolator = Interpolator; return *this; }

      /**
       * Get/Set the interpolator function.
       */
      InterpolatorEnum GetInterpolator() const { return this->m_Interpolator; }\

      /**
       * Set the size of the output image.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetOutputSize ( std::vector<uint32_t> OutputSize ) { this->m_OutputSize = std::move(OutputSize); return *this; }

      /**
       * Get the size of the output image.
       */
      std::vector<uint32_t> GetOutputSize() const { return this->m_OutputSize; }\

      /**
       * Set the output image origin.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetOutputOrigin ( std::vector<double> OutputOrigin ) { this->m_OutputOrigin = std::move(OutputOrigin); return *this; }

      /**
       * Get the output image origin.
       */
      std::vector<double> GetOutputOrigin() const { return this->m_OutputOrigin; }\

      /**
       * Set the output image spacing.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetOutputSpacing ( std::vector<double> OutputSpacing ) { this->m_OutputSpacing = std::move(OutputSpacing); return *this; }

      /**
       * Get the output image spacing.
       */
      std::vector<double> GetOutputSpacing() const { return this->m_OutputSpacing; }\

      /**
       * Set/Get the direction (orientation) of the output image
       */
      SITK_RETURN_SELF_TYPE_HEADER SetOutputDirection ( std::vector<double> OutputDirection ) { this->m_OutputDirection = OutputDirection; return *this; }

      /**
       * Set/Get the direction (orientation) of the output image
       */
      std::vector<double> GetOutputDirection() const { return this->m_OutputDirection; }\

      /**
       * Set the edge padding value
       */
      SITK_RETURN_SELF_TYPE_HEADER SetEdgePaddingValue ( double EdgePaddingValue ) { this->m_EdgePaddingValue = EdgePaddingValue; return *this; }

      /**
       * Get the edge padding value
       */
      double GetEdgePaddingValue() const { return this->m_EdgePaddingValue; }

      /** Name of this class */
      std::string GetName() const { return std::string ("WarpImageFilter"); }

      /** Print ourselves out */
      std::string ToString() const;


      /** Execute the filter on the input image */

      Image Execute ( const Image & image, const Image & displacementField );


      /** This methods sets the output size, origin, spacing and direction to that of the provided image */
      void SetOutputParameteresFromImage(const Image & refImage );


    private:
      /** Setup for member function dispatching */
      using MemberFunctionType = Image (Self::*)( const Image * image, const Image * displacementField );

      friend struct detail::DualExecuteInternalAddressor<MemberFunctionType>;
      template <class TImageType1, class TImageType2> Image DualExecuteInternal ( const Image * image, const Image * displacementField );
      friend struct detail::DualExecuteInternalVectorAddressor<MemberFunctionType>;
      template <class TImageType1, class TImageType2> Image DualExecuteInternalVector ( const Image * image, const Image * displacementField );

      std::unique_ptr<detail::DualMemberFunctionFactory<MemberFunctionType> > m_DualMemberFactory;



      /*  */
      InterpolatorEnum  m_Interpolator{itk::simple::sitkLinear};

      /*  */
      std::vector<uint32_t>  m_OutputSize{std::vector<uint32_t>(3, 0)};

      /*  */
      std::vector<double>  m_OutputOrigin{std::vector<double>(3, 0.0)};

      /*  */
      std::vector<double>  m_OutputSpacing{std::vector<double>(3, 1.0)};

      /* Passing a zero sized array, defaults to identiy matrix. The size of the array must exactly match the direction matrix for the dimension of the image. */
      std::vector<double>  m_OutputDirection{std::vector<double>()};

      double  m_EdgePaddingValue{0.0};


    };

    /**\
     * \brief Warps an image using an input displacement field.
     *
     * This function directly calls the execute method of WarpImageFilter
     * in order to support a procedural API
     *
     * \sa itk::simple::WarpImageFilter for the object oriented interface
     * @{
     */

     SITKBasicFilters_EXPORT Image Warp ( const Image & image, const Image & displacementField, InterpolatorEnum interpolator = itk::simple::sitkLinear, std::vector<uint32_t> outputSize = std::vector<uint32_t>(3, 0), std::vector<double> outputOrigin = std::vector<double>(3, 0.0), std::vector<double> outputSpacing = std::vector<double>(3, 1.0), std::vector<double> outputDirection = std::vector<double>(), double edgePaddingValue = 0.0 );

     /** @} */
}
#endif
