/*======================================================================================

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkTruncatedSignedDistanceFunction.h
	Version:		$Revision: 2965 $
	Date:			$Date: 2012-04-10 18:13:53 +0200 (Di, 10 Apr 2012) $

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
    University Erlangen-Nuremberg, Germany
    All rights reserved.

	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 RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef RITKTRUNCATEDSIGNEDDISTANCEFUNCTION_H__
#define RITKTRUNCATEDSIGNEDDISTANCEFUNCTION_H__

#include <itkImage.h>

#include "ritkCuda.h"
#include "ritkCudaRegularMemoryImportImageContainer.h"
#include "ritkCudaArrayImportImageContainer.h"
#include "ritkCuda3DPitchedMemoryImportImageContainer.h"
#include "ritkCuda3DArrayImportImageContainer.h"

#include "ritkRImage.h"
#include <vnl/vnl_double_3x4.h>


namespace ritk
{

/**	@ingroup	Cuda
 *	@class		TruncatedSignedDistanceFunction (TSDF)
 *	@brief		Implicit surface representation via the zero isoline of a TSDF
 *	@author		Jakob Wasza
 *
 *	@details
 *	This class implements a TruncatedSignedDistanceFunction (TSDF) that allows for an
 *	implicit surface representation using its zero isoline [1,2]. \n
 *	\n
 *	[1] A Volumetric Method for Building Complex Models from Range Images
 *	[2] KinectFusion: Real-Time Dense Surface Mapping and Tracking
 */
class CUDA_EXPORT TruncatedSignedDistanceFunction : public itk::Image<float,3>
{
public:
	/** @name Standard typedefs */
	//@{
	typedef TruncatedSignedDistanceFunction		Self;
	typedef itk::Image<float,3>					Superclass;
	typedef itk::SmartPointer<Self>				Pointer;
	typedef itk::SmartPointer<const Self>		ConstPointer;
	typedef itk::WeakPointer<const Self>		ConstWeakPointer;
	//@}

	/**	@name itk::Image meta information typedefs */
	//@{
	typedef Superclass::IndexType			IndexType;
	typedef Superclass::SizeType			SizeType;
	typedef Superclass::RegionType			RegionType;
	typedef Superclass::SpacingType			SpacingType;
	typedef Superclass::DirectionType		DirectionType;
	typedef Superclass::PointType			PointType;
	typedef Superclass::PixelType			PixelType;
	typedef Superclass::InternalPixelType	InternalPixelType;
	//@}

	/**	@name Typedefs for a range image */
	//@{
	typedef RImage<float,2>					RangeImageType;
	typedef RangeImageType::Pointer			RangeImagePointer;
	typedef RangeImageType::ConstPointer	RangeImageConstPointer;
	//@}

	/**	@name The container type to store the TSDF */
	//@{
	typedef ritk::Cuda3DArrayImportImageContainer<unsigned long, float>		TSDFContainerType;
	typedef TSDFContainerType::Pointer										TSDFContainerPointer;
	typedef TSDFContainerType::ConstPointer									TSDFContainerConstPointer;
	//@}

	/** @name Projection matrix typedefs */
	//@{
	typedef vnl_double_3x4		ProjectionMatrixType;
	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(TruncatedSignedDistanceFunction, itk::Image);

	/// Image dimension
	itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension);

	/// Override required due to GPU memory
	virtual void SetBufferedRegion(const RegionType &region);

	/**	@name Integrate a new range image */
	//@{
	virtual void IntegrateRangeImage(RangeImageConstPointer RI, ProjectionMatrixType P);
	itkGetConstMacro(NumberOfIntegratedRangeImages, unsigned int);
	//@}

	/// Reset the TSDF. Note that this method will be called during volume cration/allocation
	virtual void Reset(float CutoffDistance=10.f, float InvalidValue = 0);

	/**	@name Get the cutoff distance and invalid value */
	//@{
	itkGetConstMacro(CutoffValue, float);
	itkGetConstMacro(InvalidValue, float);
	//@}

	/**	@name Synchronize the TSDF (will be delegated to the internal CUDA container) */
	//@{
	virtual void Synchronize();
	virtual void SynchronizeHost();
	virtual void SynchronizeDevice();
	//@}

	
protected:
	/// Constructor 
	TruncatedSignedDistanceFunction();

	/// Destructor
	virtual ~TruncatedSignedDistanceFunction();

	/// Print the object on a stream
	virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;

protected:
	/**	@name Intermediate container for updating the TSDF */
	//@{
	typedef ritk::Cuda3DPitchedMemoryImportImageContainer<unsigned long, float>	IntermediateTSDFContainerType;
	typedef IntermediateTSDFContainerType::Pointer								IntermediateTSDFContainerPointer;
	typedef IntermediateTSDFContainerType::ConstPointer							IntermediateTSDFContainerConstPointer;
	IntermediateTSDFContainerPointer m_IntermediateTSDF;
	//@}

	/**	@name Temporary memory for range data */
	//@{
	typedef ritk::CudaArrayImportImageContainer<unsigned long, float>	RangeDataContainerType;
	typedef RangeDataContainerType::Pointer								RangeDataContainerPointer;
	typedef RangeDataContainerType::ConstPointer						RangeDataContainerConstPointer;
	RangeDataContainerPointer m_RangeDataContainer;
	//@}

	/**	@name	Temporary memory for flag data */
	//@{
	typedef ritk::CudaArrayImportImageContainer<unsigned long, unsigned char>	FlagDataContainerType;
	typedef FlagDataContainerType::Pointer										FlagDataContainerPointer;
	typedef FlagDataContainerType::ConstPointer									FlagDataContainerConstPointer;
	FlagDataContainerPointer m_FlagDataContainer;
	//@}

	/**	@name Cutoff and invalid value */
	//@{
	bool m_Initialized;
	float m_CutoffValue;
	float m_InvalidValue;
	//@}

	/// The number of integrated range images
	unsigned int m_NumberOfIntegratedRangeImages;

private:
	/// Purposely not implemented
	TruncatedSignedDistanceFunction(TruncatedSignedDistanceFunction&);

	/// Purposely not implemented
	void operator=(const TruncatedSignedDistanceFunction&); 
};

} // ritk

#endif // RITKTRUNCATEDSIGNEDDISTANCEFUNCTION_H__