/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/



#include	<stdlib.h>
#include	<math.h>
#include	"gbgraph.h"

int
check_fnan(REAL1 f)
{
int a;
	a = *(int*)&f;
	switch ( a ) {
	case 0x7f800000:
	case 0xff800000:
	case 0xffffffff:
	case 0x7fffffff:
	case 0x7fffff:
		return -1;
	}
	return 0;
}


GB_POINT p_sub(GB_POINT p1,GB_POINT p2)
{
GB_POINT ret;
	ret.x = p1.x-p2.x;
	ret.y = p1.y-p2.y;
	return ret;
}

GB_POINT p_add(GB_POINT p1,GB_POINT p2)
{
GB_POINT ret;
	ret.x = p1.x+p2.x;
	ret.y = p1.y+p2.y;
	return ret;
}



GB_POINT mp_mul(REAL1 m[2][2],GB_POINT p)
{
GB_POINT ret;
	ret.x = m[0][0]*p.x + m[0][1]*p.y;
	ret.y = m[1][0]*p.x + m[1][1]*p.y;
	return ret;
}

void
m_mul(REAL1 res[2][2],REAL1 m1[2][2],REAL1 m2[2][2])
{
int i,j,k;
double acc;
	for ( i = 0 ; i < 2 ; i ++ )
		for ( j = 0 ; j < 2 ; j ++ ) {
			acc = 0;
			for ( k = 0 ; k < 2 ; k ++ )
				acc += m1[i][k] * m2[k][j];
			res[i][j] = acc;
		}
}

GB_POINT caffen2d(AFFEN2D * a,GB_POINT p)
{
GB_POINT ret;
	ret.x = a->matrix[0][0]*p.x +
		a->matrix[0][1]*p.y +
		a->org.x;
	ret.y = a->matrix[1][0]*p.x +
		a->matrix[1][1]*p.y +
		a->org.y;
	return ret;
}



void
conv_affen2d(AFFEN2D * res,AFFEN2D * a,AFFEN2D * b)
{
	m_mul(res->matrix,a->matrix,b->matrix);
	res->org = p_add(mp_mul(a->matrix,b->org),a->org);
}


int
inside_rect(GB_RECT * r,GB_POINT p)
{
	if ( r->tl.x > r->br.x )
		return 1;
	if ( r->tl.y > r->br.y )
		return 1;
	if ( r->tl.x > r->br.x )
		return 1;
	if ( r->tl.y > r->br.y )
		return 1;
	if ( r->tl.x > p.x )
		return 0;
	if ( r->tl.y > p.y )
		return 0;
	if ( r->br.x < p.x )
		return 0;
	if ( r->br.y < p.y )
		return 0;
	return 1;
}

void
insert_rect(GB_RECT * r,GB_POINT p)
{
	if ( r->tl.x > r->br.x ) {
		r->tl = r->br = p;
		return;
	}
	if ( r->tl.x > p.x )
		r->tl.x = p.x;
	if ( r->tl.y > p.y )
		r->tl.y = p.y;
	if ( r->br.x < p.x )
		r->br.x = p.x;
	if ( r->br.y < p.y )
		r->br.y = p.y;
	return;
}

REAL1
distance(GB_POINT p1,GB_POINT p2)
{
GB_POINT p;
	p = p_sub(p1,p2);
	return sqrt(p.x*p.x + p.y*p.y);
}

int
cross_rect_circle(GB_RECT * rect,GB_POINT p,REAL1 r)
{
GB_POINT tmp;
	if ( rect->tl.x > rect->br.x )
		return 1;
	if ( rect->tl.y > rect->br.y )
		return 1;
	if ( inside_rect(rect,p) )
		return 1;
	if ( rect->tl.x <= p.x && rect->br.x >= p.x ) {
		if ( fabs(p.y-rect->tl.y) <= r )
			return 1;
		if ( fabs(p.y-rect->br.y) <= r )
			return 1;
		return 0;
	}
	else if ( rect->tl.y <= p.y && rect->br.y >= p.y ) {
		if ( fabs(p.x-rect->tl.x) <= r )
			return 1;
		if ( fabs(p.x-rect->br.x) <= r )
			return 1;
		return 0;
	}
	else if ( rect->tl.x > p.x && rect->tl.y > p.y ) {
		if ( distance(p,rect->tl) < r )
			return 1;
		else	return 0;
	}
	else if ( rect->tl.x > p.x && rect->br.y < p.y ) {
		tmp.x = rect->tl.x;
		tmp.y = rect->br.y;
		if ( distance(p,tmp) < r )
			return 1;
		else	return 0;
	}
	else if ( rect->br.x < p.x && rect->tl.y > p.y ) {
		tmp.x = rect->br.x;
		tmp.y = rect->tl.y;
		if ( distance(p,tmp) < r )
			return 1;
		else	return 0;
	}
	else {
		if ( distance(p,rect->br) < r )
			return 1;
		else	return 0;
	}
}

