单看算法,不是很难,如果在256下,程序接口为直接输入数值的这种程序很好写,我希望自己能用C语言作出那种用鼠标绘制的效果.经过几个小时的看书和在网上搜集相关资料,终于实现了鼠绘直线的效果,然后再举一反三,圆的bressnham算法也很就容易的实现了. 基中算法思想的文档可以参考这里: http://www.ekany.com/wdg98/cg/contents/chapter2/les212.htm 实现直线的bressnham算法的整个程序代码如下: #include "stdio.h" #include"dos.h" #include"graphics.h" #include"conio.h" union REGS regs; int X__max,Y__max,x_max,y_max,yn_first_point=0,f_x=0,f_y=0,c_x,c_y;
void Initgr(); /*屏幕初始化成图形模式*/ int Msinit(int Xlo,int Xhi,int Ylo,int Yhi);/*鼠标初始化*/ int Msread(int *px,int *py,int *pbuttons);/*读鼠标位置及状态*/ int Xpixel(int x);/*由象素坐标变换为屏幕坐标*/ int Ypixel(int y);/*由象素坐标变换为屏幕坐标*/ void Cursor(int x,int y); /*显示十字光标*/ int put_line(int x1,int y1,int x2,int y2,int color);/*bresenham直线生成*/ void iswap(int *a,int *b);/*交换数据*/
main() {int buttons,X,Y,x,y,a,b; char i; Initgr();/*初始化图形屏幕*/ setcolor(EGA_LIGHTRED);/*设置屏幕前景色*/ setcolor(EGA_WHITE); setwritemode(XOR_PUT);/*设置屏幕输出模式*/ Msinit(0,(int)x_max,0,(int)y_max);/*初始化鼠标*/ a=x_max;b=y_max; x=0; Cursor(a,b); /*在a=x_max;b=y_max;处画指针*/ while(x!=2) {Msread(&X,&Y,&x); Cursor(a,b); /*删除之前的鼠标,因为屏幕输出模式的关系*/
if(x==1){ if (yn_first_point==1) { put_line(Xpixel(f_x),Ypixel(f_y),Xpixel(c_x),Ypixel(c_y),4); yn_first_point=0; } else { f_x=X;/* 保存第一点的坐标*/ f_y=Y; yn_first_point=1; } } /*画点*/
if (yn_first_point==1 && x!=1 && x!=2) { put_line(Xpixel(f_x),Ypixel(f_y),Xpixel(c_x),Ypixel(c_y),0); put_line(Xpixel(f_x),Ypixel(f_y),Xpixel(X),Ypixel(Y),2); }
Cursor(X,Y); a=X;b=Y; c_x=X;c_y=Y;/*当前鼠标的坐标*/ }
Cursor(X,Y);/*再调用一次把原来的指针削掉*/ getch(); closegraph(); }
void Initgr(void) /*屏幕初始化成图形模式*/ { int w,h,grdriver=DETECT,grmode; initgraph(&grdriver,&grmode,"");/*在双引号中可加你tc放的路径,但要在tc里有EGAVGA.BGI这个来初始图形*/ if(graphresult())/*若调用不成功,退出*/ {printf("\n jkdjkj.\n"); exit(1); } X__max=getmaxx();/*求横向象点坐标数*/ Y__max=getmaxy();/*求纵向象点坐标数*/ getaspectratio(&w,&h);/*求纵横比*/ x_max=1000; /*设置屏幕坐标的宽度*/ y_max=x_max*(float)Y__max*h/((float)X__max*w); }
int Msinit(int Xlo,int Xhi,int Ylo,int Yhi)/*鼠标初始化*/ {int retcode; regs.x.ax=0;/*初始化鼠标*/ int86(0x33,®s,®s); retcode=regs.x.ax; if(retcode==0) return 0; regs.x.ax=7;/*设置鼠标X方向的移动范围*/ regs.x.cx=Xlo; regs.x.dx=Xhi; int86(0x33,®s,®s); regs.x.ax=8;/*设置鼠标Y方向的移动范围*/ regs.x.cx=Ylo; regs.x.dx=Yhi; int86(0x33,®s,®s); regs.x.ax=15;/*设置mickey与象素的比,这各会影响鼠标移动速度*/ regs.x.cx=(int)(x_max/X__max); regs.x.dx=(int)(y_max/Y__max); int86(0x33,®s,®s); return retcode; }
int Msread(int *px,int *py,int *pbuttons)/*读鼠标位置及状态*/ {static int x0=320,y0=240,but0=0; int xnew,ynew,ch; do{ if(kbhit()){ ch=getch(); if(ch==13){ *pbuttons=1; return -1; } else return ch; /*返回键盘输入*/ } regs.x.ax=3; /*调用功能3,读鼠标位置及状态*/ int86(0x33,®s,®s); xnew=regs.x.cx;/*返回鼠标当前的位置的X坐标*/ ynew=regs.x.dx;/*返回鼠标当前的位置的Y坐标*/ *pbuttons=regs.x.bx;/*返回鼠标当前的状态*/ }while(xnew==x0&&ynew==y0&&*pbuttons==but0); /*当鼠标状态改变或位置改变终止循环*/ but0=*pbuttons;/*将鼠标状态保存到静态变量中*/ x0=xnew;y0=ynew;/*将鼠标位置保存到静态变量中*/ *px=xnew;*py=(int)(y_max-ynew); return -1; }
int Xpixel(int x)/*由象素坐标变换为屏幕坐标*/ { return (int)((long)X__max*x/x_max);}
int Ypixel(int y) { return Y__max-(int)((long)Y__max*y/y_max);}
void Cursor(int x,int y) /*显示十字光标*/ {int X=Xpixel(x),Y=Ypixel(y),color; char *str=" \0"; line(X-8,Y,X-3,Y); line(X,Y-8,X,Y-4); line(X+3,Y,X+8,Y); line(X,Y+4,X,Y+8); color=getcolor(); setcolor(BLACK); outtextxy(X__max-100,10,str);/*删除前次显示值*/ sprintf(str,"%d,%d",x,y); setcolor(WHITE); outtextxy(X__max-100,10,str);/*在屏幕右上角显示当前光标的坐标*/ setcolor(color); }
int put_line(int x1,int y1,int x2,int y2,int color)/*画直线函数*/ { int curx,cury,tx,ty,inc1,inc2,d; int dx,dy,itag; if(x1==x2&y1==y2)return 1; else itag=0; dx=abs(x2-x1); dy=abs(y2-y1); if(dx<dy) { itag=1; iswap(&x1,&y1); iswap(&x2,&y2); iswap(&dx,&dy); } tx=(x2-x1)>0?1:-1; ty=(y2-y1)>0?1:-1; curx=x1; cury=y1; inc1=2*dy; inc2=2*(dy-dx); d=inc1-dx; while(curx!=x2) { if(d<0)d+=inc1; else { cury+=ty; d+=inc2; } if(itag) putpixel(cury,curx,color); else putpixel(curx,cury,color); curx+=tx; } return 0; }
void iswap(int *a,int *b) { int tmp; tmp=*a; *a=*b; *b=tmp; }
实现圆的bressnham算法的整个程序代码如下: #include "stdio.h" #include"dos.h" #include"graphics.h" #include"conio.h" #include"math.h" union REGS regs; double X__max,Y__max,x_max,y_max,yn_first_point=0,f_x=0,f_y=0,c_x,c_y;
void Initgr(); /*屏幕初始化成图形模式*/ int Msinit(int Xlo,int Xhi,int Ylo,int Yhi);/*鼠标初始化*/ int Msread(int *px,int *py,int *pbuttons);/*读鼠标位置及状态*/ int Xpixel(int x);/*由象素坐标变换为屏幕坐标*/ int Ypixel(int y);/*由象素坐标变换为屏幕坐标*/ void Cursor(int x,int y); /*显示十字光标*/ void ff(int xc,int yc,int x,int y,int c); /*画点*/ void circlea(int xc,int yc,int radius,int c); /*用bresshuam算法画圆*/ main() {int buttons,X,Y,x,y,a,b; char i; Initgr();/*初始化图形屏幕*/ setcolor(EGA_LIGHTRED);/*设置屏幕前景色*/ setcolor(EGA_WHITE); setwritemode(XOR_PUT);/*设置屏幕输出模式*/ Msinit(0,(int)x_max,0,(int)y_max);/*初始化鼠标*/ a=x_max;b=y_max; x=0; Cursor(a,b); /*在a=x_max;b=y_max;处画指针*/ while(x!=2) {Msread(&X,&Y,&x); Cursor(a,b); /*删除之前的鼠标,因为屏幕输出模式的关系*/
if(x==1){ if (yn_first_point==1) { circlea(Xpixel(f_x),Ypixel(f_y),(int)sqrt((Xpixel(c_x)-Xpixel(f_x))*(Xpixel(c_x)-Xpixel(f_x))+(Ypixel(c_y)-Ypixel(f_y))*(Ypixel(c_y)-Ypixel(f_y))),4); yn_first_point=0; } else { f_x=X;/* 保存第一点的坐标*/ f_y=Y; yn_first_point=1; } }
if (yn_first_point==1 && x!=1 && x!=2) { circlea(Xpixel(f_x),Ypixel(f_y),(int)sqrt((Xpixel(c_x)-Xpixel(f_x))*(Xpixel(c_x)-Xpixel(f_x))+(Ypixel(c_y)-Ypixel(f_y))*(Ypixel(c_y)-Ypixel(f_y))),3);
}
Cursor(X,Y); a=X;b=Y; c_x=X;c_y=Y;/*当前鼠标的坐标*/ }
Cursor(X,Y);/*再调用一次把原来的指针削掉*/ getch(); closegraph(); }
void Initgr(void) /*屏幕初始化成图形模式*/ { int w,h,grdriver=DETECT,grmode; initgraph(&grdriver,&grmode,"");/*在双引号中可加你tc放的路径,但要在tc里有EGAVGA.BGI这个来初始图形*/ if(graphresult())/*若调用不成功,退出*/ {printf("\n jkdjkj.\n"); exit(1); } X__max=getmaxx();/*求横向象点坐标数*/ Y__max=getmaxy();/*求纵向象点坐标数*/ getaspectratio(&w,&h);/*求纵横比*/ x_max=1000; /*设置屏幕坐标的宽度*/ y_max=x_max*(float)Y__max*h/((float)X__max*w); }
int Msinit(int Xlo,int Xhi,int Ylo,int Yhi)/*鼠标初始化*/ {int retcode; regs.x.ax=0;/*初始化鼠标*/ int86(0x33,®s,®s); retcode=regs.x.ax; if(retcode==0) return 0; regs.x.ax=7;/*设置鼠标X方向的移动范围*/ regs.x.cx=Xlo; regs.x.dx=Xhi; int86(0x33,®s,®s); regs.x.ax=8;/*设置鼠标Y方向的移动范围*/ regs.x.cx=Ylo; regs.x.dx=Yhi; int86(0x33,®s,®s); regs.x.ax=15;/*设置mickey与象素的比,这各会影响鼠标移动速度*/ regs.x.cx=(int)(x_max/X__max); regs.x.dx=(int)(y_max/Y__max); int86(0x33,®s,®s); return retcode; }
int Msread(int *px,int *py,int *pbuttons)/*读鼠标位置及状态*/ {static int x0=320,y0=240,but0=0; int xnew,ynew,ch; do{ if(kbhit()){ ch=getch(); if(ch==13){ *pbuttons=1; return -1; } else return ch; /*返回键盘输入*/ } regs.x.ax=3; /*调用功能3,读鼠标位置及状态*/ int86(0x33,®s,®s); xnew=regs.x.cx;/*返回鼠标当前的位置的X坐标*/ ynew=regs.x.dx;/*返回鼠标当前的位置的Y坐标*/ *pbuttons=regs.x.bx;/*返回鼠标当前的状态*/ }while(xnew==x0&&ynew==y0&&*pbuttons==but0); /*当鼠标状态改变或位置改变终止循环*/ but0=*pbuttons;/*将鼠标状态保存到静态变量中*/ x0=xnew;y0=ynew;/*将鼠标位置保存到静态变量中*/ *px=xnew;*py=(int)(y_max-ynew); return -1; }
int Xpixel(int x)/*由象素坐标变换为屏幕坐标*/ { return (int)((long)X__max*x/x_max);}
int Ypixel(int y) { return Y__max-(int)((long)Y__max*y/y_max);}
void Cursor(int x,int y) /*显示十字光标*/ {int X=Xpixel(x),Y=Ypixel(y),color; char *str=" \0"; line(X-8,Y,X-3,Y); line(X,Y-8,X,Y-4); line(X+3,Y,X+8,Y); line(X,Y+4,X,Y+8); color=getcolor(); setcolor(BLACK); outtextxy(X__max-100,10,str);/*删除前次显示值*/ sprintf(str,"%d,%d",x,y); setcolor(WHITE); outtextxy(X__max-100,10,str);/*在屏幕右上角显示当前光标的坐标*/ setcolor(color); } void ff(int xc,int yc,int x,int y,int c)
{ putpixel(xc+x,yc+y,c); putpixel(xc-x,yc+y,c); putpixel(xc+x,yc-y,c); putpixel(xc-x,yc-y,c); putpixel(xc+y,yc+x,c); putpixel(xc-y,yc+x,c); putpixel(xc+y,yc-x,c); putpixel(xc-y,yc-x,c); }
void circlea(int xc,int yc,int radius,int c) {int x,y,p; x=0; y=radius; p=3-2*radius; while (x<y) {ff(xc,yc,x,y,c); if (p<0) p=p+4*x+6; else {p=p+4*(x-y)+10; y-=1; } x+=1; } if (x==y) ff(xc,yc,x,y,c); }
基中在运行圆的算法时,开始是很正常,过了一会儿,提示sqrt domain error.我还没弄懂.不知道是怎么一回事,有时间再请教别人.星期六要软考了.汗~我得赶快去看书.

|