/**
 * This file contains implementation of Cell::Scm* methods which handle the
 * global (floating-like) movement of cells, which is implemented using
 * the image transformations based on vector flow fields.
 */

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

#include <i3d/DistanceTransform.h>
#include <i3d/morphology.h>
#include <i3d/convolution.h>
#include <i3d/filters.h>

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

template <class MV, class PV>
void Cell<MV, PV>::ScmRemoveCellFromMask(i3d::Image3d<MV> &mask)
{
	DEBUG_REPORT("removing  ID=" << ID << " from source image at " << mask.GetOffset() << " of size " \
	       << i3d::PixelsToMicrons(mask.GetSize(),mask.GetResolution())  << " in microns");

	MV *m=mask.GetFirstVoxelAddr();
#ifndef GTGEN_DEBUG
	for (size_t i=0; i < mask.GetImageSize(); ++i, ++m)
		if (*m == this->ID) *m=0;
#else
	//debug:
	size_t c=0;
	for (size_t i=0; i < mask.GetImageSize(); ++i, ++m)
		if (*m == this->ID) { *m=0; ++c; }
	REPORT(c << " dots were removed (ID " << ID << ")");
#endif
}


template <class MV, class PV>
void Cell<MV, PV>::ScmRenderCellIntoMask(i3d::Image3d<MV> &mask,
					 i3d::Image3d<MV> *Nmask)
{
	DEBUG_REPORT("inserting ID=" << ID << " into source image at " << mask.GetOffset() << " of size " \
	       << i3d::PixelsToMicrons(mask.GetSize(),mask.GetResolution())  << " in microns");

	RenderBPListIntoMask(mask,(MV)this->ID,scmCellBPList,scmCellBPCentre,scmCellOuterBPNumber);

#ifdef GTGEN_DEBUG
	//for volume preservation testing
	MV *m=mask.GetFirstVoxelAddr();
	size_t c=0;
	for (size_t i=0; i < mask.GetImageSize(); ++i, ++m)
		if (*m == this->ID) ++c;
	REPORT(c << " dots were added (ID " << ID << " )");
#endif

	//render also nuclei if it is present
	if (Nmask) RenderBPListIntoMask(*Nmask,(MV)this->ID,
				scmNucleusBPList,scmNucleusBPCentre,scmNucleusOuterBPNumber);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ScmResetCellPolarityVector(void)
{
	//temporary mask of the cell
	i3d::Image3d<bool> cellMask;

	//init the mask and make it rather tight
	cellMask.SetResolution(scheduler.sceneRes);
	cellMask.SetOffset(scheduler.sceneOffset);
	AllocateAndZeroNewMask(cellMask, scmCellBPList, 0, cellLookDistance);

	//render the cell into it
	RenderBPListIntoMask(cellMask,true,  scmCellBPList,  scmCellBPCentre,  scmCellOuterBPNumber);

	//finally, obtain cell major axis...
	i3d::Vector3d<float> cellCentre; //to be ignored
	GetCellPolarityAndCentreVector(cellMask,scmCellPolarityVector,cellCentre);
}


//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ScmUniversalMovement(FlowField<float> &FF)
{
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");

	/*
	//TODO VLADO REMOVE AFTER DEBUG
	char fn[50];
	sprintf(fn, "ID%.2u_T%.3lu_finishedSceneMasks.ics", this->ID, this->timePoint);
	scheduler.sceneMasks[timePoint]->SaveImage(fn);
	sprintf(fn, "ID%.2u_T%.3lu_consideredSceneMasks.ics", this->ID, this->timePoint);
	scheduler.sceneMasks[timePoint+1]->SaveImage(fn);
	*/

#ifdef GTGEN_WITH_FLOWFIELDS
	//the common prefix of any file storing flow fields,
	//it distinguishes a particular cell at a particular time
	char ffNamePrefix[50];
	sprintf(ffNamePrefix, "ID%.2u_T%.3lu_FF", this->ID, this->timePoint);

	//the flow field into which functions should export
	FlowField<float>* eFF=new FlowField<float>; //exportFF
	//init it to overlay over scene mask exactly
	InitFlowField(*scheduler.sceneMasks[timePoint],*eFF);
#else
#ifdef GTGEN_WITH_RIGIDMOTION
	//pointer to NULL indicates no flow field images should be stored
	char* ffNamePrefix=NULL;
	FlowField<float>* eFF=NULL;
#endif
#endif

#ifdef GTGEN_WITH_RIGIDMOTION
	//add translation:
	//create preference map
	i3d::Image3d<float> MovsMask;

	//based on it, read valid translation vector eventually
	i3d::Vector3d<float> v(0.f,0.f,0.f);
	if (scmCometState == noComet) {
		REPORT("Comet vector is " << scmCometVector << ", state is "
			<< scmCometState << " (nHTF)");
	} else {
		REPORT("Comet vector is " << scmCometVector << ", state is "
			<< scmCometState << " (nHTF) and type is "
			<< scmCometType << " (RTLB)");
	}

	//ScmSuggestTranslationsTowardsEmpty_FT(MovsMask); //slower version
	int availTranslations=ScmSuggestTranslationsTowardsEmpty_SS(MovsMask);
	if ( (availTranslations == 0)
	  && ((scmCometState == toBoundary) || (scmCometState == fromBoundary)) ) {
		//I'm cometing but have nowhere to go
		DEBUG_REPORT("Cell ID=" << this->ID << ": Can't move with cometing, quiting the job and starting a new movement try...");
		scmCometVector=i3d::Vector3d<float>(0.f,0.f,0.f);
		scmCometState=noComet;
		REPORT("New comet vector is " << scmCometVector);
		availTranslations=ScmSuggestTranslationsTowardsEmpty_SS(MovsMask);
	}
	if (availTranslations) {
		//some translational motion is possible, give it a try
		ScmSuggestTranslationVector(v,&MovsMask,availTranslations);

		//submit it to the flow field
		DescribeTranslation(FF, v, eFF);
		SaveFlowField(eFF,ffNamePrefix,"translation", cellLookDistance); //does nothing if eFF is NULL
	}
	MovsMask.DisposeData();

	//add rotation:
	//try to findout some valid rotation angle in some 50 tries
	float angle;
	char tries=0;		//number of tries
	do {
		ScmSuggestRotationAngle(angle);
		++tries;
	} while ((ScmNewCellPositionCollide(scmCellBPCentre,angle,v)) and (tries < 50));

	//if successful, append the rotation into the flow field
	if ((tries < 50) && (angle != 0.f)) {
		DescribeRotation(FF, scmCellBPCentre, angle, eFF);
		SaveFlowField(eFF,ffNamePrefix,"rotation", cellLookDistance); //does nothing if eFF is NULL

		//update the "coherency metadata"
		scmLastTranslationVector=v-scmCometVector;
#ifdef GTGEN_WITH_JUST2DTRANSLATIONS
		//if active: invert z-coordinate so that if the cell moved along z
		//in this frame, this invertion will ask the cell to move back in the next frame
		scmLastTranslationVector.z*=-1.f;
#endif
		scmLastRotationAngle=angle;
		scmLastScmUsed=timePoint+1;

		//this translaction vector was successful, can't I use it for cometing?
		if (scmCometState == hesitating) {
			//I am supposed to become comet, let's test
			//if the currently discovered "escape" way
			//suits our desired direction
			//
			//norm of xy-plane 'subvector' of v
			const float vsize=sqrtf(v.x*v.x + v.y*v.y);
			//deviation angle from optimal direction
			float ang=999999.f;

			switch (scmCometType) {
			case leftBoundary:
				ang=acosf(-1.f * v.x /vsize);
				break;
			case rightBoundary:
				ang=acosf(+1.f * v.x /vsize);
				break;
			case topBoundary:
				ang=acosf(-1.f * v.y /vsize);
				break;
			case bottomBoundary:
				ang=acosf(+1.f * v.y /vsize);
				break;
			}
			//if (ang < 0.7854)  //deviation is less than 45deg
			if (ang < 0.7) { //deviation is less than 40deg
				scmCometVector.x=cometCellMagnitudeOfMovementPerFrame*v.x/vsize;
				scmCometVector.y=cometCellMagnitudeOfMovementPerFrame*v.y/vsize;
				scmCometVector.z=0.f;
				scmCometState=toBoundary;
				DEBUG_REPORT("Cell ID=" << this->ID << ", time=" << timePoint << ": Starting comet towards boundary");
				REPORT("New comet vector is " << scmCometVector);
			}
		}
	}
	else if ((tries == 50) && (availTranslations == 0)) {
		DEBUG_REPORT("translation and rotation separately couldn't find a way out of here, doing a new try...");

		//this one tries to combine translation and rotation at once
		availTranslations=ScmSuggestRigidTowardsEmpty_SS(MovsMask);
		if (availTranslations) {
			//this function works universally, irrelevant of what
			//is represented in the MovsMask image
			ReadVectorFromPreferenceMap(v,MovsMask);
			MovsMask.DisposeData();

			//now decode the vector:
			angle=v.z*MovsMask.GetResolution().GetZ() * 0.12217f; //= 7deg

			//try to add some little translation along z-axis ... someday later TODO VLADO
			v.z=0.f;

			//submit the results into the flow field,
			//in this order to avoid concatenations of flow fields...!
			DescribeTranslation(FF, v, eFF);
			SaveFlowField(eFF,ffNamePrefix,"translation", cellLookDistance); //does nothing if eFF is NULL

			DescribeRotation(FF, scmCellBPCentre, angle, eFF);
			SaveFlowField(eFF,ffNamePrefix,"rotation", cellLookDistance); //does nothing if eFF is NULL

			//update the "coherency metadata"
			scmLastTranslationVector=v;
			scmLastRotationAngle=angle;
			scmLastScmUsed=timePoint+1;
		} else {
			MovsMask.DisposeData();
			throw ERROR_REPORT("current position is in collision, couldn't find any way out of here");
		}
	}
	

#ifdef GTGEN_DEBUG
	//TODO VLADO, disable the consistency test here
	if (ScmNewCellPositionCollide(FF))
		throw ERROR_REPORT("After rigid: Should not be colliding here!");
#endif

	//cometing...
	if ((scmCometState == toBoundary) || (scmCometState == fromBoundary)) {
		//scene boundary coordinates in "absolute microns"
		const float LEFT=scheduler.sceneOffset.x;
		const float TOP=scheduler.sceneOffset.y;
		const float RIGHT=scheduler.sceneSize.x + LEFT;
		const float BOTTOM=scheduler.sceneSize.y + TOP;

		//what is the respective distance
		float curDist=999999.f;

		switch (scmCometType) {
		case leftBoundary:
			curDist=scmCellBPCentre.x - LEFT;
			break;
		case rightBoundary:
			curDist=RIGHT - scmCellBPCentre.x;
			break;
		case topBoundary:
			curDist=scmCellBPCentre.y - TOP;
			break;
		case bottomBoundary:
			curDist=BOTTOM - scmCellBPCentre.y;
			break;
		}

		if ((scmCometState == toBoundary) && (curDist < 0.8f*cellDiameter)) {
			float shouldReturn=GetRandomUniform(0.f,1.f);
			if (shouldReturn > 0.75f) {
				//we are near boundary, let's go back
				if ((scmCometType == leftBoundary) || (scmCometType == rightBoundary))
					scmCometVector.y+=GetRandomGauss(0.f,0.2f*cellMagnitudeOfMovementPerFrame);
				else	scmCometVector.x+=GetRandomGauss(0.f,0.2f*cellMagnitudeOfMovementPerFrame);
				scmCometVector*=-1.f;
				scmCometState=fromBoundary;
				DEBUG_REPORT("Cell ID=" << this->ID << ", time=" << timePoint << ": Turning comet towards scene centre");
			} else {
				//we are near boundary and we should end our life here
				scmCometVector=i3d::Vector3d<float>(0.f,0.f,0.f);
				scmCometState=noComet;
				DEBUG_REPORT("Cell ID=" << this->ID << ", time=" << timePoint << ": Stopping cometing, going for apoptosis...");

		// TODO VLADO - enable when you want to remove cells that got trapped at the scene boundary
/*
				//turn my state to 'being after Cytokinesis', which means that the
				//scheduler will kill me after my whatever atomic phase finishes
				this->currentPhase=Cytokinesis;
				//TODO VLADO This does not remove the cell immediatelly but rather
				//after the cell finishes its atomic phase... which may allow it
				//to return back "into a scene" (and then vanish there suddenly)

				//also wipe out all my future reservations
				size_t cellTP=this->timePoint+1;
				while (cellTP <= scheduler.newestScene) {
					ScmRemoveCellFromMask(*scheduler.sceneMasks[cellTP]);
					cellTP++;
				}
*/
			}

			REPORT("New comet vector is " << scmCometVector);
		} else
		if ((scmCometState == fromBoundary) && (curDist > 2.1f*cellDiameter)) {
			//we are away from boundary, let's stop cometing
			scmCometVector=i3d::Vector3d<float>(0.f,0.f,0.f);
			scmCometState=noComet;
			DEBUG_REPORT("Cell ID=" << this->ID << ": Stopping cometing...");
			REPORT("New comet vector is " << scmCometVector);
		}
	}
#endif


#ifdef GTGEN_WITH_NONRIGIDMOTION
	//add non-rigid motion:
	//only if not in great-cell-shape-changing phases...
	if ( (currentPhase != Anaphase)
	  && (currentPhase != Cytokinesis) )
		ScmSuggestNonrigidDeformation(FF);
	else {
		DEBUG_REPORT("skipping non-rigid cell body deformation for this cell phase");

#ifdef GTGEN_WITH_FLOWFIELDS
		//if flow fields should be exported but NonRigid function
		//is not called, the appropriate flow field files should
		//be saved on the disk -- despite they will contain zeros

		//prepare the exporting flow field
		eFF->x->GetVoxelData()=0.;
		eFF->y->GetVoxelData()=0.;
		//note: the NonRigid function assures the flow field is 3D...
		//but rather... well... to be sure
		if (eFF->z) eFF->z->GetVoxelData()=0.;

		//and save it
		SaveFlowField(eFF,ffNamePrefix,"nonRigid", cellLookDistance);
#endif
	}

#ifdef GTGEN_DEBUG
	/* CONSISTENCY TEST FOR THOSE WHO ARE EXTREMELY DESPERATE :)
	if (ScmNewCellPositionCollide(FF))
		throw ERROR_REPORT("After non-rigid: Should not be colliding here!");
	*/
#endif
#endif

#ifdef GTGEN_WITH_FLOWFIELDS
	//save the final flow field showing complete global cell movement
	IMCopyFromVOI_t hints;
	IMCopyFromVOI_GetHints(*(FF.x),*(eFF->x),hints);

	const float zero=0.f;
	IMCopyFromVOI_Apply(*(FF.x),*(eFF->x),hints,&zero);
	IMCopyFromVOI_Apply(*(FF.y),*(eFF->y),hints,&zero);
	if ((FF.z) && (eFF->z)) IMCopyFromVOI_Apply(*(FF.z),*(eFF->z),hints,&zero);
	
	SaveFlowField(eFF,ffNamePrefix,"finalGlobal", cellLookDistance);

	//clear the dyn. allocated temporary flow field
	delete eFF;
#endif
}


//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ScmXYTranslationalMovement(FlowField<float> &FF)
{
	i3d::Vector3d<float> v(0.f,0.f,0.f);
	char tries=0;		//number of tries

	do {
		SuggestBrownianVector(v,cellMagnitudeOfMovementPerFrame);
		v.z=0.f; //just xy translation

		++tries;
	} while ((ScmNewCellPositionCollide(v)) and (tries < 50));

	if (tries < 50)
		DescribeTranslation(FF, v);
	else
		throw ERROR_REPORT("Can't figure out any random translation.");
}


//-----------------------------------------------------------------------------
template <class MV, class PV>
int Cell<MV, PV>::ScmSuggestRigidTowardsEmpty_SS(i3d::Image3d<float> &MovsMask)
{
	if (scmCellOuterBPNumber > scmCellBPList.size())
		throw ERROR_REPORT("There are more outer boundary points than is the length of the list.");

	//shortcut to the current sceneMasks
	i3d::Image3d<MV> const &mask=*scheduler.sceneMasks[timePoint+1];

	//will be a return value
	int noOfValidTranslations=0;

	//are we in the fast-growing phases?
	int SE=1; //SearchExpansion coefficient
	/* TMI disabled
	if ((currentPhase == Anaphase)
	  || (currentPhase == Cytokinesis)) SE=2;
	*/

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2,t3;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	//we need to compute the output size of MovsMask anyway, so here...
	//note: sizes should be odd
	const int MovsMask_xSize=SE*4*(int)floorf(cellLookDistance*mask.GetResolution().GetX()) +1;
	const int MovsMask_ySize=SE*4*(int)floorf(cellLookDistance*mask.GetResolution().GetY()) +1;
	//const int MovsMask_zSize=11; //-35..0..35 deg in steps of 7 deg
	const int MovsMask_zSize=(SE == 1)? 11 : 15; //-49..0..49 deg in steps of 7 deg if SE==2
	DEBUG_REPORT("MovsMask will have size (" << MovsMask_xSize << ","
		     << MovsMask_ySize << "," << MovsMask_zSize << ")");

	// prepare for distance transform, metadata:
	MovsMask.SetResolution(mask.GetResolution());
	MovsMask.SetOffset(i3d::Offset(0.0f,0.0f,0.0f));
	MovsMask.MakeRoom(MovsMask_xSize,MovsMask_ySize,MovsMask_zSize);

	//time-saver :-)
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	//const float zRes=mask.GetResolution().GetZ();

	// prepare for distance transform, data/content:
	float *pDT=MovsMask.GetFirstVoxelAddr();
	for (int z=-MovsMask_zSize/2; z <= MovsMask_zSize/2; ++z) {
	  const float angle=(float)z * 0.12217f; //= 7deg

	  for (int y=-MovsMask_ySize/2; y <= MovsMask_ySize/2; ++y)
	    for (int x=-MovsMask_xSize/2; x <= MovsMask_xSize/2; ++x) {
		//working shift vector
		i3d::Vector3d<float> V((float)x/xRes, (float)y/yRes, 0.f);

		if (ScmNewCellPositionCollide(scmCellBPCentre,angle,V)) {
			*pDT=0.f;
			//REPORT("collision for vector (" << x << "," << y << ") in pixels and angle " << z*7 << " in deg");
		} else {
			*pDT=100.f;
			++noOfValidTranslations;
		}

		++pDT;
	    }
	}

#ifdef GTGEN_DEBUG
	REPORT("discovered " << noOfValidTranslations << " available translations before DT");

	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("Collision detections took " << T2-T1 << " seconds");
#endif
	//now the distance transform
	i3d::EDM(MovsMask,0,100.f,false);
	// or TODO VLADO WHICH IS FASTER?
	//i3d::FastSaito(MovsMask,100.f,false);

#ifdef GTGEN_DEBUG
	gettimeofday(&t3,NULL);
	t3.tv_sec-=t1.tv_sec;
	T1=(float)t3.tv_sec + ((float)t3.tv_usec / 1000000.0f);
	REPORT("Distance transform took " << T1-T2 << " seconds");
	T2=(float)t1.tv_usec / 1000000.0f;
	REPORT("Complete processing took " << T1-T2 << " seconds");
#endif

	return (noOfValidTranslations);
}


//-----------------------------------------------------------------------------
template <class MV, class PV>
bool Cell<MV, PV>::ScmNewCellPositionCollide(i3d::Vector3d<float> const &v)
{
	if (scmCellOuterBPNumber > scmCellBPList.size())
		throw ERROR_REPORT("There are more outer boundary points than is the length of the list.");

	//time savers:
	i3d::Image3d<MV> const &mask=*scheduler.sceneMasks[timePoint+1];

	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;

	//we just won't let draw out of the image canvas
	const int mx=0;
	const int my=0;
	const int mz=0;
	const int Mx=mask.GetSizeX()-1;
	const int My=mask.GetSizeY()-1;
	const int Mz=mask.GetSizeZ()-1;

	//sweep over the outer boundary points
	for (size_t i=0; i < scmCellOuterBPNumber; ++i) {
		//tested nearest neighbor mask image pixel coordinate
		const int x=(int)roundf( (scmCellBPList[i].x+v.x -xOff) *xRes );
		const int y=(int)roundf( (scmCellBPList[i].y+v.y -yOff) *yRes );
		const int z=(int)roundf( (scmCellBPList[i].z+v.z -zOff) *zRes );

		//is the new position colliding?
#ifndef GTGEN_DEBUG_
		for (int zz=z-1; zz <= z+1; ++zz)
		  for (int yy=y-1; yy <= y+1; ++yy)
		    for (int xx=x-1; xx <= x+1; ++xx)
			if (  NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz) ||
			      ((mask.GetVoxel(xx,yy,zz) != 0) && (mask.GetVoxel(xx,yy,zz) != ID))
			   ) return true;
#else
		for (int zz=z-1; zz <= z+1; ++zz)
		  for (int yy=y-1; yy <= y+1; ++yy)
		    for (int xx=x-1; xx <= x+1; ++xx)
			if (  NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz) ||
			      ((mask.GetVoxel(xx,yy,zz) != 0) && (mask.GetVoxel(xx,yy,zz) != ID))
			   ) {
			       if ((v.x == 0.f) && (v.y == 0.f) && (v.z == 0.f)) {
				REPORT( "index " << i << " @ " << scmCellBPList[i]
				  << " -> pixel position "
				  << i3d::MicronsToPixels(scmCellBPList[i]-mask.GetOffset(),mask.GetResolution()) );
				REPORT( "moves to " << scmCellBPList[i]+v << " -> pixel position "
				  << i3d::MicronsToPixels(scmCellBPList[i]-mask.GetOffset()+v,mask.GetResolution()) );
				if (NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz)) {
				  REPORT("moved outside the image");
				} else {
				  REPORT("crashed into somebodyelse's mask with value/ID " << mask.GetVoxel(xx,yy,zz));
				}
			       }

				return true;
			}
