/***************************************************************************
                          coordinates.cpp  -  description
                             -------------------
    begin                : Sam Mai  5 13:46:33 CEST 2001
    copyright            : (C) 2001 by
    email                :
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <kdebug.h>

#include"coordinates.h"
#define	desk KApplication::desktop()

Coordinates::Coordinates()
{
	d_x = 0;
	d_y = 0;
	i_x = round( d_x );
	i_y = round( d_y );
}

Coordinates::Coordinates( double x,double y )
{
	d_x = x;
	d_y = y;
	i_x = round( d_x );
	i_y = round( d_y );
}

Coordinates::Coordinates( QPoint pt )
{
	d_x = pt.x();
	d_y = pt.y();
	i_x = round( d_x );
	i_y = round( d_y );
}

Coordinates::Coordinates( const Coordinates & coords )
{
	d_x = coords.getD_X();
	d_y = coords.getD_Y();
	i_x = round( d_x );
	i_y = round( d_y );
}

Coordinates::~Coordinates()
{
}

int Coordinates::getI_X()
{
	return i_x;
}

int Coordinates::getI_Y()
{
	return i_y;
}

double Coordinates::getD_X() const
{
	return d_x;
}

double Coordinates::getD_Y() const
{
	return d_y;
}

QString Coordinates::getD_Y( int mant )
{
	//	Round result. 10 * because QPoint doesn't take real
	double round = QString().setNum( d_y, 'f', mant ).toDouble();

	if ( round == 0 )
	{
		round = 0;
	}

	QString roundString = QString().setNum( round, 'f', mant );

	return roundString;
}

QString Coordinates::getD_X( int mant )
{
	//	Round result. 10 * because QPoint doesn't take real
	double round = QString().setNum( d_x, 'f', mant ).toDouble();

	if ( round == 0 )
	{
		round = 0;
	}

	QString roundString = QString().setNum( round, 'f', mant );

	return roundString;
}

QPoint Coordinates::getQPoint()
{
	return QPoint( getI_X(), getI_Y() );
}

void Coordinates::setX( double x )
{
	d_x = x;
	i_x = round( x );
}

void Coordinates::setY( double y )
{
	d_y = y;
	i_y = round( y );
}

void Coordinates::set( double x, double y )
{
	d_x = x;
	d_y = y;
	i_x = round( x );
	i_y = round( y );
}

void Coordinates::set( QPoint & pt )
{
	d_x = pt.x();
	d_y = pt.y();
	i_x = round( d_x );
	i_y = round( d_y );
}

void Coordinates::invertX()
{
	d_x *= -1;
	i_x = round( d_x );
}

void Coordinates::invertY()
{
	d_y *= -1;
	i_y = round( d_y );
}

void Coordinates::move( double x, double y )
{
	d_x += x;
	d_y += y;
	i_x = round( d_x );
	i_y = round( d_y );
}

void Coordinates::rotate( Coordinates coord1, double angle )
{
	//	Move coord1 to center
	*this -= coord1;
	invertY();

	//	Convert angle from deg to rad
	angle /= 360;
	angle *= 2 * PI;

	double x = ( getD_X() * cos( - angle ) ) + ( getD_Y() * sin( - angle ) );
	double y = ( - getD_X() * sin( - angle ) ) + ( getD_Y() * cos( - angle ) );
	d_x = x;
	d_y = y;
	i_x = round( d_x );
	i_y = round( d_y );

	invertY();
	*this += coord1;
}

void Coordinates::normalize( double x )
{
	double length	=	sqrt( pow( d_x, 2 ) + pow( d_y, 2 ) );

	if ( length != 0 )
	{
		d_x	/= length;
		d_x *= x;
		d_y	/= length;
		d_y *= x;

		i_x = round( d_x );
		i_y = round( d_y );
	}
}

void Coordinates::setLength( double x )
{
	double length	=	sqrt( pow( d_x, 2 ) + pow( d_y, 2 ) );

	if ( length != 0 )
	{
		d_x	/= length;
		d_x *= x;
		d_y	/= length;
		d_y *= x;

		i_x = round( d_x );
		i_y = round( d_y );
	}
}

double Coordinates::orientation( Coordinates coord1, Coordinates coord2 )
{
   // This method determines whether *this is on, left or right of the
   // line defined by coord1 and coord2. This test is done by evaluating
   // the sign of a determinant that looks as follows (a, b, c are points):
   // |ax ay 1|
   // |bx by 1| = 0 (c on the line), > 0 (left of line), < 1 (right of line)
   // |cx cy 1|

   Coordinates coord3, coord4;
   coord3 = coord1 - *this;
   coord4 = coord2 - *this;

   double orient;
   orient =  coord3.getD_X() * coord4.getD_Y();
   orient -= coord3.getD_Y() * coord4.getD_X();

   return orient;
}

double Coordinates::getLength()
{
	double length	=	sqrt( pow( d_x, 2 ) + pow( d_y, 2 ) );

	return length;
}

double Coordinates::getAngleDeg( Coordinates coord1, Coordinates coord2 )
{
  double pi = 3.1415926536;
	double angle = getAngleRad( coord1, coord2 );
  angle = (angle / (pi * 2))*360;

	return angle;
}

double Coordinates::getAngleRad( Coordinates coord1, Coordinates coord2 )
{
   // This method returns the angle that the three points determine in rad.
   // *this is the middle point and orientation is counter-clockwise from
   // coord1 to coord2.
//   coord1.setY( coord1.getD_Y() * (-1) );
//   coord2.setY( coord2.getD_Y() * (-1) );
   double pi = 3.14159;

   // First, test whether all points lie on one line using Coordinates::orientation,
   // because this means .
   double orient = coord2.orientation( *this, coord1 );
   if ( orient == 0 )
   {
      // This can now mean pi or zero rad.
      Coordinates coord6;
      coord6 = coord1 - coord2;
      if ( ( (*this - coord1).getLength() < coord6.getLength() ) &&
           ( (*this - coord2).getLength() < coord6.getLength() ) )
      {
         return pi;
      }
      else
      {
         return 0;
      }
   }

   // Now, we can be sure that our algorithm works: We construct a triangle which
   // has two equally long sides and calculates half of the smaller angle.
   Coordinates coord3, coord4, coord5;
   double x, y, angle;

   coord3 = coord1 - *this;
   coord4 = coord2 - *this;

   y = coord3.getLength();
   coord4.normalize( y );
   coord5 = coord3 - coord4;
	 coord5 /= 2;

   x = coord5.getLength();
   angle = asin( x / y );
   angle *= 2;

   // Well, is this the correct angle or is it the one on the other side?
   // Use the orientation test again, this time locate coord2. If it is on
   // the right of ( *this; coord1 ) we have to take the other angle:
   if ( orient < 0 )
   {
      angle = ( 2 * pi ) - angle;
   }

   return angle;
}

double Coordinates::getDistance( Coordinates coords )
{
	Coordinates dist;
	dist = coords - *this;

	return dist.getLength();
}

void Coordinates::orthogonalize()
{
	double temp = d_x;
	d_x = -d_y;
	d_y = temp;

	i_x = round( d_x );
	i_y = round( d_y );
}

void Coordinates::show()
{
	kdDebug() << "*******************************" << endl;
	kdDebug() << " Double values:" << endl;
	kdDebug() << " x = " << d_x << endl;
	kdDebug() << " y = " << d_y << endl << endl;
	kdDebug() << " Integer values: " << endl;
	kdDebug() << " x = " << i_x << endl;
	kdDebug() << " y = " << i_y << endl;
	kdDebug() << "*******************************" << endl;
}

bool	Coordinates::isValid()
{
	if ( ( d_x >= 0 ) &&
			 ( d_y >= 0 ) &&
			 ( d_x <= desk->width() ) &&
			 ( d_y <= desk->height() ) )
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool	Coordinates::isHorizontal( Coordinates & coords )
{
	if ( d_y == coords.getD_Y() )
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool	Coordinates::isVertical( Coordinates & coords )
{
	if ( d_x == coords.getD_X() )
	{
		return true;
	}
	else
	{
		return false;
	}
}

void Coordinates::operator=( Coordinates coords )
{
	d_x = coords.getD_X();
	d_y = coords.getD_Y();
	i_x = round( d_x );
	i_y = round( d_y );
}

Coordinates Coordinates::operator+( Coordinates coords )
{
	Coordinates ret( d_x + coords.getD_X(), d_y + coords.getD_Y() );
	return ret;
}

Coordinates Coordinates::operator-( Coordinates coords )
{
	Coordinates ret( d_x - coords.getD_X(), d_y - coords.getD_Y() );
	return ret;
}

Coordinates Coordinates::operator*( double x )
{
	Coordinates ret( d_x * x, d_y * x );
	return ret;
}

Coordinates Coordinates::operator/( double x )
{
	Coordinates ret( d_x / x, d_y / x );
	return ret;
}

Coordinates Coordinates::operator+=( Coordinates coords )
{
	d_x += coords.getD_X();
	d_y += coords.getD_Y();
	i_x = round( d_x );
	i_y = round( d_y );
	Coordinates ret( d_x, d_y );
	return ret;
}

Coordinates Coordinates::operator-=( Coordinates coords )
{
	d_x -= coords.getD_X();
	d_y -= coords.getD_Y();
	i_x = round( d_x );
	i_y = round( d_y );
	Coordinates ret( d_x, d_y );
	return ret;
}

Coordinates Coordinates::operator*=( double x )
{
	d_x *= x;
	d_y *= x;
	i_x = round( d_x );
	i_y = round( d_y );
	Coordinates ret( d_x, d_y );
	return ret;
}

Coordinates Coordinates::operator/=( double x )
{
	d_x /= x;
	d_y /= x;
	i_x = round( d_x );
	i_y = round( d_y );
	Coordinates ret( d_x, d_y );
	return ret;
}

bool Coordinates::operator==( Coordinates coords )
{
	return ( ( d_x == coords.getD_X() ) && ( d_y == coords.getD_Y() ) );
}

bool Coordinates::operator!=( Coordinates coords )
{
	return ! ( ( d_x == coords.getD_X() ) && ( d_y == coords.getD_Y() ) );
}

int Coordinates::round( double x )
{
	bool minus = false;

	if ( x < 0 )
	{
		x = -x;
		minus = true;
	}

	int i = ( int ) x;	//	Cut off digits after comma
	double d = x - (double) i ;

	if ( d >= 0.5 )
	{
		i += 1;
	}
	return ( minus ? -i : i );
}

