// Line.cpp: implementation of the CLine class.
//
//////////////////////////////////////////////////////////////////////

/** \file Line.cpp
	\brief implementace třídy CLine
*/

#include "stdafx.h"
#include "Line.h"

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

IMPLEMENT_DYNAMIC(CLine, CPrimitiveBase)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
/*MR v příkladu se nepoužívá
CLine::CLine()
{
	TRACE("-- Entering CLine default constructor --\n");

	m_a = 0;
	m_b = 0;
	m_c = 0;

	m_thick = 0;
	m_begin.X = 0;
	m_begin.Y = 0;
	m_end.X = 0;
	m_end.Y = 0;

	m_type = 1;
}
*/
/*MR
CLine::CLine(int distance, CStructures::iPoint begin, CStructures::iPoint end, int Thick, CStructures::ARGBPixel ObjectColor, CStructures::ARGBPixel EnvColor, const char* title)
	:CPrimitiveBase(distance, ObjectColor, EnvColor, title)
{
	TRACE("-- Entering CLine RGB constructor --\n");

	CStructures::iPoint size;

	m_a = 0;  
	m_b = 0;
	m_c = 0;

	m_thick = Thick;
	m_begin = begin;
	m_end = end;

	m_XPeriodCount = -1;
	m_YPeriodCount = -1;


	m_type = 1;

	CreateLineImage();

	size = GetSize();
	m_XPeriod = size.X;
	m_YPeriod = size.Y;
}

*/
CLine::~CLine()
{
	TRACE("-- Entering CLine destructor --\n");

	#ifdef _DEBUG
		Dump(afxDump);
	#endif // _DEBUG
}

void CLine::CreateLineImage()
{
	TRACE("--- Entering CLine::CreateLineImage\n");

	//Osetreni platnosti zadani - 2 stejné body netvoří přímku
	if(!(m_begin.X == m_end.X && m_begin.Y == m_end.Y))
	{
		m_a = float(m_end.Y - m_begin.Y);
		m_b = m_begin.X - m_end.X;

		//smerovy vektor, dosadime jeden z bodu
		m_c = -m_a * m_begin.X - m_b * m_begin.Y; 

	}
	else
	{
		TRACE("Points are identical!\n");

		m_a = 0;
		m_b = 0;
		m_c = 0;
	}

	m_angle = GetAngleToYAxe();

	int difX, difY;
	int width, heigth;
	CStructures::fPoint center;

	difX = abs(m_begin.X - m_end.X);
	difY = abs(m_begin.Y - m_end.Y);

	if (m_angle <= 45)	//dominantni osa Y
	{
		//vypocet rozmeru vzoru
		width = abs(m_end.X - m_begin.X) + m_thick;
		heigth = abs(m_end.Y - m_begin.Y);
		SetSize(width, heigth);
	}
	else				//dominantni osa X
	{	
		//vypocet rozmeru vzoru
		width = abs(m_end.X - m_begin.X);
		heigth = abs(m_end.Y - m_begin.Y) + m_thick;
		SetSize(width, heigth);
	}

	/*take je zapotrebi urcit si nejaky stred pro trefovani se*/
	center.X = ((float)m_begin.X + m_end.X)/2;
	center.Y = ((float)m_begin.Y + m_end.Y)/2;
	CPrimitiveBase::SetLayerCenter(center);

}

double CLine::GetAngleToYAxe()
{
	TRACE("--- Entering CLine::GetAngleToYAxe --\n");

	double la, lb, lc;
	double angle;

	CStructures::iPoint lPoint1, lPoint2;
	lPoint1.X = 0;
	lPoint1.Y = -10;
	lPoint2.X = 0;
	lPoint2.Y = 10;
	
	la = lPoint2.Y - lPoint1.Y;
	lb = lPoint1.X - lPoint1.X;
	lc = -la * lPoint1.X - lb * lPoint1.Y; 
	
	angle = floor(((double)180/3.1415)* acos((la*m_a + lb*m_b) / (sqrt(la*la + lb*lb) * sqrt(m_a*m_a + m_b*m_b))));

	if (angle == 180)
		return 0;
	else
		return angle;
}

double CLine::GetPointDistance(CStructures::iPoint point)
{
	double distance;

	//Vzdalenost bodu od primky d = ax+by+c/SQRT(a^2+b^2)
	distance = (m_a*point.X + m_b*point.Y + m_c) / sqrt(pow(m_a,2) + pow(m_b,2));


	//vratime absolutni hodnotu protoze je nam jedno zda jsme vlevo ci vpravo
	return abs(distance); 
}

CStructures::ARGBPixel CLine::GetPixelValue(CStructures::iPoint position)
{
	//TRACE("-- Entering CLine::GetPixelValue --\n");
	
	CStructures::ARGBPixel pixel;
	double distance;
	CStructures::iPoint realPoint;

	//ziskani bodu v originalnim vzoru
	realPoint = GetRealPoint(position);

	//vzdalenost od primky, pokud nejsme mimo vzor
	if(!m_Overflow)
		distance = GetPointDistance(realPoint);


	if ((!m_Overflow) && (distance <= double(m_thick/2)))
		pixel = GetObjectColor(true);
	else
		pixel = GetObjectColor(false);

	return pixel;
}


