text: /*=========================================================================
   *
   *  Copyright Insight Software Consortium
   *
   *  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 itkImageAlgorithm_h
  #define itkImageAlgorithm_h
  
  #include "itkImageRegionIterator.h"
  
  #include <type_traits>
  
  namespace itk
  {
  
  template <typename TPixelType, unsigned int VImageDimension > class VectorImage;
  
  
  /** \class ImageAlgorithm
   *  \brief A container of static functions which can operate on Images
   *  with Iterators.
   *
   *  These methods are modeled after the STL algorithms. They may use
   *  special optimization techniques to implement enhanced versions of
   *  the methods.
   *
   *  \ingroup ITKCommon
   */
  struct ImageAlgorithm
  {
  
      using TrueType = std::true_type;
      using FalseType = std::false_type;
  
  /**
   * \brief This generic function copies a region from one image to
   * another. It may perform optimizations on the copy for efficiency.
   *
   * This method performs the equivalent to the following:
   * \code
   *     itk::ImageRegionConstIterator<TInputImage> it( inImage, inRegion );
   *     itk::ImageRegionIterator<TOutputImage> ot( outImage, outRegion );
   *
   *     while( !it.IsAtEnd() )
   *       {
   *       ot.Set( static_cast< typename TInputImage::PixelType >( it.Get() ) );
   *       ++ot;
   *       ++it;
   *       }
   * \endcode
   *
   * \note: It is important not to explicitly pass the template
   * arguments to this method as it may not result in an optimized
   * method being called.
   */
    template<typename InputImageType, typename OutputImageType>
    static void Copy( const InputImageType *inImage, OutputImageType *outImage,
                      const typename InputImageType::RegionType &inRegion,
                      const typename OutputImageType::RegionType &outRegion )
    {
      ImageAlgorithm::DispatchedCopy( inImage, outImage, inRegion, outRegion );
    }
  
  /// \cond HIDE_SPECIALIZATION_DOCUMENTATION
    template<typename TPixel1, typename TPixel2, unsigned int VImageDimension>
    static void Copy( const Image<TPixel1, VImageDimension> * inImage,
                                 Image<TPixel2, VImageDimension> * outImage,
                                 const typename Image<TPixel1, VImageDimension>::RegionType &inRegion,
                                 const typename Image<TPixel2, VImageDimension>::RegionType &outRegion )
    {
      using _ImageType1 = Image<TPixel1, VImageDimension>;
      using _ImageType2 = Image<TPixel2, VImageDimension>;
      ImageAlgorithm::DispatchedCopy( inImage, outImage, inRegion, outRegion,
                                      std::is_convertible<typename _ImageType1::PixelType,
                                      typename _ImageType2::PixelType>()
                                     );
    }
  
    template<typename TPixel1, typename TPixel2, unsigned int VImageDimension>
    static void Copy( const VectorImage<TPixel1, VImageDimension> * inImage,
                                 VectorImage<TPixel2, VImageDimension> * outImage,
                                 const typename VectorImage<TPixel1, VImageDimension>::RegionType &inRegion,
                                 const typename VectorImage<TPixel2, VImageDimension>::RegionType &outRegion )
    {
      using _ImageType1 = VectorImage<TPixel1, VImageDimension>;
      using _ImageType2 = VectorImage<TPixel2, VImageDimension>;
      ImageAlgorithm::DispatchedCopy( inImage, outImage, inRegion, outRegion,
                                      std::is_convertible<typename _ImageType1::PixelType,
                                      typename _ImageType2::PixelType>()
                                     );
    }
  
  /// \endcond
  
    /**
     * \brief Sets the output region to the smallest
     * region of the output image that fully contains
     * the physical space covered by the input
     * region of the input image
     */
    template<typename InputImageType, typename OutputImageType>
    static typename OutputImageType::RegionType
    EnlargeRegionOverBox(const typename InputImageType::RegionType & inputRegion,
                         const InputImageType* inputImage,
                         const OutputImageType* outputImage);
  
  private:
  
    /** This is an optimized method which requires the input and
     * output images to be the same, and the pixel being POD (Plain Old
     * Data).
     */
    template<typename InputImageType, typename OutputImageType>
    static void DispatchedCopy( const InputImageType *inImage, OutputImageType *outImage,
                                const typename InputImageType::RegionType &inRegion,
                                const typename OutputImageType::RegionType &outRegion, TrueType isSpecialized );
  
    /** this is the reference image iterator implementation */
    template<typename InputImageType, typename OutputImageType>
    static void DispatchedCopy( const InputImageType *inImage, OutputImageType *outImage,
                                const typename InputImageType::RegionType &inRegion,
                                const typename OutputImageType::RegionType &outRegion, FalseType isSpecialized = FalseType() );
  
  
    /** A utility class to get the number of internal pixels to make up
     * a pixel.
     */
    template <typename TImageType>
    struct PixelSize
    {
      static size_t Get( const TImageType *)
        {
        return 1;
        }
    };
  
  /// \cond HIDE_SPECIALIZATION_DOCUMENTATION
    template <typename TPixelType, unsigned int VImageDimension>
    struct PixelSize< VectorImage<TPixelType, VImageDimension> >
    {
      using ImageType = VectorImage<TPixelType, VImageDimension>;
      static size_t Get( const  ImageType * i )
        {
        const size_t vectorLength = ImageType::AccessorFunctorType::GetVectorLength(i);
        return vectorLength;
        }
    };
  /// \endcond
  
    /** Unary functor just for static_cast operator */
    template<typename TInputType, typename TOutputType>
    struct StaticCast
      {
      TOutputType operator() (const TInputType i) { return static_cast<TOutputType>(i); }
      };
  
  
    /** Function to dispatch to std::copy or std::transform. */
    template<typename TType>
    static TType* CopyHelper(const TType *first, const TType *last, TType *result)
      {
      // Note: On some MS compilers the following may generate a
      // warning. Please include itkMacro.h before <algorithm> or
      // another stl header to avoid.
      return std::copy(first, last, result);
      }
  
  /// \cond HIDE_SPECIALIZATION_DOCUMENTATION
    template<typename TInputType, typename TOutputType>
    static TOutputType* CopyHelper(const TInputType *first, const TInputType *last, TOutputType *result)
      {
      return std::transform(first, last, result, StaticCast<TInputType,TOutputType>());
      }
  /// \endcond
  
  
  };
  } // end namespace itk
  
  
  #ifndef ITK_MANUAL_INSTANTIATION
  #include "itkImageAlgorithm.hxx"
  #endif
  
  
  #endif //itkImageAlgorithm_h
  