void
add_rect(GB_RECT * r1,GB_RECT * r)
{
	if ( r1->tl.x > r1->br.x ) {
		*r1 = *r;
		return;
	}
	if ( r1->tl.x > r->tl.x )
		r1->tl.x = r->tl.x;
	if ( r1->tl.y > r->tl.y )
		r1->tl.y = r->tl.y;
	if ( r1->br.x < r->br.x )
		r1->br.x = r->br.x;
	if ( r1->br.y < r->br.y )
		r1->br.y = r->br.y;
	return;
}

int
cross_rect_rect(GB_RECT * r1,GB_RECT * r2)
{
	if ( r1->tl.x <= r2->br.x && r1->br.x >= r2->tl.x &&
		r1->tl.y <= r2->br.y && r1->br.y >= r2->tl.y )
		return 1;
	return 0;
}

int
check_nan_rect(GB_RECT * r1)
{
	if ( r1->tl.x > r1->br.x )
		return 1;
	if ( r1->tl.y > r1->br.y )
		return 1;
	return 0;
}

int
cross_rect_triangle(GB_RECT * r1,GB_POINT tri[3])
{
GB_POINT p;
	if ( inside_rect(r1,tri[0]) == 1 )
		return 1;
	if ( inside_rect(r1,tri[1]) == 1 )
		return 1;
	if ( inside_rect(r1,tri[2]) == 1 )
		return 1;
	if ( inside_triangle(tri,r1->tl) == 0 )
		return 1;
	if ( inside_triangle(tri,r1->br) == 0 )
		return 1;
	p.x = r1->tl.x;
	p.y = r1->br.y;
	if ( inside_triangle(tri,p) == 0 )
		return 1;
	p.x = r1->br.x;
	p.y = r1->tl.y;
	if ( inside_triangle(tri,p) == 0 )
		return 1;
	return 0;
}

void
rect2circle(GB_POINT * center,REAL1 * radius,GB_RECT * r)
{
REAL1 xx,yy;
	center->x = (r->tl.x + r->br.x)/2;
	center->y = (r->tl.y + r->br.y)/2;
	xx = r->tl.x - r->br.x;
	yy = r->tl.y - r->br.y;
	*radius = sqrt(xx*xx + yy*yy)/2;
}


REAL1
inner(GB_POINT a,GB_POINT b)
{
	return a.x*b.x + a.y*b.y;
}


void
intersection_rect(GB_RECT * r,GB_RECT * r1,GB_RECT * r2)
{
GB_RECT ret;
	if ( r1->tl.x > r1->br.x || r1->tl.y > r1->br.y ) {
		*r = *r2; 
		return;
	}
	if ( r2->tl.x > r2->br.x || r2->tl.y > r2->br.y ) {
		*r = *r1; 
		return;
	}
	if ( r1->tl.x < r2->tl.x )
		ret.tl.x = r2->tl.x;
	else	ret.tl.x = r1->tl.x;
	if ( r1->tl.y < r2->tl.y )
		ret.tl.y = r2->tl.y;
	else	ret.tl.y = r1->tl.y;
	if ( r1->br.x < r2->br.x )
		ret.br.x = r1->br.x;
	else	ret.br.x = r2->br.x;
	if ( r1->br.y < r2->br.y )
		ret.br.y = r1->br.y;
	else	ret.br.y = r2->br.y;
	*r = ret;
}




REAL1
rect_resolution(GB_RECT * r,REAL1 dist,int num)
{
double w,h,reso2,reso1;
	w = r->br.x - r->tl.x;
	h = r->br.y - r->tl.y;
	if ( w < h )
		reso1 = 1/w;
	else	reso1 = 1/h;
	reso2 = dist/sqrt(h*w/num);
	if ( reso2 < reso1 )
		return reso1;
	return reso2;
}

