#include "edge.h"
////////////////////////////////////////////////////////////////////////
//
// edge.cpp
//
///////////////////////////////////////////////////////////////////////
//
// TriArea:  returns area af triangle abc by determinant calculation
//
 
float TriArea( Vertex* a, Vertex* b, Vertex* c ){

return (((b->x - a->x) * (c->y - a->y)) - 
		((c->x - a->x) * (b->y - a->y))) / 2.0;
}
///////////////////////////////////////////////////////////////////////
//
// Left: return true if c is left of ab
//

bool Left( Vertex* a, Vertex* b, Vertex* c ){

return TriArea( a, b, c ) > 0.0;
}
///////////////////////////////////////////////////////////////////////
// 
// Colinear: return true if a b and c are Colinear
//
 
bool Colinear( Vertex* a, Vertex* b, Vertex* c ){

return TriArea( a, b, c ) == 0.0;
}
//////////////////////////////////////////////////////////////////////

Edge::Edge( float a, float b, float c, float d ){

v1 = new Vertex( a, b ); 
v2 = new Vertex( c, d );
color = 56;
}
/////////////////////////////////////////////////////////////////////////

Edge::Edge( Vertex* v, Vertex* w ){

v1 = new Vertex( v );
v2 = new Vertex( w );
}
//////////////////////////////////////////////////////////////////////
//
// translate this by v

void Edge::Add( Vertex* v ){

	v1->Add( v );
	v2->Add( v );
}

//////////////////////////////////////////////////////////////////////
//
// is edge inside the world
 
int Edge::CheckBounds( void ){

	int cb1, cb2;

if( (cb1 = v1->CheckBounds()) > -1 ) return  cb1;
if( (cb2 = v2->CheckBounds()) > -1 ) return  cb2;
return -1;
}

//////////////////////////////////////////////////////////////////////
//
// Intersection: return true if this edge and the_other edge intersect.
// 

bool Edge::bIntersection( Edge* the_other ){

Vertex* a = this->v1;
Vertex* b = this->v2;
Vertex* c = the_other->v1;
Vertex* d = the_other->v2;

if( !Colinear( a, b, c ) && !Colinear( a, b, d ) && 
	!Colinear( c, d, a ) && !Colinear( c, d, b ) ){

	// intersection if c is left of ab and d is right of ab 
	// (and vice versa) and a is left of cd and b is right of cd
	// (and vice versa)
	// ^ = xor operator
	return (Left( a, b, c ) ^ Left( a, b, d )) && 
		   (Left( c, d, a ) ^ Left( c, d, b ));

}else return false;		
}
//////////////////////////////////////////////////////////////////////////

void Edge::Rotate( Vertex* p, double theta ){

this->v1->Rotate( p, theta );
this->v2->Rotate( p, theta );
}

/////////////////////////////////////////////////////////////////////////


void Edge::Draw( UCHAR* canvas ){

int x1 = v1->x;
int x2 = v2->x;
int y1 = v1->y;
int y2 = v2->y;

Draw_Line( x1, y1, x2, y2, color, canvas, ddsd.lPitch );
}

///////////////////////////////////////////////////////////////////////////////

double Edge::Angle( Edge* other ){

double a;

this->v2->Sub( this->v1 );
other->v2->Sub( other->v1 );
 
a = acos( this->v2->Dot( other->v2 ) / (this->v2->Norm() * other->v2->Norm()) );

this->v2->Add( this->v1 );
other->v2->Add( other->v1 );

return a;  
}
///////////////////////////////////////////////////////////////////////////////

void Edge::Equation( void ){

if( v1->x == v2->x ){
	
	slope_dne = true;

}else{

	slope_dne = false;
	
	v2->Sub( v1 );
	
	slope = v2->y / v2->x;

	v2->Add( v1 );

	y_intercept = v2->y - (slope * v2->x);
		
	equation[0] = slope;
	equation[1] = -1;
	equation[2] = -y_intercept;
}}

///////////////////////////////////////////////////////////////////////////////

void Edge::CopyEquation( double eq[] ){

memcpy( eq, equation, sizeof( double ) * 3 );
}

///////////////////////////////////////////////////////////////////////////////
// 
// returns the point at which two edges intersect
//

Vertex* Edge::vIntersection( Edge* the_other ){
	
//get the coefficients of this' and the other's equation 
this->Equation();
the_other->Equation();

// if the slopes do not exist, there is no intersection
if( this->slope_dne && the_other->slope_dne ) return NULL; 

// if the lines are parallel there is no intersection
else if( this->slope == the_other->slope ) return NULL;

// a lot of other special cases to handle
else if( this->slope_dne ){

    if( the_other->slope == 0.0 ){
	
		return new Vertex( this->v1->x, the_other->v1->y );
	}
	return new Vertex( this->v1->x, (the_other->slope * this->v1->x) + the_other->y_intercept );

}else if( the_other->slope_dne ){

    if( this->slope == 0.0 ){
	
		return new Vertex( the_other->v1->x, this->v1->y );
	}
    return new Vertex( the_other->v1->x, (this->slope * the_other->v1->x) + this->y_intercept );

}else if( this->slope == 0.0 ){

	return new Vertex( (this->v1->y - the_other->y_intercept) * the_other->slope, this->v1->y );

}else if( the_other->slope == 0.0 ){

	return new Vertex( (the_other->v1->y - this->y_intercept) * this->slope, the_other->v1->y );

}else{

	// no more special cases
	return Gauss_Jordan_2( this->equation, the_other->equation );
}}

/////////////////////////////////////////////////////////////////////////////////
//
// a kludgey implementation of Gauss-Jordan elimination that
// only works for two equations and two unknowns
//
// input  : two coefficient vectors ( equations of lines )
// output : the two solutions in a Vertex object
//
// this function assumes that the system is solvable
  
Vertex* Gauss_Jordan_2( double eq1[], double eq2[] ){

int row, pivot, col;
double mat[2][3];
double d, m;

memcpy( mat[0], eq1, sizeof( double ) * 3 );
memcpy( mat[1], eq2, sizeof( double ) * 3 );

for( row = 0; row < 2; row++ ){

	pivot = 1 - row;
	d = mat[row][row];

	for( col = 0; col < 3; col++ ){
	
		mat[row][col] /= d;
	}
	m = -mat[pivot][row];

	for( col = 0; col < 3; col++ ){
	
		mat[pivot][col] += m * mat[row][col];
	}
}
return new Vertex( mat[0][2], mat[1][2] );
}