/* -*- mia-c++ -*-
 *
 * This file is part of viewitgui - a library and program for the
 * visualization of 3D data sets. 
 *
 * Copyright (c) Leipzig, Madrid 1999-2013 Mirco Hellmann, Gert Wollny
 *
 * viewitgui 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 3 of the License, or
 * (at your option) any later version.
 *
 * viewitgui 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 viewitgui; if not, see <http://www.gnu.org/licenses/>.
 */


#ifndef MOVER_HH
#define MOVER_HH


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <ctime>
#include <cstdlib>

#include <mia/3d/vector.hh>

namespace mia {

template <class Deformation, class voxel> 
class TVoxelMover {
	const Deformation& _M_deform;
	
protected: 
	typedef typename  Deformation::const_iterator::value_type deform_type;
public:
	
	/** Constructor initialized the mover with 
	    \param __deform a deformation (interpreted as velocity field)
	*/
	TVoxelMover(const Deformation& __deform):
		_M_deform(__deform)
	{}
	
	/// this destructor is virtual 
	virtual ~TVoxelMover(){}
	
	
	/**
	   The forward movement function moves a voxel in the direction of the deformation
	   \param __v the voxel to be moved
	   \param __time_step a time step parameter
	   \retval __v the voxel with the new position
	   \returns the square of the Euclidian norm of the move applied
	 */
	
	virtual float forward(voxel *__v, float __time_step)const {
		auto shift = _M_deform(*__v) * __time_step;
		*__v += shift; 
		return shift.norm2();
	}

	/**
	   The backward movement function moves a voxel against the direction of the deformation
	   \param __v the voxel to be moved
	   \param __time_step a time step parameter
	   \retval __v the voxel with the new position
	   \returns the square of the Euclidian norm of the move applied
	 */

	virtual float backward(voxel *__v, float __time_step)const {
		auto shift = _M_deform(*__v) * __time_step;
		*__v -= shift; 
		return shift.norm2();
	}
	
	float operator()(const voxel& v)const {
		return _M_deform(v).norm2();
	}
protected:
	/**
	   Get the deformation at a certain location
	   \param __v the location;
	   \returns deformation vector
	*/
	
	deform_type get_deform(const deform_type& __v)const {
		return _M_deform(__v);
	}
};


/** This is a class to move pixels around according to a deformation added 
    with brownian random movement.  
*/

template <class Deformation, class voxel> 
class TBrownVoxelMover: public TVoxelMover<Deformation,voxel> {
	float _M_brown_weight;
protected: 
	typedef typename  Deformation::const_iterator::value_type deform_type;
public:
	
	/** Constructor initialized the mover with 
	    \param __deform a deformation (interpreted as velocity field)
	    \param __brown_weight a weighting of brownian movement
	*/
	TBrownVoxelMover(const Deformation& __deform, float __brown_weight):
		TVoxelMover<Deformation,voxel>(__deform),
		_M_brown_weight(__brown_weight)
	{
		srand48(time(NULL));
	}
	
	
	/**
	   The forward movement function moves a voxel in the direction of the deformation
	   \param __v the location  to be moved
	   \param __time_step a time step parameter
	   \retval __v the new location 
	   \returns the square of the Euclidian norm of the move applied
	 */
	
	virtual float forward(voxel *__v, float __time_step)const {
		deform_type brown(drand48() - 0.5, drand48() - 0.5, drand48() - 0.5);
		deform_type shift = __time_step * (this->get_deform(*__v) + _M_brown_weight * brown );
		*__v += shift; 
		return shift.norm2();
	}

	/**
	   The backward movement function moves a voxel against the direction of the deformation
	   \param __v the location  to be moved
	   \param __time_step a time step parameter
	   \retval __v the new location 
	   \returns the square of the Euclidian norm of the move applied
	 */

	virtual float backward(voxel *__v, float __time_step)const {
		deform_type brown(drand48() - 0.5, drand48() - 0.5, drand48() - 0.5);
		deform_type shift = __time_step * (this->get_deform(*__v) + _M_brown_weight * brown );
		*__v -= shift; 
		return shift.norm2();
	}
};


template <class vector3d>
class T3DVectorSource {
	C3DBounds _M_size; 
public:
	T3DVectorSource(const C3DBounds& __size):
		_M_size(__size)
	{
		_M_size.x--;
		_M_size.y--;
		_M_size.z--;
		srand48(time(NULL));
	}
	
	vector3d operator() () const 
	{
		return vector3d(_M_size.x * drand48(), 
				_M_size.y * drand48(), 
				_M_size.z * drand48());
	}
	
	bool inside(const vector3d& __v) {
		C3DBounds b(__v);
		return b.x < _M_size.x && b.y < _M_size.y && b.z < _M_size.z;
	}
};

} // end namespace

#endif

/* CVS LOG

   $Log$
   Revision 1.4  2005/06/29 13:22:23  wollny
   switch to version 0.7

   Revision 1.1.1.1  2005/03/17 13:44:22  gerddie
   initial import 

   Revision 1.3  2005/01/05 14:42:35  jaenicke
   Corrected some doxygen warnings.

   Revision 1.2  2004/08/25 09:08:32  wollny
   added an emacs style comment to all source files

   Revision 1.1  2004/07/09 14:54:19  tittge
   making pthreads default

   Revision 1.4  2004/06/03 09:57:32  wollny
   Changed (hopefully) all instancable class names to Cxxxxx

   Revision 1.3  2004/05/18 08:47:19  tittge
   adjust documentation

   Revision 1.2  2004/05/04 15:56:16  wollny
   make viewitgui compile and link

   Revision 1.1  2004/05/04 15:14:55  wollny
   make libviewit compile

   Revision 1.4  2004/04/05 15:24:33  gerddie
   change filter allocation

   Revision 1.3  2002/07/15 07:15:16  gerddie
   make it compile with g++ 3.1

   Revision 1.2  2002/06/20 09:59:48  gerddie
   added cvs-log entry


*/

