/*
        Triangle operations
*/
#include <graphics.h>
#include <float.h>
#include <math.h>

typedef struct {
        float row[3];
        float col[3];
	} triangle;

#include "fdesign.h"
#include "fdesequa.h"
#include "fdesfile.h"
#include "fdesmenu.h"
#include "fdesmous.h"
#include "fdesplot.h"

/*  ****************************************************************** */
int triangle_new(triangle *t,int tcolor)   /* input triangle coordinates from mouse */
{
int rcode;
mouse_state m;
	rcode = mouse_click_grat(&m);		/* point 1 of triangle */
	if (rcode&0x02) return(rcode);
        setcolor(tcolor);
        (*t).row[0] = m.row;
        (*t).col[0] = m.col;
	outtextxy(m.col,m.row,"A");
	mouse_click_grat(&m);		/* point 2 of triangle */
        (*t).row[1] = m.row;
        setcolor(tcolor);
	outtextxy(m.col,m.row,"B");
        (*t).col[1] = m.col;
        line((*t).col[0],(*t).row[0],(*t).col[1],(*t).row[1]);
	rcode = mouse_click_grat(&m);	/* point 3 of triangle */
        setcolor(tcolor);
        (*t).row[2] = m.row;
        (*t).col[2] = m.col;
	outtextxy(m.col,m.row,"C");
        line((*t).col[1],(*t).row[1],(*t).col[2],(*t).row[2]);
        line((*t).col[2],(*t).row[2],(*t).col[0],(*t).row[0]);
	return(rcode);
}

void triangle_show(triangle *t)
{
        line((*t).col[0],(*t).row[0],(*t).col[1],(*t).row[1]);
        outtextxy((*t).col[0],(*t).row[0],"A");
        line((*t).col[1],(*t).row[1],(*t).col[2],(*t).row[2]);
        outtextxy((*t).col[1],(*t).row[1],"B");
        line((*t).col[2],(*t).row[2],(*t).col[0],(*t).row[0]);
        outtextxy((*t).col[2],(*t).row[2],"C");
}

/*
	Distance of a point to a point
*/
float pt_pt_distance(float x1, float y1, float x2, float y2)
{
float d2;
	d2 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
	if (d2 == 0.0) return (0.0);
	else return (sqrt(d2));
}
/*
        Return closest triangle corner ( 0 1 or 2 )
*/
int triangle_corner(triangle *t, float col, float row)
{
float a,b,c;
	a = pt_pt_distance((*t).row[0],(*t).col[0],row,col);
	b = pt_pt_distance((*t).row[1],(*t).col[1],row,col);
	c = pt_pt_distance((*t).row[2],(*t).col[2],row,col);
        if ((a<b)&&(a<c)) return(0);
        if (b<c) return(1);
        else return(2);
}
/*
	Distance of a point to a line
*/
float pt_line_distance(float x, float y, float x1, float y1, float x2, float y2)
{
float a,b,e,c;
	if ((x==x1) && (y==y1)) a = 0.0;
	else a = sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
	if ((x==x2) && (y==y2)) b = 0.0;
	else b = sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2));
	if ((x1==x2) && (y1==y2)) e = 0.0;
	else e = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
	if (e != 0.0)
	{
		c = (b*b - a*a - e*e)/(-2*e);
		if ((a*a-c*c) < 0.0) return(0.0);
		else return(sqrt(a*a-c*c));
	}
	else
		return(a);
}
/*
	Distance of a point to a line SEGMENT
	(to locate nearest triangle edge)
*/
float pt_lines_distance(float x, float y, float x1, float y1, float x2, float y2)
{
float a,b,e,c;
	if ((x==x1) && (y==y1)) a = 0.0;
	else a = sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
	if ((x==x2) && (y==y2)) b = 0.0;
	else b = sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2));
	if ((x1==x2) && (y1==y2)) e = 0.0;
	else e = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
	if ((a*a + e*e) < (b*b)) return(a);
	if ((b*b + e*e) < (a*a)) return(b);
	if (e != 0.0)
	{
		c = (b*b - a*a - e*e)/(-2*e);
		if ((a*a-c*c) < 0.0) return(0.0);
		else return(sqrt(a*a-c*c));
	}
	else
		return(a);
}
float pt_triangle_distance(float x, float y, triangle *t)
{
float n1,n2,n3;
        n1 = pt_lines_distance(x,y,(*t).col[0],(*t).row[0],(*t).col[1],(*t).row[1]);
        n2 = pt_lines_distance(x,y,(*t).col[1],(*t).row[1],(*t).col[2],(*t).row[2]);
        n3 = pt_lines_distance(x,y,(*t).col[2],(*t).row[2],(*t).col[0],(*t).row[0]);
	if (n2 < n1) n1 = n2;
	if (n3 < n1) n1 = n3;
	return(n1);
}
/*
	Finds the triangle closest to the point specified.
	Returns the triangle number or -1 if the reference triangle.
*/
int pt_closest_triangle(float x, float y)
{
float dist[MAXFUNC];
float dist_ref;
int i;
int best_t;
	dist_ref = pt_triangle_distance(x,y,&triangle0);
/*	gotoxy(1,12); printf("%6f",dist_ref);
*/	for (i=0; i<num_triangles; i++)
	{
		dist[i] = pt_triangle_distance(x,y,&triangles[i]);
/*		printf(" %6f",dist[i]);
*/	}
	/* find minimum */
	best_t = 0;
	for (i=(num_triangles - 1); i>0; i--)
	{
		if (dist[i] < dist[0])
		{
			dist[0] = dist[i];
			best_t = i;
		}
	}

	if (dist_ref < dist[0]) return(-1);
	else return(best_t);
}
/*
	Find triangle area.
	Collapsed triangles (base or height = 0) will have an area assuming
	one pixel width (instead of zero).
*/
float triangle_area(triangle *t)
{
float base,height;
	/* area is 1/2 base times height */
        base = pt_pt_distance((*t).col[0],(*t).row[0],(*t).col[1],(*t).row[1]);
        height = pt_line_distance((*t).col[2],(*t).row[2],(*t).col[1],(*t).row[1],
                                (*t).col[0],(*t).row[0]);
        if (base < 1.0) return(5.0*height);  /* && 3.0 was 1.0 */
        else if (height < 1.0) return(5.0*base); /* && 3.0 was 1.0 */
	else return(0.5*base*height);
}