#endif
	}

	return false;
}


template <class MV, class PV>
bool Cell<MV, PV>::ScmNewCellPositionCollide(i3d::Vector3d<float> const &centre, const float angle,
	 				i3d::Vector3d<float> const &v)
{
	if (scmCellOuterBPNumber > scmCellBPList.size())
		throw ERROR_REPORT("There are more outer boundary points than is the length of the list.");

	//time savers:
	i3d::Image3d<MV> const &mask=*scheduler.sceneMasks[timePoint+1];

	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;

	//we just won't let draw out of the image canvas
	const int mx=0;
	const int my=0;
	const int mz=0;
	const int Mx=mask.GetSizeX()-1;
	const int My=mask.GetSizeY()-1;
	const int Mz=mask.GetSizeZ()-1;

	//sweep over the outer boundary points
	for (size_t i=0; i < scmCellOuterBPNumber; ++i) {
		//relative position from the centre of rotation, in microns
		const float X=scmCellBPList[i].x - centre.x;
		const float Y=scmCellBPList[i].y - centre.y;

#ifndef GTGEN_DEBUG_
		//new relative position after rotation; made absolute;
		//added the shift vector and, finally, converted to nearest pixel position
		const int x=(int)roundf( (cos(angle)*X - sin(angle)*Y + centre.x +v.x - xOff) *xRes );
		const int y=(int)roundf( (sin(angle)*X + cos(angle)*Y + centre.y +v.y - yOff) *yRes );
		const int z=(int)roundf( (scmCellBPList[i].z+v.z -zOff) *zRes );

		//is the new position colliding?
		for (int zz=z-1; zz <= z+1; ++zz)
		  for (int yy=y-1; yy <= y+1; ++yy)
		    for (int xx=x-1; xx <= x+1; ++xx)
			if (  NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz) ||
			      ((mask.GetVoxel(xx,yy,zz) != 0) && (mask.GetVoxel(xx,yy,zz) != ID))
			   ) return true;
#else
		//new relative position after rotation; made absolute;
		//added the shift vector and, finally, converted to nearest pixel position
		const float nX=cos(angle)*X - sin(angle)*Y + centre.x +v.x;
		const float nY=sin(angle)*X + cos(angle)*Y + centre.y +v.y;
		const float nZ=scmCellBPList[i].z+v.z;
		const int x=(int)roundf( (nX - xOff) *xRes );
		const int y=(int)roundf( (nY - yOff) *yRes );
		const int z=(int)roundf( (nZ - zOff) *zRes );

		//is the new position colliding?
		for (int zz=z-1; zz <= z+1; ++zz)
		  for (int yy=y-1; yy <= y+1; ++yy)
		    for (int xx=x-1; xx <= x+1; ++xx)
			if (  NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz) ||
			      ((mask.GetVoxel(xx,yy,zz) != 0) && (mask.GetVoxel(xx,yy,zz) != ID))
			   ) {
				REPORT("index " << i << " @ " << scmCellBPList[i]
				  << " -> pixel position "
				  << i3d::MicronsToPixels(scmCellBPList[i]-mask.GetOffset(),mask.GetResolution()) );
				REPORT("moves to (" << nX << "," << nY << "," << nZ << ") -> pixel position ("
				  << x << "," << y << "," << z << ")");
				if (NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz)) {
				  REPORT("moved outside the image");
				} else {
				  REPORT("crashed into somebodyelse's mask with value/ID " << mask.GetVoxel(xx,yy,zz));
				}

				return true;
			}
