/**********************************************************************
* 
* cellChr.cpp
*
* This file is part of MitoGen
* 
* Copyright (C) 2013-2016 -- Centre for Biomedical Image Analysis (CBIA)
* http://cbia.fi.muni.cz/
* 
* MitoGen 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.
* 
* MitoGen 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 MitoGen. If not, see <http://www.gnu.org/licenses/>.
* 
* Author: David Svoboda and Vladimir Ulman
* 
* Description: 
* This file contains implementation of Cell::Chr* methods which handle the
* the chromatin structure inside the cell nucleus.
*
***********************************************************************/

#ifdef GTGEN_DEBUG
  #include <sys/time.h>
#endif

/**
 * If enabled, creates files, e.g., ID03_T011_chrDotList.dat that store
 * Cell::chrCount groups each consisting of 10 subgroups. The outer groups
 * represent all dots/molecules associated to every chromosome in the cell,
 * the dots are sorted according to the distance to the chromocentre. The
 * inner groups then split the listing in every 10th, 20th, ... percentile.
 *
 * This can be visualized with gnuplot:
 * plot [0:3] for [c=0:45] for [p=0:9] "ID02_T004_chrDotList.dat" i p+c*10 u 1:(c) notitle lc p
 */
//#define REPORT_CHRDOT_DISTRIBUTIONS_IN_ChrUpdateStats


#ifdef REPORT_CHRDOT_DISTRIBUTIONS_IN_ChrUpdateStats
	#include <fstream>
#endif

#include <sstream>
#ifndef __APPLE__
	#include <values.h>		//defines FLT_MAX and FLT_MIN on Linux
#else
	#include <float.h>		//defines FLT_MAX and FLT_MIN on Apple
#endif
#include <time.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

#include <i3d/DistanceTransform.h>
#include <i3d/morphology.h>
#include <i3d/neighbours.h>

#include "cell.h"
#include "toolbox/flowfields.h"
#include "toolbox/bp_lists.h"
#include "toolbox/rnd_generators.h"


