// FilterBarrel.cpp: implementation of the CFilterBarrel class.
//
//////////////////////////////////////////////////////////////////////

/** \file FilterBarrel.cpp
	\brief implementace třídy CFilterBarrel
*/

#include "stdafx.h"
#include "FilterBarrel.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
//#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//Defaultni konstruktor
CFilterBarrel::CFilterBarrel(float CameraFocus, float DistanceToCamera, const char* name, double param) 
	: CFilterBase(CameraFocus, DistanceToCamera, name)
{
	TRACE("-- Entering CFilterBarrel constructor --\n");

	m_paramBarrel = param;
	m_type = 1;
}

CFilterBarrel::~CFilterBarrel()
{
	TRACE("-- Entering CFilterBarrel destructor --\n");
	
	#ifdef _DEBUG
		Dump(afxDump);
	#endif // _DEBUG
}


//GetNextSize
CStructures::iPoint CFilterBarrel::GetNextSize() const
{
	TRACE("-- Entering CFilterBarrel::GetNextSize --\n");
	

	int i;
	CStructures::iPoint point, newPoint, currSize, nextSize;
	float lengthen;
	int xMax = 0, yMax = 0; //maximalni prirustky v x a y. Vzhledem k symetricnosti staci jen jedna strana
	
	//vrati aktualni rozmery filtru
	currSize = CFilterBase::GetSize();

	//prepocet sirky
	for(i = 0; i < (currSize.X / 2 + 1); i++)
	{
		point.X = i;
		point.Y = currSize.Y / 2;
		if(i == 50)
			int j = 6;
		//newDistance = GetDistanceToCenter(point) * (1 + __CParam * pow(GetDistanceToCenter(point), 2));
		if(point.X == 900)
			int hl = 7;

    //ru = rd + k1 rd3

		//newDistance = GetDistanceToCenter(point) + (1 +__CParam*GetDistanceToCenter(point));
		lengthen = GetDistanceToCenter(point) * m_paramBarrel;
		//Ratio = (float)(newDistance / oldDistance);
		newPoint.X = point.X * (1+lengthen);//floor((float)point.X * (1 - abs((float)__CParam*point.X) + 0.5));
		newPoint.Y = point.Y * (1+lengthen);//floor((float)point.Y * (1 - abs((float)__CParam*point.Y) + 0.5));
		if(newPoint.X > xMax)xMax = newPoint.X;
		if(newPoint.Y > yMax)yMax = newPoint.Y;
	}

	//prepocet vysky
	for(i = 0; i < (currSize.Y / 2 + 1); i++)
	{
		point.X = currSize.X / 2;
		point.Y = i;
		//newDistance = GetDistanceToCenter(point) * (1 + __CParam * pow(GetDistanceToCenter(point), 2));
		//newDistance = GetDistanceToCenter(point) * (1 +__CParam*GetDistanceToCenter(point));
		lengthen = GetDistanceToCenter(point) * m_paramBarrel;
		//Ratio = (float)(newDistance / oldDistance);		
		newPoint.X = point.X * (1+lengthen);//floor((float)point.X * (1 - abs((float)__CParam*point.X) + 0.5));
		newPoint.Y = point.Y * (1+lengthen);//floor((float)point.Y * (1 - abs((float)__CParam*point.Y) + 0.5));
		if(newPoint.X > xMax) xMax = newPoint.X;
		if(newPoint.Y > yMax) yMax = newPoint.Y;
	}

	nextSize.X = (2*(xMax+1));
	nextSize.Y = (2*(yMax+1));
	
	//__FilterWidth = (2*(((float)(xMax / prevDistance) * __DistanceToCamera)+1)); //Prepocet useku x`= (x/y * y`) na velikost ve vzdalenosti filtru
	//__FilterHeight = (2*(((float)(yMax / prevDistance) * __DistanceToCamera)+1)); //Prepocet useku x`= (x/y * y`) na velikost ve vzdalenosti filtru
	
	TRACE("Rozliseni nasledujiciho filtru: <%d x %d>\n", nextSize.X, nextSize.Y);

	return nextSize;
}



void CFilterBarrel::Transform(CPixelArray* pSource, CPixelArray* pTarget)
{
	TRACE("Entering CFilterBarrel::Transform\n");

	int x, y;
	int xMax, yMax;
	//float value;
	CStructures::ARGBPixel pixelValue;
	CStructures::iPoint point, size;
	CStructures::iPoint newPoint;
	float newDistance, lengthen;


	size = CFilterBase::GetSize();

	xMax = (size.X/2)-1;
	yMax = (size.Y/2)-1;

	long total = (size.X * size.Y)/100;
	long currPix = 0;

	
	TRACE("Processing CFilterBarrel... <%d x %d>\r\n",size.X, size.Y);	
	printf(" <%d x %d>\n",size.X, size.Y);	

	for(x = -xMax; x < xMax; x++)
		for(y = -yMax; y < yMax; y++)
		{
			point.X = x;
			point.Y = y;
			
			newDistance = GetDistanceToCenter(point)*(floor(GetDistanceToCenter(point) * (1 - fabs(m_paramBarrel*point.X) + 0.5)));
			lengthen = GetDistanceToCenter(point)*m_paramBarrel;

			if((point.X != 0)||(point.Y != 0))//Pokud jde o stred filtru, tak delime 0, tak nam vyjde NaN
			{
				newPoint.X =  point.X * (1+lengthen); //floor((float)Pixel.X * (1 - abs((float)__CParam*Pixel.X) + 0.5));
				newPoint.Y =  point.Y * (1+lengthen); //floor((float)Pixel.Y * (1 - abs((float)__CParam*Pixel.Y) + 0.5));
			}
			else
			{
				//Jsme ve stredu 
				newPoint.X = 0;
				newPoint.Y = 0;
			}


			//value = pSource->GetGrayPixel(newPoint);
			pixelValue = pSource->GetRGBPixel(newPoint);

			//pTarget->SetGrayPixel(point, value);
			pTarget->SetRGBPixel(point, pixelValue);

			currPix++;
			if((currPix % total) == 0) printf("\r%d%% done", currPix/total);
		}
		printf("\n");

//#ifdef _OPENCV
//	pTarget->Display("Barrel");
//#endif //_OPENCV

}


void CFilterBarrel::Show()
{
	CFilterBase::Show();
	cout << "Barrel parameter: " << m_paramBarrel << "\n";
}

//dumping objektu
#ifdef _DEBUG
void CFilterBarrel::Dump(CDumpContext& dc) const
{
	CFilterBase::Dump(dc);
	dc << "Barrel parameter: " << m_paramBarrel << "\n";
	
}
#endif // _DEBUG