#endif
	}

	return false;
}


template <class MV, class PV>
bool Cell<MV, PV>::ScmNewCellPositionCollide(FlowField<float> const &FF)
{
	//DEBUG_REPORT("I'm in..."); //TODO VLADO REMOVE ROTATION

	//sanitary checks...
	if (scmCellOuterBPNumber > scmCellBPList.size())
		throw ERROR_REPORT("There are more outer boundary points than is the length of the list.");

	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//time savers:
	i3d::Image3d<MV> const &mask=*scheduler.sceneMasks[timePoint+1];

	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;

	//we just won't let draw out of the image canvas
	const int mx=0;
	const int my=0;
	const int mz=0;
	const int Mx=mask.GetSizeX()-1;
	const int My=mask.GetSizeY()-1;
	const int Mz=mask.GetSizeZ()-1;

	//sweep over the outer boundary points
	for (size_t i=0; i < scmCellOuterBPNumber; ++i) {
		const float X=scmCellBPList[i].x;
		const float Y=scmCellBPList[i].y;
		const float Z=scmCellBPList[i].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 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 );

		//is the new position colliding?
#ifndef GTGEN_DEBUG_
		for (int zz=nZp-1; zz <= nZp+1; ++zz)
		  for (int yy=nYp-1; yy <= nYp+1; ++yy)
		    for (int xx=nXp-1; xx <= nXp+1; ++xx)
			if (  NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz) ||
			      ((mask.GetVoxel(xx,yy,zz) != 0) && (mask.GetVoxel(xx,yy,zz) != ID))
			   ) return true;