/************************************************************************
	Transformation Check if affine
************************************************************************/
int transform_affine(triangle *t)	/* return 0 if not affine */
{
float ra,rb,rc;
float a,b,c;
        ra = pt_pt_distance(triangle0.row[0],triangle0.col[0],
                            triangle0.row[1],triangle0.col[1]);
        rb = pt_pt_distance(triangle0.row[1],triangle0.col[1],
                            triangle0.row[2],triangle0.col[2]);
        rc = pt_pt_distance(triangle0.row[2],triangle0.col[2],
                            triangle0.row[0],triangle0.col[0]);
        a = pt_pt_distance((*t).row[0],(*t).col[0],(*t).row[1],(*t).col[1]);
        b = pt_pt_distance((*t).row[1],(*t).col[1],(*t).row[2],(*t).col[2]);
        c = pt_pt_distance((*t).row[2],(*t).col[2],(*t).row[0],(*t).col[0]);
	if (a > ra) return(0);
	if (b > rb) return(0);
	if (c > rc) return(0);
	if ((a == ra) && (b == rb) && (c == rc)) return(0);
	return(1);
}
/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        Find screen limits of Triangles
        (used to re-orient Triangles on screen)
   *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
void triangles_limits(float *left,float *up,float *right,float *down)
{

int i,j;
        *left = *right = triangle0.col[0];
        *up = *down = triangle0.row[0];

        for (i=0; i<3; i++)
        {
                if (triangle0.row[i] < *up) *up = triangle0.row[i];
                if (triangle0.row[i] > *down) *down = triangle0.row[i];
                if (triangle0.col[i] < *left) *left = triangle0.col[i];
                if (triangle0.col[i] > *right) *right = triangle0.col[i];
        }
        for (j=0; j<num_triangles; j++)
        {
                for (i=0; i<3; i++)
                {
                        if (triangles[j].row[i] < *up) *up = triangles[j].row[i];
                        if (triangles[j].row[i] > *down) *down = triangles[j].row[i];
                        if (triangles[j].col[i] < *left) *left = triangles[j].col[i];
                        if (triangles[j].col[i] > *right) *right = triangles[j].col[i];
                }
        }
}





