用C实现直线和圆的bressham算法

类别:编程语言 点击:0 评论:0 推荐:

单看算法,不是很难,如果在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,&regs,&regs);
retcode=regs.x.ax;
if(retcode==0) return 0;
regs.x.ax=7;/*设置鼠标X方向的移动范围*/
regs.x.cx=Xlo;
regs.x.dx=Xhi;
int86(0x33,&regs,&regs);
regs.x.ax=8;/*设置鼠标Y方向的移动范围*/
regs.x.cx=Ylo;
regs.x.dx=Yhi;
int86(0x33,&regs,&regs);
regs.x.ax=15;/*设置mickey与象素的比,这各会影响鼠标移动速度*/
regs.x.cx=(int)(x_max/X__max);
regs.x.dx=(int)(y_max/Y__max);
int86(0x33,&regs,&regs);
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,&regs,&regs);
    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,&regs,&regs);
retcode=regs.x.ax;
if(retcode==0) return 0;
regs.x.ax=7;/*设置鼠标X方向的移动范围*/
regs.x.cx=Xlo;
regs.x.dx=Xhi;
int86(0x33,&regs,&regs);
regs.x.ax=8;/*设置鼠标Y方向的移动范围*/
regs.x.cx=Ylo;
regs.x.dx=Yhi;
int86(0x33,&regs,&regs);
regs.x.ax=15;/*设置mickey与象素的比,这各会影响鼠标移动速度*/
regs.x.cx=(int)(x_max/X__max);
regs.x.dx=(int)(y_max/Y__max);
int86(0x33,&regs,&regs);
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,&regs,&regs);
    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.我还没弄懂.不知道是怎么一回事,有时间再请教别人.星期六要软考了.汗~我得赶快去看书.

本文地址:http://com.8s8s.com/it/it25886.htm