#else
		for (int zz=nZp-1; zz <= nZp+1; ++zz)
		  for (int yy=nYp-1; yy <= nYp+1; ++yy)
		    for (int xx=nXp-1; xx <= nXp+1; ++xx)
			if (  NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz) ||
			      ((mask.GetVoxel(xx,yy,zz) != 0) && (mask.GetVoxel(xx,yy,zz) != ID))
			   ) {
				REPORT("index " << i << " @ " << scmCellBPList[i]
				  << " -> pixel position (" << Xp << "," << Yp << "," << Zp << ")");
				REPORT("moves to (" << nX << "," << nY << "," << nZ << ") -> pixel position ("
				  << nXp << "," << nYp << "," << nZp << ")");
				if (NOT_INCLUDE(xx,mx,Mx, yy,my,My, zz,mz,Mz)) {
				  REPORT("moved outside the image");
				} else {
				  REPORT("crashed into somebodyelse's mask with value/ID " << mask.GetVoxel(xx,yy,zz));
				}

				return true;
			}
#endif
	}

	return false;
}


template <class MV, class PV>
void Cell<MV, PV>::ScmSuggestTranslationsTowardsEmpty_FT(i3d::Image3d<float> &MovsMask)
{
	if (scmCellOuterBPNumber > scmCellBPList.size())
		throw ERROR_REPORT("There are more outer boundary points than is the length of the list.");

	//find the (rectangular coordinate-system axis-aligned) bounding box
	//in microns...
	float xFrom=100000000000000.f;
	float yFrom=100000000000000.f;
	float zFrom=100000000000000.f;
	float xTo= -100000000000000.f;
	float yTo= -100000000000000.f;
	float zTo= -100000000000000.f;

	//sweep over the list and seek extremal coordinates
	for (size_t i=0; i < scmCellOuterBPNumber; ++i) {
		//tested position
		const float x=scmCellBPList[i].x;
		const float y=scmCellBPList[i].y;
		const float z=scmCellBPList[i].z;

		if (x < xFrom) xFrom=x;
		if (y < yFrom) yFrom=y;
		if (z < zFrom) zFrom=z;
		if (x > xTo) xTo=x;
		if (y > yTo) yTo=y;
		if (z > zTo) zTo=z;
	}

	DEBUG_REPORT("points span x=" << xFrom << " to " << xTo << "; y="
	       << yFrom << " to " << yTo << "; z=" << zFrom << " to " << zTo);

	//shortcut to the current sceneMasks
	i3d::Image3d<MV> const &mask=*scheduler.sceneMasks[timePoint+1];

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2,t3;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	//we need to compute the output size of MovsMask anyway, so here...
	//note: sizes should be odd
	const int MovsMask_xSize=2*(int)floorf(cellLookDistance*mask.GetResolution().GetX()) +1;
	const int MovsMask_ySize=2*(int)floorf(cellLookDistance*mask.GetResolution().GetY()) +1;
	const int MovsMask_zSize=3;
	DEBUG_REPORT("MovsMask will have size (" << MovsMask_xSize << ","
		     << MovsMask_ySize << "," << MovsMask_zSize << ")");

	//new size of the image: includes the cell + how far it can
	//					     see in both directions
	int xSize=(int)ceilf( (xTo-xFrom + 2*cellLookDistance)
				* mask.GetResolution().GetX() );
	int ySize=(int)ceilf( (yTo-yFrom + 2*cellLookDistance)
				* mask.GetResolution().GetY() );
	int zSize=(int)ceilf( (zTo-zFrom + 2*cellLookDistance)
				* mask.GetResolution().GetZ() );

	//new offset of the image 
	xFrom-=cellLookDistance;
	yFrom-=cellLookDistance;
	zFrom-=cellLookDistance;

	//we gonna do a "CopyFromVOI" from the sceneMasks:
	//pixel offset and region size within the sceneMasks image
	int xOff=(int)ceilf( (xFrom - mask.GetOffset().x) *mask.GetResolution().GetX() );
	if (xOff < 0) { xSize+=xOff; xOff=0; }
	if ((xOff+xSize) > (signed)mask.GetSizeX()) xSize=mask.GetSizeX()-xOff;

	int yOff=(int)ceilf( (yFrom - mask.GetOffset().y) *mask.GetResolution().GetY() );
	if (yOff < 0) { ySize+=yOff; yOff=0; }
	if ((yOff+ySize) > (signed)mask.GetSizeY()) ySize=mask.GetSizeY()-yOff;

	int zOff=(int)ceilf( (zFrom - mask.GetOffset().z) *mask.GetResolution().GetZ() );
	if (zOff < 0) { zSize+=zOff; zOff=0; }
	if ((zOff+zSize) > (signed)mask.GetSizeZ()) zSize=mask.GetSizeZ()-zOff;

	//e.g., xSize may be still negative if xOff is too negative...
	//if ((xSize <= 0) || (ySize <= 0) || (zSize <= 0)) {
	//in fact, it must be at least of the size of the output MovsMask image...
	if ((xSize <= MovsMask_xSize) || (ySize <= MovsMask_ySize) || (zSize <= MovsMask_zSize)) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " is out of scene or overlay is too small";
		throw ERROR_REPORT(err.str());
	}

	//the mask of free positions where the cell can appear in the given situation,
	//this image will then be distance transformed to suggest the optimal direction
	i3d::Image3d<float> imgDT;
	imgDT.MakeRoom(xSize,ySize,zSize);
	imgDT.SetResolution(mask.GetResolution());
	imgDT.SetOffset( mask.GetOffset()
	  + i3d::PixelsToMicrons(i3d::Vector3d<size_t>(xOff,yOff,zOff),mask.GetResolution()) );

	//mask images of the object and its environment, the "CopyFromVOI" targets ;-)
	i3d::Image3d<bool> imgObj, imgSpace;

	//the "CopyFromVOI"
	imgSpace.CopyMetaData(imgDT);
	bool *iS=imgSpace.GetFirstVoxelAddr();
	for (int z=0; z < zSize; ++z)
	  for (int y=0; y < ySize; ++y) {
	    const MV *mp=mask.GetVoxelAddr(xOff,yOff+y,zOff+z);
	    for (int x=0; x < xSize; ++x) {
		*iS=((*mp > 0) && (*mp != ID));
		++mp; ++iS;
	    }
	  }

	//basically also a "CopyFromVOI" but since the sceneMasks is probably not actuall
	//we must render the cell object our selves rather than coping it from the sceneMasks
	imgObj.CopyMetaData(imgDT);
	imgObj.Clear();
	RenderBPListIntoMask(imgObj,true, scmCellBPList,scmCellBPCentre,scmCellOuterBPNumber);
	//imgObj.SaveImage("CopyFromVOI_object.ics");
	//imgSpace.SaveImage("CopyFromVOI_space.ics");

