#include<graphics.h>  /*图形系统头文件*/
#include<conio.h>
#include<dos.h>
#include<math.h>
#include<bios.h>      /*控制方向键头文件*/
#include<stdlib.h>

#define PI 3.1415926


int A=50;
float w=0.2;
static double yy=0.0,xx=0.0;
char ch;

void convey()        /*轨迹方程函数*/
{ 
	xx=xx+10.0;
	yy=200-A*sin(w*xx);
	if(xx>=500&&yy>=400) {xx=10.0;yy=0.0;}  /*设置球体运动的最大坐标*/
	return;
}



void quittime01(int t2)  /*按↑键加速球体运动*/
{ 
	int t3;t3=t2;
	delay(10000-200*t3);
	return;
}

void quittime02(int t4)   /*按↓键减速球体运动*/
{
	int t5;t5=t4;
	delay(20000+200*t5);
	return;
}

void keyboard(int t1)      /*定义判断是否按键控制速度函数*/
{
	int t2,t4;

	if (kbhit())              /*判断是否按方向键*/ 
	{
		ch=getch();
		switch(ch)
		{
		case 72: 
			t2=t1;
			quittime01(t2);  /*调用quittime01()函数*/
			return; 
		case 80: 
			t4=t1;
			quittime02(t4);
			return;
		default:
			break;
		}
	}
	else
	{ 
		delay(10000);
		return;
	}
}

void sphere(float R,int alfa,int beta)
{    /*R为球体半径，alfa、beta分别为半径与经纬线的夹角*/
	float x[4],y[4],z[4];  /*定义旋转变换前点坐标数组*/
	float x1[4],z1[4];    /*定义旋转变换后点坐标数组*/
	int i,j,k;
	float sx[4],sy[4];
	int shfill[10];  /*定义存放了5个顶点坐标序列的数组*/
	double yn;
	double a1,a2,b1,b2,c,d;

	c=alfa*PI/180.0;  /*每次旋转的角度*/
	d=beta*PI/180.0;
	cleardevice();

	for(j=0;j<180;j=j+20)
	{
		a1=j*PI/180.0;
		a2=(j+20)*PI/180.0;
		for(i=0;i<360;i=i+20)
		{
			b1=i*PI/180;
			b2=(i+20)*PI/180;
			x[0]=R*sin(a1)*cos(b1);   /*求出图形旋转前点的坐标*/
			y[0]=R*sin(a1)*sin(b1);
			z[0]=R*cos(a1);
			x[1]=R*sin(a2)*cos(b1);
			y[1]=R*sin(a2)*sin(b1);
			z[1]=R*cos(a2);
			x[2]=R*sin(a2)*cos(b2);
			y[2]=R*sin(a2)*sin(b2);
			z[2]=R*cos(a2);
			x[3]=R*sin(a1)*cos(b2);
			y[3]=R*sin(a1)*sin(b2);
			z[3]=R*cos(a1);
			for(k=0;k<4;k++)    /*求出图形旋转后点的坐标*/
			{
				x1[k]=x[k]*cos(c)-y[k]*sin(c);
				z1[k]=-x[k]*sin(c)*sin(d)-y[k]*cos(c)*sin(d)+z[k]*cos(d);
				sx[k]=100-x1[k];  /*将三维坐标转化为屏幕坐标*/
				sy[k]=100-z1[k];

			}
			yn=-(x1[2]-x1[0])*(z1[3]-z1[1])+(x1[3]-x1[1])*(z1[2]-z1[0]);
			if(yn>=0.0)   /*对可见部分进行画线，实现消隐*/
			{
				moveto(sx[0],sy[0]);
				lineto(sx[1],sy[1]);
				lineto(sx[2],sy[2]);
				lineto(sx[3],sy[3]);
				lineto(sx[0],sy[0]);
				shfill[0]=(int)sx[0],shfill[1]=(int)sy[0];
				shfill[2]=(int)sx[1],shfill[3]=(int)sy[1];
				shfill[4]=(int)sx[2],shfill[5]=(int)sy[2];
				shfill[6]=(int)sx[3],shfill[7]=(int)sy[3];
				shfill[8]=(int)sx[0],shfill[9]=(int)sy[0];
				if(i==20)    /*对一段经曲面进行填充为绿色*/
				{ 
					setfillstyle(1,2); 
				}	else setfillstyle(1,15);
				fillpoly(5,shfill);  /*用当前颜色填充多边形*/
			}
		}
	}
}

 

void main()
{
	int gdrive=DETECT,gmode,k,t,i=0; /*自动探测图形显示器适配器种类*/
	int size; void *buf[10];

	initgraph(&gdrive,&gmode,"");   /*初始化图形系统*/
	setcolor(RED);   /*设置当前画笔颜色为红色*/
	for(k=36;k<=360;k=k+36)
	{
		sphere(50,k,k);   /*调用sphere函数*/
		size=imagesize(50,40,150,150); 
		/*将保护位图象所需的字节数赋值给size*/
		if(size!=-1) buf[i]=malloc(size);    /* 分配size字节的内存空间*/
		if(buf[i]) getimage(50,40,150,150,buf[i]);  /*在屏幕指定的位置将一个位图保存到内存*/
		i++;
	}
	cleardevice();
	for(t=0;t<=45;t++)
	{
		cleardevice();
		putimage(xx,yy,buf[t%10],COPY_PUT);  /*在指定位置以拷贝形式输出一个位图*/
		keyboard(t);
		convey();
	}
	for(i=0;i<10;i++) free(buf[i]);    /*释放内存空间*/
	getch();
	closegraph();  /*关闭图形系统*/
}