//------------------------------------------------------------------
#define SQR(x) ((x)*(x))
//-----------------------------------------------------------------------------
// statistics stuff
//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrUpdateStats(const float percentil)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) 
	{
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if ((percentil < 0.f) || (percentil > 1.f))
		throw ERROR_REPORT("The percentil parameter is out of the interval [0,1].");

	// During Anaphase and Cytokinesis the number of chromosomes 
	// is changing, i.e. avoid testing consistency during Anaphase
	if ((currentPhase == Anaphase) || (currentPhase == Cytokinesis))
	{
		 chrCentres.resize(chrCount);
		 chrSpreads.resize(chrCount);
		 chrDensities.resize(chrCount);
	}
	else
	{ 
		if (chrCount != chrCentres.size()) 
		{
			std::ostringstream err;
			err << "Cell ID=" << ID << " has bad number (" << chrCentres.size()
				 << ") of chrCentres items, should be " << chrCount;
			throw ERROR_REPORT(err.str());
		} 
		 
		if (chrCount != chrSpreads.size())
		{
			std::ostringstream err;
			err << "Cell ID=" << ID << " has bad number (" << chrSpreads.size()
				 << ") of chrSpreads items, should be " << chrCount;
			throw ERROR_REPORT(err.str());
		}

		if (chrCount != chrDensities.size())
		{
			std::ostringstream err;
			err << "Cell ID=" << ID << " has bad number (" << chrDensities.size()
				 << ") of chrDensities items, should be " << chrCount;
			throw ERROR_REPORT(err.str());
		}
	}

	//now the lengths are OK, let's make use of it
#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif

	//iterators, for computations of geometric centre
	std::vector<Molecule>::const_iterator dIter=chrDotList.begin();
	std::vector<Dot>::iterator cIter=chrCentres.begin();

	while (dIter != chrDotList.end())
	{
		//chromosome geometric centre
		double X=0.; double Y=0.; double Z=0.;

		//until entire sub-sequence is read
		for (size_t i=0; i < chrDots; ++i, ++dIter)
		{
			//update centre...
			X+=dIter->pos.x;
			Y+=dIter->pos.y;
			Z+=dIter->pos.z;
		}

		//compute the centre of mass and save it into the "stats" variable
		cIter->pos.x=X/(double)chrDots;
		cIter->pos.y=Y/(double)chrDots;
		cIter->pos.z=Z/(double)chrDots;

		++cIter;
	}

	//iterators again, this time for computations of spread
	dIter=chrDotList.begin();
	cIter=chrCentres.begin();
	std::vector<float>::iterator sIter=chrSpreads.begin();

	//we need to store the distances aside so that we can re-order
	//there and obtain the given percentil; we will work with squared
	//values as the square function is monotonic
	std::vector<float> distances;
	distances.resize(chrDots);

#ifdef REPORT_CHRDOT_DISTRIBUTIONS_IN_ChrUpdateStats
	char fn[50];
	sprintf(fn, "ID%.2u_T%.3lu_chrDotList.dat", this->ID, this->timePoint);
	std::ofstream dotlist(fn);
#endif

	while (dIter != chrDotList.end())
	{
		//iterator for storing the distances aside
		*sIter=0;
		std::vector<float>::iterator distIter=distances.begin();

		//until entire sub-sequence is read
		for (size_t i=0; i < chrDots; ++i, ++dIter, ++distIter)
		{
			//the current distance
			float dx=cIter->pos.x - dIter->pos.x;
			float dy=cIter->pos.y - dIter->pos.y;
			float dz=cIter->pos.z - dIter->pos.z;
			dx=dx*dx + dy*dy + dz*dz;

			//store it aside
			*distIter=dx;
		}

		//now, sort the distances
		std::sort(distances.begin(), distances.end());

		//finalize saving of the "stats" variable
		*sIter=sqrtf(distances[ (int)floorf(percentil * (float)chrDots) ]);

#ifdef REPORT_CHRDOT_DISTRIBUTIONS_IN_ChrUpdateStats
		dotlist << "######### next chromosome #########\n";
		distIter=distances.begin();
		for (int qq=0; qq < 10; ++qq) {
			for (unsigned int ww=0; ww < chrDots/10; ++ww) {
				dotlist << sqrtf(*distIter) << std::endl;
				++distIter;
			}
			dotlist << std::endl << std::endl;
		}
#endif
		++cIter; ++sIter;
	}

#ifdef REPORT_CHRDOT_DISTRIBUTIONS_IN_ChrUpdateStats
	dotlist.close();
#endif

	//last but not least, the chrDensities should get updated as well,
	//we're gonna reuse the existing iterators...

	//first, reset the density stats
	sIter = chrDensities.begin();
	while (sIter != chrDensities.end()) { *sIter=0.f; ++sIter; }

	//iterate throught all molecules/dots (a longer list of the two)
	for (dIter=chrDotList.begin(); dIter != chrDotList.end(); ++dIter)
		//now, iterate throught all chrCentres (a shorter list of the two)
		for (cIter=chrCentres.begin(), sIter=chrDensities.begin();
				cIter != chrCentres.end(); ++cIter, ++sIter)
			//if closer than 0.2 microns then count it
			if (i3d::Norm2(cIter->pos - dIter->pos) < 0.04f) ++(*sIter);

#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("operation took " << T2-T1 << " seconds, percentil is " << percentil);
#endif
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrGetCentreOfMass(i3d::Vector3d<float>& centre)
{
	//for sweeping
	std::vector<Molecule>::const_iterator chrIter=chrDotList.begin();

	//for accumulating
	double x=0., y=0., z=0.;

	while (chrIter != chrDotList.end())
	{
		x+=(double)chrIter->pos.x;
		y+=(double)chrIter->pos.y;
		z+=(double)chrIter->pos.z;
		++chrIter;
	}

	//divide in double precision and convert to float afterwards
	centre.x=(float)(x / (double)chrDotList.size());
	centre.y=(float)(y / (double)chrDotList.size());
	centre.z=(float)(z / (double)chrDotList.size());
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrGetCentreOfLowDensity(i3d::Vector3d<float>& centre)
{
	//consistency test
	if (chrCentres.size() != chrDensities.size())
	{
		std::ostringstream err;
		err << "Cell ID=" << ID << " has mismatch in numbers of chrCentres ("
			 << chrCentres.size() << ") and chrDensities (" << chrDensities.size()
			 << ")";
		throw ERROR_REPORT(err.str());
	}

	//for sweeping
	std::vector<Dot>::const_iterator cIter=chrCentres.begin();
	std::vector<float>::const_iterator dIter=chrDensities.begin();

	//for accumulating
	double x=0., y=0., z=0.;
	double dens=0.;

	while (cIter != chrCentres.end())
	{
		x+=(double)cIter->pos.x / (double)*dIter;
		y+=(double)cIter->pos.y / (double)*dIter;
		z+=(double)cIter->pos.z / (double)*dIter;
		dens+=1. / (double)*dIter;
		++cIter; ++dIter;
	}

	//divide in double precision and convert to float afterwards
	centre.x=(float)(x / dens);
	centre.y=(float)(y / dens);
	centre.z=(float)(z / dens);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrReportStats(void)
{
	/*
	for (size_t i=0; i < chrCentres.size(); ++i)
	{
		DEBUG_REPORT("chromosome " << i << " has centre coordinate "
			<< chrCentres[i].pos << " um, spread of "
			<< chrSpreads[i] << " um, and density " << chrDensities[i]);
	}
	*/
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrReportClosests(void)
{
	/*
	for (size_t i=0; i < chrCentres.size(); ++i)
	{
		float closests_dist=100;
		size_t closests_ID=99999;

		for (size_t j=0; j < chrCentres.size(); ++j)
		{
			const float dist=i3d::Norm2(chrCentres[i].pos - chrCentres[j].pos);
			if ((i != j) && (dist < closests_dist))
			{
				closests_dist=dist;
				closests_ID=j;
			}
		}

		DEBUG_REPORT("chromosome " << i << " has closest chromosome "
			<< closests_ID << " at distance " << closests_dist << " um");
	}
	*/
}


//-----------------------------------------------------------------------------
// chromatin mass moving functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// This function takes the mask of cell/nucleus as a domain where the voxels can
// be placed into. The position outside this domain are forbidden. Hence any voxel
// with forbidden position is to be projected into the mask. This projection is 
// performed as an nearest distance algorithm. For this purpose, the distance map is 
// required. If it does not exist, it is newly generated. As soon as the DM is available
// the iterative search for the nearest mask voxel is started.
//-----------------------------------------------------------------------------
template <class VOXEL>
i3d::Vector3d<float> FindNearestMaskVoxel(const i3d::Vector3d<float> v,
														const i3d::Image3d<VOXEL> &mask,
														const VOXEL value,
														i3d::Image3d<float>* &DM)
{
	 // If distance transform is not available, do it on your own
	 // (on demand). The currently created distance map is not destroyed
	 // when leaving this function as it can be used later by another 
	 // call of function 'FindNearestMaskVoxel'.
	 if (DM == NULL)
	 {
		  DM = new i3d::Image3d<float>();
		  DM->CopyMetaData(mask);
#ifdef GTGEN_DEBUG
		  float DMsum=0.f;
#endif
		  for (size_t i=0; i<mask.GetImageSize(); i++) 
		  {
				if (mask.GetVoxel(i) == value)
					 DM->SetVoxel(i, 1.0f); 
				else
					 DM->SetVoxel(i, 0.0f);
#ifdef GTGEN_DEBUG
		  		DMsum+=DM->GetVoxel(i);
#endif
		  } 
#ifdef GTGEN_DEBUG
		  REPORT("Regenerating distance map, it contains " << DMsum << " pixels");
#endif
		  //DM->SaveImage("DT_from_mask_before.ics"); //TODO VLADO REMOVE
		  //mask.SaveImage("DT_mask_for_new_DT.ics");
	
		  i3d::EDM(*DM, 0, 0.0f, false);
		  DEBUG_REPORT("Regeneration finished.");

		  //DM->SaveImage("DT_from_mask_after.ics"); //TODO VLADO REMOVE

		  remapped.clear();
	 }

	 i3d::Vector3d<float> res = mask.GetResolution().GetRes();
	 i3d::Vector3d<float> off = mask.GetOffset();
	 i3d::Vector3d<size_t> pos;

	 pos.x = (size_t) roundf((v.x - off.x) * res.x);
	 pos.y = (size_t) roundf((v.y - off.y) * res.y);
	 pos.z = (size_t) roundf((v.z - off.z) * res.z);

	 // if already computed before, fetch from the associative map
	 size_t index = mask.GetIndex(pos);

	 if (remapped.find(index) != remapped.end())
	 {
		  i3d::Vector3d<size_t> npos = mask.GetPos(remapped[index]);
		  i3d::Vector3d<float> posInMask = 
					 i3d::PixelsToMicrons(npos, res) + mask.GetOffset(); 

		  return posInMask;
	 }

	 // use either global or local distance map
	 std::vector<const float*> win;

	 //emergency break counter
	 size_t counter = 0;

	 do {
		  // collect neighbouring voxels of the current voxel
		  i3d::GetWindow(*DM, pos.x, pos.y, pos.z, i3d::nb3D_6, win);

		  // find the voxel with the lowest intensity 
		  float min_value = FLT_MAX;
		  size_t min_index = 0;
		  for (size_t j=0; j<win.size(); j++)
		  {
				float cur_value = *win[j];
				
	//			printf("(%f)",cur_value);

				if (min_value > cur_value)
				{
					 min_value = cur_value;
					 min_index = j;
				}
		  }

		  
	 //	  printf("[%lu,%lu,%lu] \n",pos.x, pos.y, pos.z);

		  if (min_value >= 80.0f) // in microns
		  {
				DEBUG_REPORT("would have thrown an error, min_value="
				<< min_value << " for input point " << v << ", render to " << pos);
				DM->SaveImage("DT_when_error.ics");
				//throw ERROR_REPORT("too big distance");
		  }
		  

		  // move to the voxel with the lowest intensity and
		  // repeat the process until you find the voxel with zero intensity, i.e.
		  // the mask voxel
		  size_t index = win[min_index] - DM->GetFirstVoxelAddr();
		  pos.x = DM->GetX(index);
		  pos.y = DM->GetY(index);
		  pos.z = DM->GetZ(index);

		  counter++;

	 } while ((DM->GetVoxel(pos) > 0.0f) && (counter < 100));

	 //DEBUG_REPORT("projection completed in " << counter << " step(s).");

	 if (counter < 100) {
		// store into associative map in case the emergency break has not been used
	 	remapped[index] = mask.GetIndex(pos);
		return ( i3d::PixelsToMicrons(pos, res) + DM->GetOffset() );
	 } else {
	 	// if in trouble, do not change the dot position
		REPORT("Couldn't find nearest mask position for the dot at position " << v << " (in microns)");
		return (v);
	 }
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveByVector()
 * and Cell::ChrMoveByVectorBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveByVector( std::vector<Molecule> &chrDotList, 
								const size_t from,
								const size_t to,
								i3d::Vector3d<float> const &shift,
								i3d::Image3d<MV> const &mask, 
								i3d::Image3d<float>* &dmOfBackground,
								const MV value)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	//sweep over given portion of the chrDotList
	for (size_t i=from; i < to; ++i) {
		//a working copy of the new coordinate
		i3d::Vector3d<float> D(chrDotList[i].pos+shift);

		//nearest neighbor mask image pixel coordinate
		const int x=(int)roundf( (D.x-xOff) *xRes );
		const int y=(int)roundf( (D.y-yOff) *yRes );
		const int z=(int)roundf( (D.z-zOff) *zRes );

		//move the point to its new position
		if (mask.Include(x,y,z))
		{
			 if (mask.GetVoxel(x,y,z) == value) // is within the mask
				  chrDotList[i].pos = D;
			 else // escaped from the mask
				  chrDotList[i].pos = FindNearestMaskVoxel(D, mask, value, dmOfBackground);
		}
		else
		{
//			 throw ERROR_REPORT("The movement of dots is too fast.");
		}
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByVector(const size_t chrID,
											  i3d::Vector3d<float> const &shift,
											  i3d::Image3d<MV> const &mask,
											  i3d::Image3d<float>* &dmOfBackground,
											  const MV value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveByVector(chrDotList,
							chrDots * chrID,
							chrDots * (chrID+1), 
							shift,
							mask,
							dmOfBackground,
							value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByVectorBM(const size_t chrID,
												 i3d::Vector3d<float> const &shift,
												 i3d::Image3d<bool> const &mask,
												 i3d::Image3d<float>* &dmOfBackground,
												 const bool value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveByVector(chrDotList,
							chrDots * chrID,
							chrDots * (chrID+1), 
							shift,
							mask,
							dmOfBackground,
							value);
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveWithBrown()
 * and Cell::ChrMoveWithBrownBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveWithBrown(std::vector<Molecule> &chrDotList, 
								const size_t from,
								const size_t to,
								const i3d::Vector3d<float> step,
								i3d::Image3d<MV> const &mask, 
								i3d::Image3d<float>* &dmOfBackground,
								const MV value)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	//sweep over given portion of the chrDotList
	for (size_t i=from; i < to; ++i) {
		//a working copy of the new coordinate
		//const i3d::Vector3d<float> &D=chrDotList[i].pos;
		const i3d::Vector3d<float> D(chrDotList[i].pos);

		//up to 3x times Brownian motion while we are not in the mask
		i3d::Vector3d<float> V; //testing vector
		char tries=0;		//number of tries
		int x,y,z;		//new pixel position
		do {
			SuggestBrownianVector(V, step);
			++tries;

			//nearest neighbor mask image pixel coordinate
			x=(int)roundf( (D.x+V.x-xOff) *xRes );
			y=(int)roundf( (D.y+V.y-yOff) *yRes );
			z=(int)roundf( (D.z+V.z-zOff) *zRes );
			//REPORT(D << " (tries " << (int)tries << "): + " << V << " = (" << x << "," << y << "," << z << ")");
		} while ( ((!mask.Include(x,y,z)) || (mask.GetVoxel(x,y,z) != value))
			&& (tries < 3) );

		//move the point to its new position
		if (tries < 3) 
			 chrDotList[i].pos=D+V;
		else if (mask.Include(x,y,z) && (mask.GetVoxel(x,y,z) != value))
			 chrDotList[i].pos = FindNearestMaskVoxel(D+V, mask, value, dmOfBackground);
		// else do no motion
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithBrown(const size_t chrID,
												const i3d::Vector3d<float> step,
												i3d::Image3d<MV> const &mask,
												i3d::Image3d<float>* &dmOfBackground,
												const MV value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveWithBrown(chrDotList,
							 chrDots * chrID,
							 chrDots * (chrID+1), 
							 step,
							 mask,
							 dmOfBackground,
							 value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithBrownBM(const size_t chrID,
												  const i3d::Vector3d<float> step,
												  i3d::Image3d<bool> const &mask,
												  i3d::Image3d<float>* &dmOfBackground,
												  const bool value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveWithBrown(chrDotList,
							 chrDots * chrID,
							 chrDots * (chrID+1), 
							 step,
							 mask,
							 dmOfBackground,
							 value);
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveWithGravity()
 * and Cell::ChrMoveWithGravityBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveWithGravity(std::vector<Molecule> &chrDotList, 
								  const size_t from,
								  const size_t to,
								  const float step,
								  i3d::Image3d<MV> const &mask, 
								  i3d::Image3d<float>* &dmOfBackground,
								  const MV value,
								  const Dot& chrCentre)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	//sweep over given portion of the chrDotList
	for (size_t i=from; i < to; ++i) 
	{
		//a temporary copy of the new coordinate
		const i3d::Vector3d<float> D(chrDotList[i].pos);

/*
 * ----
 * This part of code if commented as we found out that we do not need to
 * compute the local neighbourhood of each molecule precisely. 
 * The global neighbourhood (without local weights) is also a good 
 * and sufficiently precie approximation. In detail, the difference between
 * the precisely compute angles and the approximate ones is 
 * at most 5 degrees.
 * 
 * The complexity of local nbh method: O(n^2)
 * The complexity of global nbh method:  O(n)
 * ----
 *
		//gravity vector
		i3d::Vector3d<float> V(0.f,0.f,0.f);

		//TODO VLADO: TRY IF IT CAN BE FASTER WITH ITERATORS...

		//sweep again over the given portion of the chrDotList
		for (size_t j=from; j < to; ++j) {
			//move over the same dot
			if (i == j) continue;

			//vector from the evaluated one towards the other
			const float dx=chrDotList[j].pos.x - D.x;
			const float dy=chrDotList[j].pos.y - D.y;
			const float dz=chrDotList[j].pos.z - D.z;
		
			//size of this vector (distance between the dots, in fact) and its square
			const float s2=dx*dx + dy*dy + dz*dz; 
			//const float s=sqrtf(s2+0.0001); //to prevent from sqrtf(0)

			
			//the "Gravity" vector is: step * (dx,dy,dz)/s * 1/s2
			//           [step times normalized direction] * [inverse proportional square of distance]
			// float W=(s2 > 0)?  step / (s * s2) : 0.f;
			//
			//if dots are too close, the W would catapult them against each other
			// if (W > 1.f) W=1.f;
			//
			//ALTERNATIVE:
			//the "Gravity" vector is: step * (dx,dy,dz)/s * s/(1+s2)
			//           [step times normalized direction] * [some harmonic 1/x2-like function]
			float W=step / (1+s2);

			//movement due to mutual gravity between the dots "i" and "j"
			V += i3d::Vector3d<float>(W*dx,W*dy,W*dz);
		}*/

		// find the vector heading to the centre
		i3d::Vector3d<float> V = step*(chrCentre.pos - D);

		//nearest neighbor mask image pixel coordinate
		const int x=(int)roundf( (D.x+V.x-xOff) * xRes );
		const int y=(int)roundf( (D.y+V.y-yOff) * yRes );
		const int z=(int)roundf( (D.z+V.z-zOff) * zRes );

		//move the point, if its new position is still within the mask
		if (mask.Include(x,y,z))
		{
			 if (mask.GetVoxel(x,y,z) == value) // is within mask
				  chrDotList[i].pos = D+V;
			 else // escaped from the mask -> correct
			 {
				  chrDotList[i].pos = 
							 FindNearestMaskVoxel(D+V, mask, value, dmOfBackground);
			 }
		}
		else
		{
			// throw ERROR_REPORT("The movement of dots is too fast.");
		}
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithGravity(const size_t chrID,
												  const float step,
												  i3d::Image3d<MV> const &mask,
												  i3d::Image3d<float>* &dmOfBackground,
												  const MV value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList;
	//in order to keep the strength of the 'step' constant rather the same,
	//it must be reduced by the number of dots as they all contribute additively
	__ChrMoveWithGravity(chrDotList,
								chrDots * chrID,
								chrDots * (chrID+1), 
								step,
								mask,
								dmOfBackground,
								value,
								chrCentres[chrID]);

}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithGravityBM(const size_t chrID,
													 const float step,
													 i3d::Image3d<bool> const &mask,
													 i3d::Image3d<float>* &dmOfBackground,
													 const bool value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	//in order to keep the strength of the 'step' constant rather the same,
	//it must be reduced by the number of dots as they all contribute additively
	__ChrMoveWithGravity(chrDotList,
								chrDots * chrID,
								chrDots * (chrID+1), 
								step,
								mask,
								dmOfBackground,
								value,
								chrCentres[chrID]);
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveByFlow()
 * and Cell::ChrMoveByFlowBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveByFlow(std::vector<Molecule> &chrDotList,
							const size_t from,
							const size_t to,
							FlowField<float> const &FF,
							i3d::Image3d<MV> const &mask, 
							i3d::Image3d<float>* &dmOfBackground,
							const MV value)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	//move dot by dot...
	for (size_t i=from; i < to; ++i) 
	{
		const float X=chrDotList[i].pos.x;
		const float Y=chrDotList[i].pos.y;
		const float Z=chrDotList[i].pos.z;

		//the position in pixels of the flow field
		const float Xp=(X -xOffFF) *xResFF;
		const float Yp=(Y -yOffFF) *yResFF;
		const float Zp=(Z -zOffFF) *zResFF;

		//new molecule position after moving along the flow field
		//note: GetPixel() returns 0 in case we ask for value outside the image molecule position
		//(both the position and vectors in the flow field are in microns)
		const float nX=X + GetPixel(*FF.x, Xp,Yp,Zp);
		const float nY=Y + GetPixel(*FF.y, Xp,Yp,Zp);
		const float nZ=Z + GetPixel(*FF.z, Xp,Yp,Zp);

		//new position in the pixels of the mask image, using nearest neighbor
		const int nXp=(int)roundf( (nX-xOff) *xRes );
		const int nYp=(int)roundf( (nY-yOff) *yRes );
		const int nZp=(int)roundf( (nZ-zOff) *zRes );

		if (mask.Include(nXp,nYp,nZp))
		{
			 if (mask.GetVoxel(nXp,nYp,nZp)==value) 
			 {
				  //new position fits into the image and even into this cell mask,
				  // update the dot then (with the real unrounded position)
				  chrDotList[i].pos.x=nX;
				  chrDotList[i].pos.y=nY;
				  chrDotList[i].pos.z=nZ;
			 }
			 else
			 {
				  chrDotList[i].pos = 
							 FindNearestMaskVoxel(i3d::Vector3d<float>(nX, nY, nZ),
														 mask,
														 value,
														 dmOfBackground);
			 }
		}
		else
		{
			 // throw ERROR_REPORT("The movement of dots is too fast.");
		}
	}
}

//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveByFlow()
 * and Cell::ChrMoveByFlowBM() are supposed to do. The goal is not to duplicate
 * the same code.
 */
template <class MV>
void __ChrMoveByFlow(std::vector<Molecule> &chrDotList,
							FlowField<float> const &FF,
							i3d::Image3d<MV> const &mask, 
							i3d::Image3d<float>* &dmOfBackground,
							const MV value)
{
	 __ChrMoveByFlow(chrDotList,
						  0, chrDotList.size(),
						  FF, mask, dmOfBackground, value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByFlow(FlowField<float> const &FF,
											i3d::Image3d<MV> const &mask,
											i3d::Image3d<float>* &dmOfBackground,
											const MV value)
{
	//sanitary checks...
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//process the whole chrDotList
	__ChrMoveByFlow(chrDotList, FF,mask,dmOfBackground,value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByFlow(const size_t chrID,
											FlowField<float> const &FF,
											i3d::Image3d<MV> const &mask,
											i3d::Image3d<float>* &dmOfBackground,
											const MV value)
{
	//sanitary checks...
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//process the whole chrDotList
	__ChrMoveByFlow(chrDotList, 
						 chrDots * chrID,
						 chrDots * (chrID+1),
						 FF,
						 mask,
						 dmOfBackground,
						 value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByFlowBM(FlowField<float> const &FF,
											  i3d::Image3d<bool> const &mask,
											  i3d::Image3d<float>* &dmOfBackground,
											  const bool value)
{
	//sanitary checks...
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//process the whole chrDotList
	__ChrMoveByFlow(chrDotList, FF,mask,dmOfBackground, value);
}


//-----------------------------------------------------------------------------
// centrosomes moving functions
//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrCentrosomesMoveByFlow(FlowField<float> const &FF,
					  i3d::Image3d<MV> const &mask, 
					  i3d::Image3d<float>* &dmOfBackground,
					  const MV value, const bool doCorrection)
{
	if ((!this->centrosomeA) && (!this->centrosomeB))
	{
		DEBUG_REPORT("No centrosomes to update...");
		return;
	}

	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	if (this->centrosomeA)
	{
		const float X=centrosomeA->pos.x;
		const float Y=centrosomeA->pos.y;
		const float Z=centrosomeA->pos.z;

		//the position in pixels of the flow field
		const float Xp=(X -xOffFF) *xResFF;
		const float Yp=(Y -yOffFF) *yResFF;
		const float Zp=(Z -zOffFF) *zResFF;

		//new molecule position after moving along the flow field
		//note: GetPixel() returns 0 in case we ask for value outside the image molecule position
		//(both the position and vectors in the flow field are in microns)
		const float nX=X + GetPixel(*FF.x, Xp,Yp,Zp);
		const float nY=Y + GetPixel(*FF.y, Xp,Yp,Zp);
		const float nZ=Z + GetPixel(*FF.z, Xp,Yp,Zp);

		//new position in the pixels of the mask image, using nearest neighbor
		const int nXp=(int)roundf( (nX-xOff) *xRes );
		const int nYp=(int)roundf( (nY-yOff) *yRes );
		const int nZp=(int)roundf( (nZ-zOff) *zRes );

		if (mask.Include(nXp,nYp,nZp))
		{
			 if (mask.GetVoxel(nXp,nYp,nZp)>=value) 
			 {
				  //new position fits into the image and even into this cell mask,
				  // update the centrosome then (with the real unrounded position)
				  centrosomeA->pos.x=nX;
				  centrosomeA->pos.y=nY;
				  centrosomeA->pos.z=nZ;
			 }
			 else
			 {
			 	if (doCorrection)
				{
				  centrosomeA->pos = 
							 FindNearestMaskVoxel(i3d::Vector3d<float>(nX, nY, nZ),
														 mask,
														 value,
														 dmOfBackground);
				}
				REPORT("Warning: CentrosomeA was outside the mask!?");
			 }
		}
		else
		{
			 throw ERROR_REPORT("CentrosomeA outside the mask image (-> totally outside the mask)!");
		}
	}

	if (this->centrosomeB)
	{
		const float X=centrosomeB->pos.x;
		const float Y=centrosomeB->pos.y;
		const float Z=centrosomeB->pos.z;

		//the position in pixels of the flow field
		const float Xp=(X -xOffFF) *xResFF;
		const float Yp=(Y -yOffFF) *yResFF;
		const float Zp=(Z -zOffFF) *zResFF;

		//new molecule position after moving along the flow field
		//note: GetPixel() returns 0 in case we ask for value outside the image molecule position
		//(both the position and vectors in the flow field are in microns)
		const float nX=X + GetPixel(*FF.x, Xp,Yp,Zp);
		const float nY=Y + GetPixel(*FF.y, Xp,Yp,Zp);
		const float nZ=Z + GetPixel(*FF.z, Xp,Yp,Zp);

		//new position in the pixels of the mask image, using nearest neighbor
		const int nXp=(int)roundf( (nX-xOff) *xRes );
		const int nYp=(int)roundf( (nY-yOff) *yRes );
		const int nZp=(int)roundf( (nZ-zOff) *zRes );

		if (mask.Include(nXp,nYp,nZp))
		{
			 if (mask.GetVoxel(nXp,nYp,nZp)>=value) 
			 {
				  //new position fits into the image and even into this cell mask,
				  // update the centrosome then (with the real unrounded position)
				  centrosomeB->pos.x=nX;
				  centrosomeB->pos.y=nY;
				  centrosomeB->pos.z=nZ;
			 }
			 else
			 {
			 	if (doCorrection)
				{
				  centrosomeB->pos = 
							 FindNearestMaskVoxel(i3d::Vector3d<float>(nX, nY, nZ),
														 mask,
														 value,
														 dmOfBackground);
				}
				REPORT("Warning: CentrosomeB was outside the mask!?");
			 }
		}
		else
		{
			 throw ERROR_REPORT("CentrosomeB outside the mask image (-> totally outside the mask)!");
		}
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrCentrosomesMoveByFlowBM(FlowField<float> const &FF,
						 i3d::Image3d<bool> const &mask, 
						 i3d::Image3d<float>* &dmOfBackground,
						 const bool value, const bool doCorrection)
{
	if ((!this->centrosomeA) && (!this->centrosomeB))
	{
		DEBUG_REPORT("No centrosomes to update...");
		return;
	}

	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	if (this->centrosomeA)
	{
		const float X=centrosomeA->pos.x;
		const float Y=centrosomeA->pos.y;
		const float Z=centrosomeA->pos.z;

		//the position in pixels of the flow field
		const float Xp=(X -xOffFF) *xResFF;
		const float Yp=(Y -yOffFF) *yResFF;
		const float Zp=(Z -zOffFF) *zResFF;

		//new molecule position after moving along the flow field
		//note: GetPixel() returns 0 in case we ask for value outside the image molecule position
		//(both the position and vectors in the flow field are in microns)
		const float nX=X + GetPixel(*FF.x, Xp,Yp,Zp);
		const float nY=Y + GetPixel(*FF.y, Xp,Yp,Zp);
		const float nZ=Z + GetPixel(*FF.z, Xp,Yp,Zp);

		//new position in the pixels of the mask image, using nearest neighbor
		const int nXp=(int)roundf( (nX-xOff) *xRes );
		const int nYp=(int)roundf( (nY-yOff) *yRes );
		const int nZp=(int)roundf( (nZ-zOff) *zRes );

		if (mask.Include(nXp,nYp,nZp))
		{
			 if (mask.GetVoxel(nXp,nYp,nZp)==value) 
			 {
				  //new position fits into the image and even into this cell mask,
				  // update the centrosome then (with the real unrounded position)
				  centrosomeA->pos.x=nX;
				  centrosomeA->pos.y=nY;
				  centrosomeA->pos.z=nZ;
			 }
			 else
			 {
			 	if (doCorrection)
				{
				  centrosomeA->pos = 
							 FindNearestMaskVoxel(i3d::Vector3d<float>(nX, nY, nZ),
														 mask,
														 value,
														 dmOfBackground);
				}
				REPORT("Warning: CentrosomeA was outside the mask!?");
			 }
		}
		else
		{
			 throw ERROR_REPORT("CentrosomeA outside the mask image (-> totally outside the mask)!");
		}
	}

	if (this->centrosomeB)
	{
		const float X=centrosomeB->pos.x;
		const float Y=centrosomeB->pos.y;
		const float Z=centrosomeB->pos.z;

		//the position in pixels of the flow field
		const float Xp=(X -xOffFF) *xResFF;
		const float Yp=(Y -yOffFF) *yResFF;
		const float Zp=(Z -zOffFF) *zResFF;

		//new molecule position after moving along the flow field
		//note: GetPixel() returns 0 in case we ask for value outside the image molecule position
		//(both the position and vectors in the flow field are in microns)
		const float nX=X + GetPixel(*FF.x, Xp,Yp,Zp);
		const float nY=Y + GetPixel(*FF.y, Xp,Yp,Zp);
		const float nZ=Z + GetPixel(*FF.z, Xp,Yp,Zp);

		//new position in the pixels of the mask image, using nearest neighbor
		const int nXp=(int)roundf( (nX-xOff) *xRes );
		const int nYp=(int)roundf( (nY-yOff) *yRes );
		const int nZp=(int)roundf( (nZ-zOff) *zRes );

		if (mask.Include(nXp,nYp,nZp))
		{
			 if (mask.GetVoxel(nXp,nYp,nZp)==value) 
			 {
				  //new position fits into the image and even into this cell mask,
				  // update the centrosome then (with the real unrounded position)
				  centrosomeB->pos.x=nX;
				  centrosomeB->pos.y=nY;
				  centrosomeB->pos.z=nZ;
			 }
			 else
			 {
			 	if (doCorrection)
				{
				  centrosomeB->pos = 
							 FindNearestMaskVoxel(i3d::Vector3d<float>(nX, nY, nZ),
														 mask,
														 value,
														 dmOfBackground);
				}
				REPORT("Warning: CentrosomeB was outside the mask!?");
			 }
		}
		else
		{
			 throw ERROR_REPORT("CentrosomeB outside the mask image (-> totally outside the mask)!");
		}
	}
}


//-----------------------------------------------------------------------------
// rendering functions
//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoPhantoms(i3d::Image3d<PV> &phantoms,
													  FlowField<float> const &FF)
{
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID="
		     << ID << " (WITH FLOW FIELD)");

	//flow field related time savers:
	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	//phantom image related time savers:
	const float xRes=phantoms.GetResolution().GetX();
	const float yRes=phantoms.GetResolution().GetY();
	const float zRes=phantoms.GetResolution().GetZ();
	const float xOff=phantoms.GetOffset().x;
	const float yOff=phantoms.GetOffset().y;
	const float zOff=phantoms.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif

	// For the purpose of photobleaching we need to compute the exponential decay
	// for each individual fluorophore molecule. Therefore, we need a image buffer
	// with floating point datatype. After collecting all the pieces of information 
	// together, we will convert this floating point data into grayscale
	i3d::Image3d<float> floatVoxels;
	floatVoxels.CopyMetaData(phantoms);
	floatVoxels.GetVoxelData() = 0.0f;

#ifdef GTGEN_WITH_PHOTOBLEACHING
	// a variable for debugging the photobleaching
	float meanIntensityCounter = 0.0f;
#endif

	for (size_t i=0; i < chrDotList.size(); ++i) 
	{
		//working copy of the chrDot vector, in microns
		float x=chrDotList[i].pos.x;
		float y=chrDotList[i].pos.y;
		float z=chrDotList[i].pos.z;

		//turn micron position into flow field pixel one
		const float X=(x -xOffFF) *xResFF;
		const float Y=(y -yOffFF) *yResFF;
		const float Z=(z -zOffFF) *zResFF;

		//move the working copy micron position of the chrDot
		//note: GetPixel() returns 0 in case we ask for value outside the image
		x += GetPixel(*FF.x, X,Y,Z);
		y += GetPixel(*FF.y, X,Y,Z);
		z += GetPixel(*FF.z, X,Y,Z);

		//now, turn the micron position back to phantom pixel one
		const int nX=(int)roundf( (x-xOff) *xRes);
		const int nY=(int)roundf( (y-yOff) *yRes);
		const int nZ=(int)roundf( (z-zOff) *zRes);

		if (floatVoxels.Include(nX,nY,nZ)) 
		{
#ifdef GTGEN_WITH_PHOTOBLEACHING
			 // find the bleached value of the current molecule
			 float fvalue = GetBleachFactor(chrDotList[i].birth, this->timePoint+1);
			 meanIntensityCounter += fvalue;
#else
			 float fvalue = 1.0f;
#endif

			 // find the value of all already computer molecules
			 float* faddr = floatVoxels.GetVoxelAddr(nX, nY, nZ);
			 
			 // add the results together
			 *faddr += fvalue;
		} 
		else
		{
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is moved outside the scene");
		}

		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(phantoms,nX,nY,nZ);
		*/
	}

#ifdef GTGEN_WITH_PHOTOBLEACHING
	DEBUG_REPORT(" ID: " << ID << 
					 ", preparing timepoint: " << timePoint+1 <<
					 ", total cell intensity: " << meanIntensityCounter <<
					 ", mean dot intensity: " << meanIntensityCounter/chrDotList.size());
					 //well, the mean is okay only if there were no 'ups' above
#endif


	// copy the currently rendered phantom into image "phantoms"
	for (size_t i=0; i<phantoms.GetImageSize(); i++)
	{
		 float fvalue = floatVoxels.GetVoxel(i);

		 // do not rewrite zero positions as there may reside another cell
		 if (fvalue != 0.0f) 
		 {
			  phantoms.SetVoxel(i, static_cast<PV>(roundf(fvalue)));
		 }
	}

#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("rendering chr points altered by FF took " << T2-T1 << " seconds");
#endif

#ifdef GTGEN_WITH_CHRCENTRESINPHANTHOMS
	//ok, also draw Cell::chrCentres with this "colour"
	const PV centreColour=std::numeric_limits<PV>::max()/2;
	/*
	DEBUG_REPORT("threshold to " << centreColour << " to see the chromo centres");
	DEBUG_REPORT("there are " << chrCentres.size() << " chromo centres (should be "
		<< chrCount << ")");
	*/

	for (size_t i=0; i < chrCentres.size(); ++i) {
		//working copy of the chrDot vector, in microns
		float x=chrCentres[i].pos.x;
		float y=chrCentres[i].pos.y;
		float z=chrCentres[i].pos.z;

		//turn micron position into flow field pixel one
		const float X=(x -xOffFF) *xResFF;
		const float Y=(y -yOffFF) *yResFF;
		const float Z=(z -zOffFF) *zResFF;

		//move the working copy micron position of the chrDot
		//note: GetPixel() returns 0 in case we ask for value outside the image
		x += GetPixel(*FF.x, X,Y,Z);
		y += GetPixel(*FF.y, X,Y,Z);
		z += GetPixel(*FF.z, X,Y,Z);

		//now, turn the micron position back to phantom pixel one
		const int nX=(int)roundf( (x-xOff) *xRes);
		const int nY=(int)roundf( (y-yOff) *yRes);
		const int nZ=(int)roundf( (z-zOff) *zRes);
		/*
		DEBUG_REPORT("chromosome " << i << " has centre coordinate "
			<< "(" << x << "," << y << "," << z << ")"
			<< " um, translated into (" << nX << "," << nY << "," << nZ << ") px");
		*/

		if (phantoms.Include(nX,nY,nZ)) {
			PV *p=phantoms.GetVoxelAddr(nX,nY,nZ);
			*p+=centreColour;
			//note: let it overflow if needed so that
			//subtraction later can restore to the correct value
		}
		else
		{
			DEBUG_REPORT("ups, chromo centre " << chrCentres[i].pos << " is moved outside the scene");
		}
	}
#endif
}

//------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoPhantoms(i3d::Image3d<PV> &phantoms)
{
	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID=" << ID);

	//phantom image related time savers:
	const float xRes=phantoms.GetResolution().GetX();
	const float yRes=phantoms.GetResolution().GetY();
	const float zRes=phantoms.GetResolution().GetZ();
	const float xOff=phantoms.GetOffset().x;
	const float yOff=phantoms.GetOffset().y;
	const float zOff=phantoms.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif

	// For the purpose of photobleaching we need to compute the exponential decay
	// for each individual fluorophore molecule. Therefore, we need a image buffer
	// with floating point datatype. After collecting all the pieces of information 
	// together, we will convert this floating point data into grayscale
	i3d::Image3d<float> floatVoxels;
	floatVoxels.CopyMetaData(phantoms);
	floatVoxels.GetVoxelData() = 0.0f;

#ifdef GTGEN_WITH_PHOTOBLEACHING
	// a variable for debugging the photobleaching
	float meanIntensityCounter = 0.0f;
#endif

	for (size_t i=0; i < chrDotList.size(); ++i) 
	{
		// turn micron position to phantom pixel one
		const int nX=(int)roundf( (chrDotList[i].pos.x-xOff) *xRes);
		const int nY=(int)roundf( (chrDotList[i].pos.y-yOff) *yRes);
		const int nZ=(int)roundf( (chrDotList[i].pos.z-zOff) *zRes);

		if (floatVoxels.Include(nX,nY,nZ)) 
		{
#ifdef GTGEN_WITH_PHOTOBLEACHING
			 // find the bleached value of the current molecule
			 float fvalue = 
						GetBleachFactor(chrDotList[i].birth, this->timePoint+1);

			 meanIntensityCounter += fvalue;
#else
			 float fvalue = 1.0f;
#endif

			 // find the value of all already computer molecules
			 float* faddr = floatVoxels.GetVoxelAddr(nX, nY, nZ);

			 // add the results together
			 *faddr += fvalue;
		} 
		else
		{
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the scene");
		}
	}

#ifdef GTGEN_WITH_PHOTOBLEACHING
	DEBUG_REPORT(" ID: " << ID << 
					 " preparing timepoint: " << timePoint+1 <<
					 " total cell intensity: " << meanIntensityCounter <<
					 " mean dot intensity: " << meanIntensityCounter/chrDotList.size());
					 //well, the mean is okay only if there were no 'ups' above
#endif


	// copy the currently rendered phantom into image "phantoms"
	for (size_t i=0; i<phantoms.GetImageSize(); i++)
	{
		 float fvalue = floatVoxels.GetVoxel(i);

		 // do not rewrite zero positions as there may reside another cell
		 if (fvalue != 0.0f) 
		 {
			  phantoms.SetVoxel(i, static_cast<PV>(roundf(fvalue)));
		 }
	}

#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("direct rendering chr points took " << T2-T1 << " seconds");
#endif

#ifdef GTGEN_WITH_CHRCENTRESINPHANTHOMS
	//ok, also draw Cell::chrCentres with this "colour"
	const PV centreColour=std::numeric_limits<PV>::max()/2;
	/*
	DEBUG_REPORT("threshold to " << centreColour << " to see the chromo centres");
	DEBUG_REPORT("there are " << chrCentres.size() << " chromo centres (should be "
		<< chrCount << ")");
	*/

	for (size_t i=0; i < chrCentres.size(); ++i) {
		//turn micron position to phantom pixel one
		const int nX=(int)roundf( (chrCentres[i].pos.x-xOff) *xRes);
		const int nY=(int)roundf( (chrCentres[i].pos.y-yOff) *yRes);
		const int nZ=(int)roundf( (chrCentres[i].pos.z-zOff) *zRes);
		/*
		DEBUG_REPORT("chromosome " << i << " has centre coordinate " << chrCentres[i].pos
			<< " um, translated into (" << nX << "," << nY << "," << nZ << ") px");
		*/

		if (phantoms.Include(nX,nY,nZ)) {
			PV *p=phantoms.GetVoxelAddr(nX,nY,nZ);
			*p+=centreColour;
			//note: let it overflow if needed so that
			//subtraction later can restore to the correct value
		}
		else
		{
			DEBUG_REPORT("ups, chromo centre " << chrCentres[i].pos << " is outside the scene");
		}
	}
#endif
}

//------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoTerritories(i3d::Image3d<PV> &territories,
														  FlowField<float> const &FF)
{
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID="
		     << ID << " (WITH FLOW FIELD)");

	//flow field related time savers:
	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	//phantom image related time savers:
	const float xRes=territories.GetResolution().GetX();
	const float yRes=territories.GetResolution().GetY();
	const float zRes=territories.GetResolution().GetZ();
	const float xOff=territories.GetOffset().x;
	const float yOff=territories.GetOffset().y;
	const float zOff=territories.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	if (configIni["testing"].present("territories with nucleus boundary"))
	{
		REPORT("TESTING MODE: Drawing nucleus boundary before the territories.");

		for (size_t i=0; i < scmNucleusOuterBPNumber; ++i)
		{
			//working copy of the chrDot vector, in microns
			float x=scmNucleusBPList[i].x;
			float y=scmNucleusBPList[i].y;
			float z=scmNucleusBPList[i].z;

			//turn micron position into flow field pixel one
			const float X=(x -xOffFF) *xResFF;
			const float Y=(y -yOffFF) *yResFF;
			const float Z=(z -zOffFF) *zResFF;

			//move the working copy micron position of the chrDot
			//note: GetPixel() returns 0 in case we ask for value outside the image
			x += GetPixel(*FF.x, X,Y,Z);
			y += GetPixel(*FF.y, X,Y,Z);
			z += GetPixel(*FF.z, X,Y,Z);

			//now, turn the micron position back to phantom pixel one
			const int nX=(int)roundf( (x-xOff) *xRes);
			const int nY=(int)roundf( (y-yOff) *yRes);
			const int nZ=(int)roundf( (z-zOff) *zRes);
			if (territories.Include(nX,nY,nZ))
				territories.SetVoxel(nX,nY,nZ,(PV)1);
		}
	}

	//a common list of chromatin IDs for the two regimes of iterations...
	std::stringstream	chrList;

	//how are we going to iterate over chromatin dots...
	if (!configIni["testing"].present("territories show only these chromatins"))
	{
		//normal listing...
		for (size_t i=0; i < chrCount; ++i) chrList << i << " ";
	}
	else
	{
		std::stringstream	tmpList;
		tmpList << (const char*)configIni["testing"]["territories show only these chromatins"];
		size_t id;
		while (tmpList >> id)
			if ((id >= 0) && (id < chrCount)) chrList << id << " ";
		REPORT("TESTING MODE: Will render only this chromatin: " << chrList.str());
	}

	//read list item (=chromatin ID) one by one and render it
	size_t chrIdx;
	while (chrList >> chrIdx)
	{
	 size_t i=chrIdx*chrDots;
	 for (size_t k=0; k < chrDots; ++k, ++i)
	 {
		//working copy of the chrDot vector, in microns
		float x=chrDotList[i].pos.x;
		float y=chrDotList[i].pos.y;
		float z=chrDotList[i].pos.z;

		//turn micron position into flow field pixel one
		const float X=(x -xOffFF) *xResFF;
		const float Y=(y -yOffFF) *yResFF;
		const float Z=(z -zOffFF) *zResFF;

		//move the working copy micron position of the chrDot
		//note: GetPixel() returns 0 in case we ask for value outside the image
		x += GetPixel(*FF.x, X,Y,Z);
		y += GetPixel(*FF.y, X,Y,Z);
		z += GetPixel(*FF.z, X,Y,Z);

		//now, turn the micron position back to phantom pixel one
		const int nX=(int)roundf( (x-xOff) *xRes);
		const int nY=(int)roundf( (y-yOff) *yRes);
		const int nZ=(int)roundf( (z-zOff) *zRes);

		if (territories.Include(nX,nY,nZ))
			territories.SetVoxel(nX,nY,nZ, (PV)floorf((float)i/(float)chrDots));
		else
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the cell");
		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(territories,nX,nY,nZ);
		*/
	 }
	}
#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("rendering chr points altered by FF took " << T2-T1 << " seconds");
#endif
}

template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoTerritories(i3d::Image3d<PV> &territories)
{
	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID=" << ID);

	//phantom image related time savers:
	const float xRes=territories.GetResolution().GetX();
	const float yRes=territories.GetResolution().GetY();
	const float zRes=territories.GetResolution().GetZ();
	const float xOff=territories.GetOffset().x;
	const float yOff=territories.GetOffset().y;
	const float zOff=territories.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	if (configIni["testing"].present("territories with nucleus boundary"))
	{
		REPORT("TESTING MODE: Drawing nucleus boundary before the territories.");

		for (size_t i=0; i < scmNucleusOuterBPNumber; ++i)
		{
			//turn micron position to phantom pixel one
			const int nX=(int)roundf( (scmNucleusBPList[i].x-xOff) *xRes);
			const int nY=(int)roundf( (scmNucleusBPList[i].y-yOff) *yRes);
			const int nZ=(int)roundf( (scmNucleusBPList[i].z-zOff) *zRes);
			if (territories.Include(nX,nY,nZ))
				territories.SetVoxel(nX,nY,nZ,(PV)1);
		}
	}

	//a common list of chromatin IDs for the two regimes of iterations...
	std::stringstream	chrList;

	//how are we going to iterate over chromatin dots...
	if (!configIni["testing"].present("territories show only these chromatins"))
	{
		//normal listing...
		for (size_t i=0; i < chrCount; ++i) chrList << i << " ";
	}
	else
	{
		std::stringstream	tmpList;
		tmpList << (const char*)configIni["testing"]["territories show only these chromatins"];
		size_t id;
		while (tmpList >> id)
			if ((id >= 0) && (id < chrCount)) chrList << id << " ";
		REPORT("TESTING MODE: Will render only this chromatin: " << chrList.str());
	}

	//read list item (=chromatin ID) one by one and render it
	size_t chrIdx;
	while (chrList >> chrIdx)
	{
	 size_t i=chrIdx*chrDots;
	 for (size_t k=0; k < chrDots; ++k, ++i)
	 {
		//turn micron position to phantom pixel one
		const int nX=(int)roundf( (chrDotList[i].pos.x-xOff) *xRes);
		const int nY=(int)roundf( (chrDotList[i].pos.y-yOff) *yRes);
		const int nZ=(int)roundf( (chrDotList[i].pos.z-zOff) *zRes);

		if (territories.Include(nX,nY,nZ))
			territories.SetVoxel(nX,nY,nZ,(PV)chrIdx);
		else
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the cell");
		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(territories,nX,nY,nZ);
		*/
	 }
	}
#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("direct rendering chr points took " << T2-T1 << " seconds");
#endif
}


//------------------------------------------------------------------
// chromatin mass distribution managing
//------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV,PV>::ChrInitialDistribution(const i3d::Image3d<bool> &mask,
													  const float density)
{
	size_t sizeOfMask=0;	//how many pixels form the mask 

	const bool *m=mask.GetFirstVoxelAddr(); //start address
	bool const *mL=mask.GetFirstVoxelAddr()+mask.GetImageSize(); //stop address

	// counting...
	while (m != mL) 
	{
		sizeOfMask += (*m == true) ? 1 : 0;
		++m;
	}
	DEBUG_REPORT(sizeOfMask << " pixels were found in the mask");

	//how many dots?
	size_t numberOfDots=static_cast<size_t>((float)sizeOfMask * density / 100.0f);

	//this is what is desired, now round it to some multiple of chromosomeCount
	//and to be even, and divisible by four (because of S-phase)
	numberOfDots=ceilf((float)numberOfDots / (float)(4*chrCount)) * (4*chrCount);

	//the number of dots forming one chromosome
	chrDots = numberOfDots/chrCount;
	DEBUG_REPORT("going to use " << chrDots << " molecules for a chromosome, as " << numberOfDots << " is required total");

	//resize the vector in advance to avoid its incremental increasing,
	//which copies the early dots over and over again...
	chrDotList.reserve(numberOfDots);

	// this way we create continuous ascending sequence of unique IDs
	for (size_t i=0; i<numberOfDots; i++)
		 chrDotList.push_back(Molecule());

	//time savers: resolution [px/um]
	const i3d::Vector3d<float> res = mask.GetResolution().GetRes();

	// find chrCount random evenly distributed position 
	// inside the mask of the nucleus
	std::vector<Dot> newPositions;
	GenerateRandomPositions(mask, chrCount, newPositions, true);

	//finally, generate the demanded amount of dots
	for (size_t i=0; i < chrCount; ++i) 
	{ 
		 // store the position of each centrosome
		 chrCentres[i].pos = newPositions[i].pos;

		 // store the initial spread
		 chrSpreads[i]=0.f; 
		 
		 // store all molecules belonging to one chromosome
		 for (size_t j=0; j < chrDots; ++j)
		 {
			  chrDotList[i*chrDots+j].pos = newPositions[i].pos;
		 }

	} //cycle over number of chromosomes
}

//---------------------------------------------------------------------------
//
// !!!Important note !!!
//
// This function should not be called in the phases when there are two
// nuclei inside the cell or if there is no nucleus. The use of this function 
// is intended only in the phases when the chromosome distribution may 
// collapse, i.e. in G1, S, or G2 phase.
//
// The chromatin cannot collapse in other phases as it is either freshly
// reinitialized (Cytokinesis) or fully controlled by mitotic events
// (Prophase, Metaphase, Anaphase, Telophase).
//
//---------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRepairDistribution(const i3d::Image3d<MV> &maskNucleus,
													  i3d::Image3d<float>* &dmOfBackground,
													  const MV value)
{
	std::vector<Dot> correctedChrCentres; 

	// reinitialize the distribution of chromocenters
	i3d::Image3d<MV> erodedMask;
	i3d::Erosion(maskNucleus, erodedMask, i3d::nb3D_26);

	GenerateRandomPositions(erodedMask,
									chrCount,
									correctedChrCentres,
									value);

	// assign the old position with the new ones
	AssignNearestDots(chrCentres, correctedChrCentres);

	// move the chromosomes (individual molecules) following the 
	// movement of chromocenter that they belong to
	for (size_t i=0; i<chrCount; i++)
	{
		  const i3d::Vector3d<float> shift = 
						 correctedChrCentres[i].pos - chrCentres[i].pos; 
			  
		  ChrMoveByVector(i, shift, maskNucleus, dmOfBackground, value); 
	}

	DEBUG_REPORT("Position of chromocenters reinitialized");

}

//-------------------------------------------------------------------

template <class MV, class PV>
void Cell<MV, PV>::ChrRepairDistrWeighted(const i3d::Image3d<MV> &maskNucleus,
													  	i3d::Image3d<float>* &dmOfBackground,
													  	const MV value)
{
	 float minDensity = FLT_MAX,
			 maxDensity = FLT_MIN;

	 for (size_t i=0; i<chrCount; i++)
	 {
		  minDensity = std::min(minDensity, chrDensities[i]);
		  maxDensity = std::max(maxDensity, chrDensities[i]);
	 }

	std::vector<Dot> correctedChrCentres; 

	// reinitialize the distribution of chromocenters
	i3d::Image3d<MV> erodedMask;
	i3d::Erosion(maskNucleus, erodedMask, i3d::nb3D_26);

	GenerateRandomPositions(erodedMask,
									chrCount,
									correctedChrCentres,
									value);

	// assign the old position with the new ones
	AssignNearestDots(chrCentres, correctedChrCentres);

	// move the chromosomes (individual molecules) following the 
	// movement of chromocenter that they belong to
	for (size_t i=0; i<chrCount; i++)
	{
		  i3d::Vector3d<float> shift = correctedChrCentres[i].pos - chrCentres[i].pos; 

		  // for high density keep the original shift, for low density
		  // eliminate the shift
		  float factor = (chrDensities[i] - minDensity)/(maxDensity - minDensity);

		  // the factor is not linear but quadratic
		  factor = SQR(factor);

		  shift *= factor;
			  
		  ChrMoveByVector(i, shift, maskNucleus, dmOfBackground, value); 
	}

	DEBUG_REPORT("Position of chromocenters reinitialized (proportionally)");
}

//-------------------------------------------------------------------

template <class MV, class PV>
void Cell<MV, PV>::ChrRepairDistrLocally(const i3d::Image3d<MV> &maskNucleus,
													  const std::vector<bool> &overcrowded,
													  i3d::Image3d<float>* &dmOfBackground,
													  const MV value)
{
	// localize the positions that correspond to overcrowded area
	i3d::Image3d<bool> localMask;
	localMask.CopyMetaData(maskNucleus);
	localMask.Clear();
	i3d::Vector3d<float> fpos;
	i3d::Resolution res = maskNucleus.GetResolution();
	i3d::Offset off = maskNucleus.GetOffset();

	// The diameter d2 of sphere (similar to cell shape) that has
	// the half volume of sphere with diameter d1 is given by
	// the following term: d2 = d1/pow(2,1/3)
	float d1 = cellDiameter * res.GetX();
	const int d2 = (int) floorf(0.35f* d1/powf(2.0f, 1.0f/3.0f));
	//note: d2 RADIUS now and is already in voxels

	// render the overcrowded positions already dilated into the blank image
	for (size_t i=0; i<overcrowded.size(); i++)
	{
		 if (overcrowded[i] == true)
		 {
			  //get voxel coordinate of the overcrowded centre
			  fpos = i3d::MicronsToPixels(chrCentres[i].pos - off, res);
			  i3d::Vector3d<int> ipos = (i3d::Vector3d<int>) fpos;

			  //do "a circular" dilation within the maskNucleus mask
			  i3d::Vector3d<int> wpos; //working position "pointer"
			  for (wpos.z=ipos.z-d2; wpos.z <= ipos.z+d2; ++wpos.z)
			  for (wpos.y=ipos.y-d2; wpos.y <= ipos.y+d2; ++wpos.y)
			  for (wpos.x=ipos.x-d2; wpos.x <= ipos.x+d2; ++wpos.x)
			  		if (  (maskNucleus.Include(wpos))
						&& (maskNucleus.GetVoxel(wpos) == value)
						&& (i3d::Norm(wpos-ipos) <= d2))
							localMask.SetVoxel(wpos, true);
		 }
	}

	//now erode a little to get further from the nucleus boundary
	i3d::Image3d<bool> erodedLocalMask;
	i3d::Erosion(localMask, erodedLocalMask, i3d::nb3D_26);
	localMask.DisposeData();

	// render the not-overcrowded positions into the image
	// to introduce basically some more constraints
	for (size_t i=0; i<overcrowded.size(); i++)
	{
		 if (overcrowded[i] == false)
		 {
			  //get voxel coordinate of the not-overcrowded centre
			  fpos = i3d::MicronsToPixels(chrCentres[i].pos - off, res);
			  i3d::Vector3d<int> ipos = (i3d::Vector3d<int>) fpos;

			  if (erodedLocalMask.Include(ipos)) erodedLocalMask.SetVoxel(ipos,false);
		 }
	}

#ifdef GTGEN_DEBUG
	DEBUG_REPORT("Saving mask of 'skrumaz'");
	char fn[50];

	sprintf(fn, "ID%.2u_T%.3lu_nucleusMaskWhole.ics", this->ID, this->timePoint);
	maskNucleus.SaveImage(fn);

	sprintf(fn, "ID%.2u_T%.3lu_nucleusMaskSkrumaz.ics", this->ID, this->timePoint);
	erodedLocalMask.SaveImage(fn);
#endif

	// Take the chromocenters belonging to overcrowded area and reinitialize 
	// their positions in the given area
	std::vector<Dot> selectedChrCentres(0);
	for (size_t i=0; i<chrCentres.size(); i++)
	{
		 if (overcrowded[i])
		 {
			  selectedChrCentres.push_back(chrCentres[i]);
		 }
	}

	// declare a vector buffer for new positions
	std::vector<Dot> correctedChrCentres; 

	// reinitialize the distribution of chromocenters in the
	// selected area 'erodedLocalMask'
	// (actually, the first reinitialized point can get just next
	// to some not-overcrowded one as the first point is not treated
	// with the distance function in the GenerateRandomPositions(),
	// however, all the remaining points should be safe)
	GenerateRandomPositions(erodedLocalMask,
									selectedChrCentres.size(),
									correctedChrCentres,
									true);

	erodedLocalMask.DisposeData();

	// assign the old positions with the new ones
	AssignNearestDots(selectedChrCentres, correctedChrCentres);

	// move the chromosomes (individual molecules) following the 
	// movement of chromocenter that they belong to
	// (apply this motion only to the overcrowded chromocentres)
	size_t index = 0;
	for (size_t i=0; i<chrCount; i++)
	{
		 if (overcrowded[i])
		 {
			  const i3d::Vector3d<float> shift = 
						 correctedChrCentres[index].pos - chrCentres[i].pos; 
			  
			  ChrMoveByVector(i, shift, maskNucleus, dmOfBackground, value); 

			  DEBUG_REPORT("Moving chromocenter ID " << i
			  				<< " (density " << chrDensities[i]
							<< ") at pos " << chrCentres[i].pos 
							<< " by shift " << shift << " [um]");

			  index++;
		 }
	}

	DEBUG_REPORT("Position of chromocenters reinitialized (locally)");
}

//----------------------------------------------------------------------
// A function for Random Walk in 3D image
//----------------------------------------------------------------------
i3d::Vector3d<float> RandomWalk3D(float step)
{
	 float length=0.f;
	 i3d::Vector3d<float> shift(0.f);

	 while (length == 0.f)
	 {
		 shift.x=roundf(GetRandomUniform(-1.49,1.49));
		 shift.y=roundf(GetRandomUniform(-1.49,1.49));
		 shift.z=roundf(GetRandomUniform(-1.49,1.49));
		 
		 length=i3d::Norm(shift);
	 }

	 return step* shift/length;
}



//----------------------------------------------------------------------
// A function for initial distribution of uncoiled chromatin
//----------------------------------------------------------------------
template <class MV, class PV> template <class T>
void Cell<MV, PV>::ChrRandomWalk(const size_t chrID,
											float step,
											float radius,
											float tolerance,
											i3d::Image3d<T> const &mask,
											i3d::Image3d<float>* &dmOfBackground,
											const T value)
{
	//DEBUG_REPORT("entering Random Walk function for chromosome No." << chrID);

	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;
	const size_t from = chrDots * chrID;
	const size_t to = chrDots * (chrID + 1);

	const i3d::Vector3d<float> start = chrCentres[chrID].pos;
	i3d::Vector3d<float> next = start;

	int x,y,z;

	// test if the initial point of random walk is inside the image
	// and in the nucleus mask
	x=(int)roundf( (start.x-xOff)*xRes );
	y=(int)roundf( (start.y-yOff)*yRes );
	z=(int)roundf( (start.z-zOff)*zRes );

	if (!mask.Include(x,y,z))
		 throw ERROR_REPORT("Starting point is not in the image!!!");
	
	if (mask.GetVoxel(x,y,z) != value)
	{	
		 DEBUG_REPORT("Starting point is not in the nucleus mask.");

		 next = FindNearestMaskVoxel(start, mask, value, dmOfBackground);

		 DEBUG_REPORT("Corrected.");

	}

	// sweep over the given portion of the chrDotList
	size_t counter = from;

	while (counter < to)
	{
		 // store the current position
		 i3d::Vector3d<float> last = next;

		 // try to move to a new position
		 next = next + RandomWalk3D(step);

		 // nearest neighbor mask image pixel coordinate
		 x=(int)roundf( (next.x-xOff)*xRes );
		 y=(int)roundf( (next.y-yOff)*yRes );
		 z=(int)roundf( (next.z-zOff)*zRes );

		 // if the new position is out of domain or out of mask,
		 // do nothing a wait for new/better walk direction
		 if (!mask.Include(x,y,z) || (mask.GetVoxel(x,y,z) != value))
		 {
			  next = last;
			  continue;
		 }

		 // find out the distance beween the current position and the
		 // starting point - we would like to prevent to uncoil outside
		 // some predefined area
		 float dist = i3d::Norm(start - next);

		 // the max allowed distance reached
		 if (dist > radius)
		 {
			  // Tolerate (randomly) some overlap of the boundary.
			  // If overflow happens, do not move and ask for new
			  // random step.
			  if ((dist - radius) > (GetRandomUniform(0,tolerance)))
			  {
					next = last;
					continue;
			  }
		 }

		 // store the current position of head of uncoiled thread
		 chrDotList[counter].pos = next;

		 // move to the next position of the thread
		 counter++;
	}
	//DEBUG_REPORT("leaving Random Walk function");
}


//----------------------------------------------------------------------
// explicit instantiations to force explicit build of the functions in this file
// because otherwise the linker couldn't find them
//----------------------------------------------------------------------
template class Cell<i3d::GRAY8,  i3d::GRAY16>;
template class Cell<i3d::GRAY16, i3d::GRAY16>;

template void Cell<i3d::GRAY16, i3d::GRAY16>::ChrRandomWalk<i3d::GRAY16>(const size_t, float, float, float, i3d::Image3d<i3d::GRAY16> const &, i3d::Image3d<float>* &, const i3d::GRAY16);

template void Cell<i3d::GRAY16, i3d::GRAY16>::ChrRandomWalk<bool>(const size_t, float, float, float, i3d::Image3d<bool> const &, i3d::Image3d<float>* &, const bool);

template void Cell<i3d::GRAY8, i3d::GRAY16>::ChrRandomWalk<i3d::GRAY8>(const size_t, float, float, float, i3d::Image3d<i3d::GRAY8> const &,i3d::Image3d<float>* &, const i3d::GRAY8);

template void Cell<i3d::GRAY8, i3d::GRAY16>::ChrRandomWalk<bool>(const size_t, float, float, float, i3d::Image3d<bool> const &, i3d::Image3d<float>* &, const bool);