#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("CopyFromVOI and stuff took " << T2-T1 << " seconds");
#endif
	// dilate the space to guarantee there will be a gap between
	// the generated objects:
	//i3d::Image3d<bool> space_mirror;
	//i3d::Dilation(imgSpace, space_mirror, i3d::nb3D_26);

	// apply convolution; as we flip the image in advance we apply
	// the correlation instead of convolution
	imgObj.Flip(true, true, true);
	i3d::Convolution<double>(imgSpace,imgObj,imgDT,false);

	imgObj.DisposeData();
	imgSpace.DisposeData();

	// prepare for distance transform: remove the positions, where
	// the correlation results give some non-zero value
	float *pDT=imgDT.GetFirstVoxelAddr();
	for (size_t i=0; i<imgDT.GetImageSize(); ++i, ++pDT)
	  *pDT=(*pDT < 0.5f)? 100.f : 0.f;

	//imgDT.SaveImage("DTmask.ics");

#ifdef GTGEN_DEBUG
	gettimeofday(&t3,NULL);
	t3.tv_sec-=t1.tv_sec;
	T1=(float)t3.tv_sec + ((float)t3.tv_usec / 1000000.0f);
	REPORT("Convolution and thresholding took " << T1-T2 << " seconds");
#endif
	//now the distance transform
	i3d::EDM(imgDT,0,100.f,false);
	// or TODO VLADO WHICH IS FASTER?
	//i3d::FastSaito(imgDT,100.f,false);

