
/*

  Texture synthesis using Wei-Levoy algorithm

  WARNING: assumes that input texture image spacings are isotropic

*/


#ifndef _WeiLevoyTextureGenerator_h
#define _WeiLevoyTextureGenerator_h

#include "itkImageSource.h"
#include "itkSize.h"
#include "itkSmartPointer.h"

#include "DynArray.h"

template <class TOutputImage>
class WeiLevoyTextureGenerator:
  public itk::ImageSource<TOutputImage>
{

public:
  /** Standard class typedefs. */
  typedef WeiLevoyTextureGenerator   Self;
  typedef itk::ImageSource<TOutputImage>  Superclass;
  typedef itk::SmartPointer<Self>  Pointer;
  typedef itk::SmartPointer<const Self>  ConstPointer;

  typedef TOutputImage OutputImageType;
  typedef typename TOutputImage::Pointer OutputImagePointer;
  typedef typename TOutputImage::PixelType OutputImagePixelType;

  /** Typedef to describe the output image region type. */
  typedef typename TOutputImage::RegionType OutputImageRegionType;

  /** Spacing typedef support.  Spacing holds the size of a pixel.  The
   * spacing is the geometric distance between image samples. */
  typedef typename TOutputImage::SpacingType SpacingType;

  /** Origin typedef support.  The origin is the geometric coordinates
   * of the index (0,0). */
  typedef typename TOutputImage::PointType PointType;

  /** Dimensionality of the output image */
  itkStaticConstMacro(NDimensions, unsigned int, TOutputImage::ImageDimension);

  /** Size type matches that used for images */
  typedef itk::Size<itkGetStaticConstMacro(NDimensions)> SizeType;

  /** Run-time type information (and related methods). */
  itkTypeMacro(WeiLevoyTextureGenerator, itk::ImageSource);

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  typedef typename TOutputImage::IndexType IndexType;
  typedef typename TOutputImage::OffsetType OffsetType;

  typedef typename itk::Image<unsigned char, TOutputImage::ImageDimension>
    ByteImageType;
  typedef typename ByteImageType::Pointer ByteImagePointer;

  itkSetMacro(Size, SizeType);
  itkGetMacro(Size, SizeType);

  itkSetMacro(Spacing, SpacingType);
  itkGetMacro(Spacing, SpacingType);

  itkSetMacro(TextureImage, OutputImagePointer);

  itkSetMacro(MaskImage, ByteImagePointer);

  itkSetMacro(NumberOfLevels, unsigned int);
  itkGetConstMacro(NumberOfLevels, unsigned int);

  itkSetMacro(NeighborhoodRadius, unsigned int);
  itkGetConstMacro(NeighborhoodRadius, unsigned int);

  itkSetMacro(MaxTextureSamples, unsigned int);
  itkGetConstMacro(MaxTextureSamples, unsigned int);

protected:
  WeiLevoyTextureGenerator();
  ~WeiLevoyTextureGenerator();

  void GenerateData();
  virtual void GenerateOutputInformation();

private:

  WeiLevoyTextureGenerator(const WeiLevoyTextureGenerator&);
    //purposely not implemented
  void operator=(const WeiLevoyTextureGenerator&); //purposely not implemented

  void InitializeOutput(
    long rad, OutputImageType* out, const OutputImageType* texture);

  DynArray<OffsetType> _BuildNeighborhoodOffsets(long radius);
  void _WrapIndex(IndexType& ind, const SizeType& size);
  void _ReflectIndex(IndexType& ind, const SizeType& size);

  SizeType m_Size;
  SpacingType m_Spacing;

  OutputImagePointer m_TextureImage;

  ByteImagePointer m_MaskImage;

  unsigned int m_NumberOfLevels;

  unsigned int m_NeighborhoodRadius;

  unsigned int m_MaxTextureSamples;

};

#ifndef MU_MANUAL_INSTANTIATION
#include "WeiLevoyTextureGenerator.txx"
#endif

#endif
