/*
*	Yamana's Otomeza Plug-in Tool
*		スプライン曲線
*	
*	1995.08.20	２次関数を用いた補完
*	1995.08.27	スプライン法に変更
*	
*	問題点
*	・汚いソースである(^^;)
*	
*/
#include	"otome_pi.h"

const char longname[] = "DRAW  : スプライン曲線";
int			cnfg_max = 1;
PI_CNFG		cnfg[] = {
				{"線の太さ"		, 1, 32,  1,  1 }
			};

#define	USE_ENV		PI_SET_ENV
#define	USE_TYPE	PI_EFFC_POLY
#include	"otome_pi.c"

typedef struct
	{
		short	x,y;
		
	}Points;

/*******************************************************/

int num;

int mk_spTbl( x,y,f )
double	*x,*f;
int 	*y;
{
	int 	i;
	double	t,*h,*d;
	
	if( (h=(double *)PI_MALLOC( sizeof(double)*num*2 ))==NULL )
		return ERROR;
	d = &h[ num ];
	
	f[0] = f[num-1] = 0;
	for( i=0; i<num-1; i++ )
	{
		h[i  ] = (x[i+1] - x[i]);
		d[i+1] = (y[i+1] - y[i]) / h[i];
	}
	
	f[1] =  d[2] - d[1];
	d[1] = (x[2] - x[0])*2 ;
	for( i=1; i<num-2; i++ )
	{
		t = (h[i] / d[i]);
		f[i+1] = (d[i+2] - d[i+1])   - f[i] * t;
		d[i+1] = (x[i+2] - x[i  ])*2 - h[i] * t;
	}
	f[num-2] -= h[num-2]*f[num-1];
	for( i=num-2; i>0; i-- )
		f[i] = (f[i] - h[i] * f[i+1]) / d[i];
	
	return NOERR;
}

int 	get_sp( t,x,y,f )
double	*x,*f;
int 	t,*y;
{
	int 	i,j,k;
	int 	d,h;
	
	i=0,j=num-1;
	while( i<j )
	{	k = (i+j)/2;
		if( x[k] < t )	i = k+1;
				else	j = k;
	}
	if( i>0 )	i--;
	
	h = (x[i+1] - x[i]);
	d = (   t   - x[i]);
	
	return (
			  ((f[i+1] - f[i])* d * 256 / h +  f[i] * 3 *256 ) * d
			+ ((y[i+1] - y[i])    * 256 / h - (f[i] * 2 + f[i+1])* h*256 )
		) * d /256 + y[i];
	
}

int spline( pp )
Points	*pp;
{
	int 	i;
	int 	x0,y0,x1,y1,step;
	int 	t0,t1,*x,*y;
	double	*l,*a,*b;
	
	LINE	line;
	line.n = 2;
	
	/* double=64bit,int=32bit */
	if( (l=(double *)PI_MALLOC( sizeof(double)*num*4 ))==NULL )
		return PI_ERROR_NO_MEMORY;
	a = &l[num];
	b = &a[num];
	x = (int*)&b[num];
	y = (int*)&x[num];
	
	for( i=0; i<num ; i++)
	{	x[i] = pp[i].x;
		y[i] = pp[i].y;
	}
	l[0] = 0;
	for( i=1; i<num; i++ )	/* 始点からの総距離 */
	{	t0 = x[i] - x[i-1];
		t1 = y[i] - y[i-1];
		l[i] = l[i-1] + (int)sqrt( t0*t0 + t1*t1 );
	}
	mk_spTbl( l, x, a );
	mk_spTbl( l, y, b );
	
	/* 速度と精度のバランスをうまく取りたい(^^;) */
	step = l[num-1]/128;
	for( i=256; (t0=l[num-1]/i)>0 ; i*=2 )
		step -= t0;
	if( step <= 0 )	step  = 2;
			else	step *= 2;
	
	x0 = get_sp( 0, l, x, a );
	y0 = get_sp( 0, l, y, b );
	
	for( i=1 ; i<=l[num-1] ; i+=step )
	{	x1 = get_sp( i, l, x, a );
		y1 = get_sp( i, l, y, b );
		
		line.x0 = x0;
		line.y0 = y0;
		line.x1 = x1;
		line.y1 = y1;
		EGB_connect( EgbPtr, &line );
		
		x0=x1,y0=y1;
	}
	if( i-step < l[num-1] )
	{	i = l[num-1];
		x1 = get_sp( i, l, x, a );
		y1 = get_sp( i, l, y, b );
		
		line.x0 = x0;
		line.y0 = y0;
		line.x1 = x1;
		line.y1 = y1;
		EGB_connect( EgbPtr, &line );
	}
sp_end:
	PI_FREE( l );
	
	return NOERR;
}


/*************************************/

int APL_exec()
{
	int 	pen;
	
	pen  = cnfg[0].val;
	
	EGB_writePage( EgbPtr, PI_PAGE );
	EGB_writeMode( EgbPtr, EGB_PSET );
	
	/* タイル指定を有効に */
	if( PI_TILEFLG )
	{	EGB_tilePattern( EgbPtr, EGB_FORECOL,
					PI_TILE_X, PI_TILE_Y, PI_TILE_PAT );
		EGB_paintMode( EgbPtr, EGB_PAINT_TILE );
	}else
	{	EGB_color( EgbPtr, EGB_FORECOL,  PI_FORECOL );
		EGB_paintMode( EgbPtr, EGB_PAINT_BETA );
	}
	EGB_penSize( EgbPtr, pen );
	
	/****/
	
	num = WORD( g_para );
	return spline( (Points *)(g_para+2) );
	
}