#ifdef GTGEN_DEBUG
	gettimeofday(&t3,NULL);
	t3.tv_sec-=t1.tv_sec;
	T2=(float)t3.tv_sec + ((float)t3.tv_usec / 1000000.0f);
	REPORT("Distance transform took " << T2-T1 << " seconds");
#endif
	MovsMask.CopyFromVOI(imgDT,i3d::VOI<i3d::PIXELS>((imgDT.GetSizeX()-MovsMask_xSize)/2,
						    (imgDT.GetSizeY()-MovsMask_ySize)/2,
						    imgDT.GetSizeZ()/2-1,
						    MovsMask_xSize,MovsMask_ySize,MovsMask_zSize));
#ifdef GTGEN_DEBUG
	gettimeofday(&t3,NULL);
	t3.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t3.tv_sec + ((float)t3.tv_usec / 1000000.0f);
	REPORT("Complete processing took " << T2-T1 << " seconds");
#endif
}


template <class MV, class PV>
int Cell<MV, PV>::ScmSuggestTranslationsTowardsEmpty_SS(i3d::Image3d<float> &MovsMask)
{
	if (scmCellOuterBPNumber > scmCellBPList.size())
		throw ERROR_REPORT("There are more outer boundary points than is the length of the list.");

	//shortcut to the current sceneMasks
	i3d::Image3d<MV> const &mask=*scheduler.sceneMasks[timePoint+1];

	//will be a return value
	int noOfValidTranslations=0;

	//are we in the fast-growing phases?
	int SE=1; //SearchExpansion coefficient
	/* TMI disabled
	if ((currentPhase == Anaphase)
	  || (currentPhase == Cytokinesis)) SE=2;
	*/

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2,t3;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	//we need to compute the output size of MovsMask anyway, so here...
	//note: sizes should be odd
	const int MovsMask_xSize=SE*2*(int)floorf(cellLookDistance*mask.GetResolution().GetX()) +1;
	const int MovsMask_ySize=SE*2*(int)floorf(cellLookDistance*mask.GetResolution().GetY()) +1;
	const int MovsMask_zSize=SE*2*2 +1; //3D search
	DEBUG_REPORT("MovsMask will have size (" << MovsMask_xSize << ","
		     << MovsMask_ySize << "," << MovsMask_zSize << ")");

	// prepare for distance transform, metadata:
	MovsMask.SetResolution(mask.GetResolution());
	MovsMask.SetOffset(i3d::Offset(0.0f,0.0f,0.0f));
	MovsMask.MakeRoom(MovsMask_xSize,MovsMask_ySize,MovsMask_zSize);
	MovsMask.GetVoxelData()=0;

	//time-saver :-)
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();

	// prepare for distance transform, data/content:
#ifdef GTGEN_WITH_MULTITHREADING
	#pragma omp parallel for schedule(dynamic,1) num_threads(5)
#endif
	for (int z=-MovsMask_zSize/2; z <= MovsMask_zSize/2; ++z)
	{

	  for (int y=-MovsMask_ySize/2; y <= MovsMask_ySize/2; y+=2)
	  {
		 float *pDT=MovsMask.GetVoxelAddr(0,y+(MovsMask_ySize/2),z+(MovsMask_zSize/2));
	    for (int x=-MovsMask_xSize/2; x <= MovsMask_xSize/2; x+=2)
		 {
			//working shift vector
			i3d::Vector3d<float> V((float)x/xRes, (float)y/yRes, (float)z/zRes);
			V+=scmCometVector;

			if (ScmNewCellPositionCollide(V)) {
				*pDT=0.f;
				//REPORT("collision for vector (" << x << "," << y << "," << z << ") in pixels");
				if ((x == 0) && (y == 0) && (z == 0))
				  REPORT("trouble ahead: colliding even for no movement");
			} else {
				*pDT=100.f;
				if (x < MovsMask_xSize/2) *(pDT+1)=100.f;
				if (y < MovsMask_ySize/2) *(pDT+MovsMask_xSize)=100.f;
				if ((x < MovsMask_xSize/2) && (y < MovsMask_ySize/2)) *(pDT+MovsMask_xSize+1)=100.f;
				++noOfValidTranslations;
			}

			pDT+=2;
	    }
	  }

	}

#ifdef GTGEN_DEBUG
	REPORT("discovered " << noOfValidTranslations << " available translations before DT");

	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("Collision detections took " << T2-T1 << " seconds");
#endif
	//now the distance transform
	//MovsMask.SaveImage("MovsMask1-detection.ics");
	i3d::EDM(MovsMask,0,100.f,false);
	//MovsMask.SaveImage("MovsMask2-EDM.ics");
	// or TODO VLADO WHICH IS FASTER?
	//i3d::FastSaito(MovsMask,100.f,false);

#ifdef GTGEN_DEBUG
	gettimeofday(&t3,NULL);
	t3.tv_sec-=t1.tv_sec;
	T1=(float)t3.tv_sec + ((float)t3.tv_usec / 1000000.0f);
	REPORT("Distance transform took " << T1-T2 << " seconds");
	T2=(float)t1.tv_usec / 1000000.0f;
	REPORT("Complete processing took " << T1-T2 << " seconds");
#endif

	return (noOfValidTranslations);
}


