/* ImLib3D
 * Copyright (c) 2001, ULP-IPB Strasbourg.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*!
  \file   FFT.hpp
  \brief  FFT using fftw library
*/


#ifndef _FFT_hpp
#define _FFT_hpp

#include<ImLib3D/Image3D.hpp>

#ifdef HAS_FFTW

#include<ImLib3D/ImageProcessor.hpp>
#include<ImLib3D/Image3Dlinear.hpp>


typedef FFTW_REAL_TYPE fftw_real;
typedef complex<fftw_real> complex_fftw;
typedef Image3Dlinear<complex_fftw> Image3DComplexFFTW;

#ifdef FFTW_REAL_TYPE_IS_FLOAT
typedef Image3Df Image3Dfftw;
#else
typedef Image3Dd Image3Dfftw;
#endif

/*! #&FFTOperators&# ~*/
namespace FFTOperators 
{
	void AssertCompatibleComplexType();
	void FFT(const Image3DComplexFFTW& src, Image3DComplexFFTW &res);
	void FFTInverse(const Image3DComplexFFTW& src, Image3DComplexFFTW &res);
	void FFTRealToComplex(const Image3Dfftw& src, Image3DComplexFFTW &res,bool resultFullSize=true);
	void FFTInverseComplexToReal(Image3DComplexFFTW& src0, const Size3D &fullSize, Image3Dfftw &res,bool overwriteSrc=false);
}


namespace IP3D
{
/*! #&FFTDouble&#     Complex to complex fft.
        Uses double precision. Ignores mask.
     <UL>Args:
      <LI>Source image  type:Image3Dcomplex
      <LI>Result image  type:Image3Dcomplex
     </UL>
~*/
		void FFTDouble(const Image3Dcomplexd& src, Image3Dcomplexd &res);
};

namespace IP3D
{
/*! #&FFTFloat&#     Complex to complex fft.
        Uses single precision floats. Ignores mask.
     <UL>Args:
      <LI>Source image  type:Image3Dcomplexf
      <LI>Result image  type:Image3Dcomplexf
     </UL>
~*/
		void FFTFloat(const Image3Dcomplexf& src, Image3Dcomplexf &res);
};


namespace IP3D
{
/*! #&FFTInverseDouble&#     Complex to complex inverse fft.
        Ignores mask.
     <UL>Args:
      <LI>Source image  type:Image3Dcomplex
      <LI>Result image  type:Image3Dcomplex
     </UL>
~*/
		void FFTInverseDouble(const Image3Dcomplexd& src, Image3Dcomplexd &res);
};

namespace IP3D
{
/*! #&FFTInverseFloat&#     Complex to complex inverse fft.
        Ignores mask.
     <UL>Args:
      <LI>Source image  type:Image3Dcomplexf
      <LI>Result image  type:Image3Dcomplexf
     </UL>
~*/
		void FFTInverseFloat(const Image3Dcomplexf& src, Image3Dcomplexf &res);
};

namespace IP3D
{
/*! #&FFTDoubleToComplex&#     Image3Dd  to Image3Dcomplex fft.
        Real valued FFT's can be done only with half of image (symetry), this saves 
        time (set full  size result to false).Ignores mask.
     <UL>Args:
      <LI>Source image          type:Image3Dd
      <LI>Result image          type:Image3Dcomplex
      <LI>Use full size result  type:bool
     </UL>
~*/
		void FFTDoubleToComplex(const Image3Dd& src, Image3Dcomplexd &res,bool resultFullSize=true);
};
namespace IP3D
{
/*! #&FFTFloatToComplex&#     Image3Df  to Image3Dcomplex fft.
        Real valued FFT's can be done only with half of image (symetry), this saves 
        time (set full  size result to false). 
        The result image's width is (w0/2)+1 (this loses information on the 
        original width). 
        If the inverse transform is applied, you will need to give it the original 
        size of the image. 
        Ignores mask.
     <UL>Args:
      <LI>Source image          type:Image3Df
      <LI>Result image          type:Image3Dcomplexf
      <LI>Use full size result  type:bool
     </UL>
~*/
		void FFTFloatToComplex(const Image3Df& src, Image3Dcomplexf &res,bool resultFullSize=true);
};


namespace IP3D
{
/*! #&FFTInverseComplexToDouble&#     Inverse FFT, half sided complex to real.
        Real valued FFT's can be done only with half of image (symetry), this saves 
        time. This is th inverse transform. Result is a real valued image 
     <UL>Args:
      <LI>Source image       type:Image3Dcomplex
      <LI>Result image size  type:Size3D
      <LI>Result image       type:Image3Dd
     </UL>
~*/
		void FFTInverseComplexToDouble(Image3Dcomplexd& src0, const Size3D &fullSize, Image3Dd &res,bool overwriteSrc=false);
};

namespace IP3D
{
/*! #&FFTInverseComplexToFloat&#     Inverse FFT, half sided complex to real.
        Real valued FFT's can be done only with half of image (symetry), this saves 
        time. This is th inverse transform. Result is a real valued image 
     <UL>Args:
      <LI>Source image       type:Image3Dcomplexf
      <LI>Result image size  type:Size3D
      <LI>Result image       type:Image3Df
     </UL>
~*/
		void FFTInverseComplexToFloat(Image3Dcomplexf& src0, const Size3D &fullSize,Image3Df &res,bool overwriteSrc=false);
};



#endif // HAS_FFTW
#endif //_FFT_hpp