//Vrati pozici pixelu v zakladnim vzoru
CStructures::iPoint CLine::GetRealPoint(CStructures::iPoint VirtualPosition)
{
	CStructures::iPoint point;
	CStructures::iPoint size;
	CStructures::fPoint lineCenter;
	float halfXsize, halfYsize;
	int Xrepeated = 0;
	int Yrepeated = 0;
	int XperiodCorrection = 0; 
	int YperiodCorrection = 0;
	m_Overflow = false;

	size = GetSize();
	lineCenter = GetCenter();

	halfXsize = (float)size.X/2;
	halfYsize = (float)size.Y/2;


	if(m_XPeriodCount > 0 || m_XPeriodCount == -1)	
		XperiodCorrection = (int)((m_XPeriod / 2) - halfXsize);	//Korekcni clen pro pripad opakovani v x-ove ose
	if(m_YPeriodCount > 0 || m_YPeriodCount == -1)
		YperiodCorrection = (int)((m_YPeriod / 2) - halfYsize);	//Korekcni clen pro pripad opakovani v y-ove ose


	if(VirtualPosition.X > lineCenter.X)
	{
		//pokud je pozadovany pixlik za rozmerem zakladniho vzoru vpravo
		while((lineCenter.X + halfXsize + XperiodCorrection ) < VirtualPosition.X)
		{
			//dokud se nedostaneme do zakladniho vzoru odecitame periodu opakovani
			VirtualPosition.X -= m_XPeriod;
			Xrepeated++;			
		}
	}
	else
	{
		//pokud je pozadovany pixlik za rozmerem zakladniho vzoru vlevo
		while((lineCenter.X - halfXsize - XperiodCorrection) > VirtualPosition.X)
		{
			//dokud se nedostaneme do zakladniho vzoru pricitame periodu opakovani
			VirtualPosition.X += m_XPeriod;
			Xrepeated++;
		}
	}


	if(VirtualPosition.Y > lineCenter.Y)
	{
		//pokud je pozadovany pixlik za rozmerem zakladniho vzoru nahore
		while((lineCenter.Y + halfYsize + YperiodCorrection) < VirtualPosition.Y)
		{
			//dokud se nedostaneme do zakladniho vzoru odecitame periodu opakovani
			VirtualPosition.Y -= m_YPeriod;
			Yrepeated++;
		}
	}
	else
	{
		//pokud je pozadovany pixlik za rozmerem zakladniho vzoru dole
		while((lineCenter.Y - halfYsize - YperiodCorrection) > VirtualPosition.Y)
		{
			//dokud se nedostaneme do zakladniho vzoru pricitame periodu opakovani
			VirtualPosition.Y += m_YPeriod;
			Yrepeated++;
		}
	}	


	point.X = VirtualPosition.X; //nastaveni x v zakladnim vzoru
	point.Y = VirtualPosition.Y; //nastaveni y v zakladnim vzoru

	//nekonecny pocet opakovani
	if(m_XPeriodCount == -1)
		Xrepeated = -1;

	if(m_YPeriodCount == -1)
		Yrepeated = -1;

	//oprava bugu pro rovnobeznost s osamy
	//s osou y
	if(m_angle == 0)
	{
		if((lineCenter.Y + halfYsize) < (abs(point.Y)))
			m_Overflow = true;
	}

	//s osou x
	if(m_angle == 90)
	{
		if((lineCenter.X + halfXsize) < (abs(point.X)))
			m_Overflow = true;
	}

	if((Xrepeated > m_XPeriodCount) || (Yrepeated > m_YPeriodCount)) 
		m_Overflow = true;		 //Pokud jsme prekrocili pocet opakovani nastavime priznak preteceni	
	
	return point;

}

void CLine::Translate(int dx, int dy)
{
	TRACE("-- Entering CLine::Translate --\n");

	m_begin.X += dx;
	m_begin.Y += dy;
	
	m_end.X += dx;
	m_end.Y += dy;

	//prepocet nove polohy
	CreateLineImage();
}

void CLine::Rotate(double gama)
{
	//TRACE("-- Entering CLine::Rotate --\n");

	CStructures::Angle angle;
	double rotX, rotY;
	double gama_rad;
	const double pi = 3.14159;

	gama_rad = pi/180*gama;

	//rotace pocatecni bodu
	rotX = cos(gama_rad)*m_begin.X - sin(gama_rad)*m_begin.Y;
	rotY = sin(gama_rad)*m_begin.X + cos(gama_rad)*m_begin.Y;

	m_begin.X = (int)rotX;
	m_begin.Y = (int)rotY;

	//rotace koncoveho bodu
	rotX = cos(gama_rad)*m_end.X - sin(gama_rad)*m_end.Y;
	rotY = sin(gama_rad)*m_end.X + cos(gama_rad)*m_end.Y;

	m_end.X = (int)rotX;
	m_end.Y = (int)rotY;

	//prepocet nove plohy
	CreateLineImage();

	angle = GetAngle();
	angle.gama = (float)gama;
	SetAngle(angle);

}

void CLine::Resample(CStructures::Supersample supersample)
{
	TRACE("Entering CLine::Resample\n");

	m_begin.X = m_begin.X * supersample.X;
	m_begin.Y = m_begin.Y * supersample.Y;

	m_end.X = m_end.X * supersample.X;
	m_end.Y = m_end.Y * supersample.Y;
	
	m_thick = m_thick * supersample.X;

	m_XPeriod = m_XPeriod * supersample.X;
	m_YPeriod = m_YPeriod * supersample.Y;

	CreateLineImage();
}

//dumping objektu
#ifdef _DEBUG
void CLine::Dump(CDumpContext& dc) const
{
	CPrimitiveBase::Dump(dc);
	dc << "Begin point X = " << m_begin.X <<
		"\n            Y = " << m_begin.Y <<
		"\nEnd point X= " << m_end.X <<
		"\n          Y= " << m_end.Y <<
		"\nThick: " << m_thick << 
		"\nKoeficients a = " << m_a <<
		"\n            b = " << m_b << 
		"\n            c = " << m_c << 
		"\nAngle to Y: " << m_angle << "\n\n";  
}
#endif // _DEBUG