//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ScmSuggestTranslationVector(i3d::Vector3d<float> &V,
					const i3d::Image3d<float> *MovsMask,
					const size_t availTrans)
{
	if (!MovsMask) {
		DEBUG_REPORT("No MovsMask to follow, doing my way...");
		//no preference map... okay we suggest something:
		//Brownian motion in 20 attempts
		char tries=0;		//number of tries
		do {
			SuggestBrownianVector(V,cellMagnitudeOfMovementPerFrame);
#ifdef GTGEN_WITH_JUST2DTRANSLATIONS
			V.z=0.f;
#endif
			V+=scmCometVector;
			++tries;
		} while ((ScmNewCellPositionCollide(V)) and (tries < 20));

		if (tries == 20) {
			//no luck?
			//aren't we cometing towards boundary?
			if (scmCometState == toBoundary) {
				//yes, we are... let's try to move back now...
				if ((scmCometType == leftBoundary) || (scmCometType == rightBoundary))
					scmCometVector.y+=GetRandomGauss(0.f,0.2f*cellMagnitudeOfMovementPerFrame);
				else	scmCometVector.x+=GetRandomGauss(0.f,0.2f*cellMagnitudeOfMovementPerFrame);
				scmCometVector*=-1.f;
				scmCometState=fromBoundary;
				DEBUG_REPORT("Cell ID=" << this->ID << ", time=" << timePoint << ": Turning comet towards scene centre");

				//new tries:
				tries=0;
				do {
					SuggestBrownianVector(V,cellMagnitudeOfMovementPerFrame);
#ifdef GTGEN_WITH_JUST2DTRANSLATIONS
					V.z=0.f;
#endif
					V+=scmCometVector;
					++tries;
				} while ((ScmNewCellPositionCollide(V)) and (tries < 20));

				if (tries == 20) {
					DEBUG_REPORT("Cell ID=" << this->ID << ": Can't move with cometing, quiting the job and not moving this time...");
					scmCometVector=i3d::Vector3d<float>(0.f,0.f,0.f);
					scmCometState=noComet;

					REPORT("I'm comet and I'm stuck, returning with (0,0,0) default");
					V.x=V.y=V.z=0.f;
				}
			}
			//return "no movement vector" in this case
			else V.x=V.y=V.z=0.f;
		}
	} else {
		//local copy of MovsMask as we gonna modify it
		i3d::Image3d<float> mm(*MovsMask);

#ifdef GTGEN_DEBUG
		float sum=0;
		const float *m=mm.GetFirstVoxelAddr();
		float const *mL=mm.GetFirstVoxelAddr()+mm.GetImageSize();
		while (m != mL) { sum+= *m; ++m; }
		REPORT("Got to follow MovsMask, its initial sum is " << sum);
#endif
		if (availTrans >= 5) {
			//make cellMagnitudeOfMovementPerFrame vector lengths the most popular
			//MultiplyWithRadialGaussian(mm,cellMagnitudeOfMovementPerFrame,cellLookDistance/3.f);
			MultiplyWithRadialGaussian(mm,cellMagnitudeOfMovementPerFrame,1.5f*cellMagnitudeOfMovementPerFrame); //=4/3*vel
			//
			//mm.SaveImage("MovsMask3-radial.ics");

			if (scmLastScmUsed == timePoint) {
				//the last vector information is not too old
				//we'll use it in order to preserve coherency of motion
				if ( (scmLastTranslationVector.x) || (scmLastTranslationVector.y)
				   || (scmLastTranslationVector.z))
					MultiplyWithAngularGaussian(mm,scmLastTranslationVector,1.35f);
				//note: sigma 1.35f makes vector parallel to the scmLastTranslationVector
				//twice preferred than a vector perpendicular to it (leaving reasonable
				//chance to change direction of motion in this way)
				//
				//mm.SaveImage("MovsMask4-angular.ics");
			}

#ifdef GTGEN_WITH_JUST2DTRANSLATIONS
			//suppress a little the motion along z
			MultiplyWithSliceDrivenGaussian(mm,0.65f); //cca 50:50 for staying with z=0 or z!=0
#endif
		} else DEBUG_REPORT("skipping coherency due to low number of available translations");

		//try to obtain some more preferred vector in 3 tries:
		char tries=0;		//number of tries
		do {
			//readout some vector from the map into V
			ReadVectorFromPreferenceMap(V,mm);
			V+=scmCometVector;
			++tries;
		} while ((ScmNewCellPositionCollide(V)) and (tries < 3));

		if (tries == 3) {
			//no luck? return "no movement vector" in this case
			V.x=V.y=V.z=0.f;
			REPORT("Couldn't read out a valid vector in 3 attempts. Is MovsMask valid?");

			/*
			//TODO REMOVE AFTER DEBUG VLADO
			MovsMask->SaveImage("MovsMask_orig_preference.ics");
			mm.SaveImage("MovsMask_after_coherency.ics");
			throw ERROR_REPORT("stoping because of invalid MovsMask");
			*/
		}
	}
	//when we get here, we have some nice valid vector V
}


template <class MV, class PV>
void Cell<MV, PV>::ScmSuggestRotationAngle(float &ang)
{
	/*
	if (scmLastScmUsed == timePoint) {
		//the last angle information is not too old
		//we'll use it in order to preserve coherency of motion
	} else {
		//the last angle information is too old, ignore it

	}
	*/
	ang=0.f; //safe default

	//the sigma should force the function to return +-15deg angles with
	//probability half of the probability for 0deg (the mean)
	ang=GetRandomGauss(0.f,0.23f);

	//some observed rotations...
	//ang=GetRandomRotationMultimodal(); TODO VLADO, opravit a vratit zpet
}


template <class MV, class PV>
void Cell<MV, PV>::ScmSuggestNonrigidDeformation(FlowField<float> &FF)
{
	//if we are supposed to skip this deformation from time to time,
	//and if it is the right time (every odd frame) now, we just quit...
	if ((cellSparseNonRigidDeformations) && (timePoint & 1)) {
		REPORT("skipping non-rigid this time");
		return;
	}

	//consistency 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.");

	//does images size fit the current CellBP lists?
	if (scmPnHints.GetSizeX() != scmCellOuterBPNumber) {
		//prepare 'power noise' hints for non-rigid cell deformation
		scheduler.PnGetMeNonrigidHints(scmCellBPList,scmCellOuterBPNumber,scmPnHints);

		/*
		char name[]="XXpowernoise.ics";
		name[0]=(this->ID/10)+48;
		name[1]=(this->ID%10)+48;
		scmPnHints.SaveImage(name);
		*/
	}

	//line of scmPnHints image that will be used in this call
	size_t curPnTime=(size_t)scmPnHints.GetOffset().y;

	//aren't we at the end of "non-rigid" deformation history?
	if (curPnTime == scmPnHints.GetSizeY()) {
		//hmm, this is possible but rather unlikely
		REPORT("cell ID " << ID << " managed to consume its whole 'power noise' history");
		scheduler.PnGetMeNonrigidHints(scmCellBPList,scmCellOuterBPNumber,scmPnHints);
		curPnTime=0;
	}

	//ok, the scmPnHints image is good for us, let's make use of it

	//flow field extra only for the 'power noise' deformation
	FlowField<float> pnFF;

	//this makes it zeroed and of appropriate size
	InitFlowField(*FF.x,pnFF);

	//pointer to the PnHints image
	DEBUG_REPORT("processing line " << curPnTime << " of the 'power noise' image, ID=" << ID);
	float *pnValue=scmPnHints.GetVoxelAddr(0,curPnTime,0);

	/* uncomment to see how much the centres differ:
	i3d::Vector3d<float> massCentre;
	ChrGetCentreOfLowDensity(massCentre);
	DEBUG_REPORT("centres: geom=" << scmCellBPCentre << ", low_mass=" << massCentre << " [um]");
	DEBUG_REPORT("centres: low_mass-geom=" << massCentre-scmCellBPCentre
						<< " of lenght " << i3d::Norm(massCentre-scmCellBPCentre) << " um");
	*/

	//shall we do "strong non-rigid deformation" this time?
	//else just a regular one?
	if (timePoint == scmPnNextStrongUsage) {
		//yeap... define when to do the same thing next time
		//(to be able to report it at once, which we wish to do right now)
		//allows for this event to happen roughly four-times during the cell cycle
		float PnStrongInitDelay=(float)cellCycleLength/4.f;

		if (configIni["testing"].present("strong deformation delay"))
		{
			REPORT("TESTING MODE: enforcing average strong deformation delay to "
				<< (int)configIni["testing"]["strong deformation delay"] << " frames.");
			PnStrongInitDelay=(float)configIni["testing"]["strong deformation delay"];
		}

		scmPnNextStrongUsage+=(size_t)std::max(GetRandomGauss(PnStrongInitDelay,PnStrongInitDelay/4.f),1.f);

		DEBUG_REPORT("using stronger hints this time; next such event will be at " << scmPnNextStrongUsage);

		//allocate memory for the extra copy of scmPnHints
		float *bigPnValue=new float[scmCellOuterBPNumber];
		if (bigPnValue) {
			//copy the scmPnHints line and multiply
			const float mult=cellNonRigidStrongDeformation/cellNonRigidDeformation;
			for (size_t qq=0; qq < scmCellOuterBPNumber; ++qq)
				*(bigPnValue+qq)=*(pnValue+qq) * mult;
			//note: the pnHint image is already stretched to cellNonRigidDeformation,
			//that's why we "re-stretch" with the fraction above

			//prepare the flow field
			DescribeRadialFlow(pnFF,scmCellBPList,scmCellBPCentre,scmCellOuterBPNumber,bigPnValue,1,true);

			//delete the temporal memory
			delete[] bigPnValue;
		} else {
			//DO NOT QUIT ON SUCH BANAL ERROR,
			//just leave a note
			REPORT("Couldn't allocate " << scmCellOuterBPNumber*sizeof(float)/1024
			    << "kB for occasional \"strong\" non-rigid deformation, skipping it this time");
		}
	} else DescribeRadialFlow(pnFF,scmCellBPList,scmCellBPCentre,scmCellOuterBPNumber,pnValue,1,true);

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	//pure non-rigid deformation flow field is created
	//add it to the existing flow field FF
	FlowField<float> *tmpFF = new FlowField<float>();
	AddFlowFields(FF,pnFF,*tmpFF);

	//and test this new configuration
	if (!ScmNewCellPositionCollide(*tmpFF)) {
		//no collision!, ok, return tmpFF as a FF
		//switch pointers in the tmpFF and FF structures
		i3d::Image3d<float> *fimg;
		fimg=tmpFF->x; tmpFF->x=FF.x; FF.x=fimg;
		fimg=tmpFF->y; tmpFF->y=FF.y; FF.y=fimg;
		fimg=tmpFF->z; tmpFF->z=FF.z; FF.z=fimg;

		//since this line was successful, advance to another one
		scmPnHints.SetOffset(i3d::Vector3d<float>(0.f,(float)(curPnTime+1),0.f));

		REPORT("good, non-rigid deformation does not cause a collision");
	}
#ifdef GTGEN_WITH_FLOWFIELDS
	else {
		//collision, zero/clear the flow field before it is saved
		//to show that this flow field was not applied in this run
		pnFF.x->GetVoxelData()=0.;
		pnFF.y->GetVoxelData()=0.;
		//note: this function assures the flow field is 3D...
		pnFF.z->GetVoxelData()=0.;
		DEBUG_REPORT("bad, had to skip/clear non-rigid deformation this time");
	}
#endif

	//clear tmpFF anyway, destructor will remove underline images
	delete tmpFF;

#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("forming resulting flow field and testing it took " << T2-T1 << " seconds");
#endif
#ifdef GTGEN_WITH_FLOWFIELDS
	//save the pnFF flow field images after "cropping it" to an export size
	//(do it after the time watch above...)
	//note: this function assures the flow field is 3D

	i3d::Image3d<float>* tmp=new i3d::Image3d<float>;
	//init it to overlay over scene mask exactly,
	//also allocates memory...
	tmp->CopyMetaData(*scheduler.sceneMasks[timePoint]);

	IMCopyFromVOI_t hints;
	IMCopyFromVOI_GetHints(*(pnFF.x),*(tmp),hints);

	//extract the flow fields
	const float zero=0.f;
	IMCopyFromVOI_Apply(*(pnFF.x),*(tmp),hints,&zero);

	pnFF.x->CopyMetaData(*tmp);
	IMCopyFromVOI_Apply(*(pnFF.y),*(pnFF.x),hints,&zero);

	pnFF.y->CopyMetaData(*tmp);
	IMCopyFromVOI_Apply(*(pnFF.z),*(pnFF.y),hints,&zero);

	delete pnFF.z;

	//rotate back
	pnFF.z=pnFF.y;
	pnFF.y=pnFF.x;
	pnFF.x=tmp;

	//prefix is the same as the one in Cell::ScmUniversalMovement()
	char ffNamePrefix[50];
	sprintf(ffNamePrefix, "ID%.2u_T%.3lu_FF", this->ID, this->timePoint);
	SaveFlowField(&pnFF,ffNamePrefix,"nonRigid", cellLookDistance);
#endif
}



// 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>;
