zoukankan      html  css  js  c++  java
  • 画圆形(Bresenham算法)

    下面先简要介绍常用的画圆算法(Bresenham算法),然后再具体阐述笔者对该算法的改进。

        一个圆,如果画出了圆上的某一点,那么可以利用对称性计算余下的七段圆弧:Plot(x,y),Plot(y,x),Plot(y,-x),Plot(x,-y),Plot(-x,-y),Plot(-y,-x),Plot(-y,x),Plot(-x,y)。

        1、Bresenham 画圆算法。Bresenham算法的主要思想是:以坐标原点(0,0)为圆心的圆可以通过0度到45°的弧计算得到,即x从0增加到半径,然后利用对称性计算余下的七段圆弧。当x从0增加到时,y从R递减到。

        设圆的半径为R,则圆的方程为:

        f(x,y)=(x+1)2+y2-R2=0                                   (1)

        假设当前列(x=xi列)中最接近圆弧的像素已经取为P(xi,yi),根据第二卦限1/8圆的走向,下一列(x=xi+1列)中最接近圆弧的像素只能在P的正右方点H(xi+1,yi)或右下方点L(xi+1,yi-1)中选择,如图1所示。Bresenham画圆算法采用点T(x,y)到圆心的距离平方与半径平方之差D(T)作为选择标准,即

        D(T)=(x+1)2+y2-R2                                         (2)

        通过比较H、L两点各自对实圆弧上点的距离大小,即根据误差大小来选取,具有最小误差的点为绘制点。根据公式(2)得:

        对H(xi+1,yi)点有:D(H)=(xi+1)2+yi2-R2;

        对L(xi+1,yi-1)点有:D(L)=(xi+1)2+(yi-1)2-R2;

        根据Bresenham画圆算法,则选择的标准是:

        如果|D(H)|<|D(L)|,那么下一点选取H(xi+1,yi);

        如果|D(H)|>|D(L)|,那么下一点选取L(xi+1,yi-1);

        如果|D(H)|=|D(L)|,那么下一点可以取L(xi+1,yi-1),也可以选取H(xi+1,yi),我们约定选取H(xi+1,yi)。

        图1  Bresenham画圆算法点的选取

        综合上述情况,得:

        当|D(H)|>|D(L)|时,选取L点(xi+1,yi-1)为绘制点坐标;

        当|D(H)|<|D(L)|时,选取H点(xi+1,yi)为绘制点坐标。

        然后将选取的点坐标作为当前坐标,重复上述过程直至xi=或者yi=为止,(xi,yi)的初始值为(0,R)。

        以上便是Bresenham算法的主要思想,但是上述算法是在一个假设下:以坐标原点(0,0)为圆心。该假设实际上只是为了方便算法的研究。但在实际嵌入式LCD显示设备中,往往圆心坐标不是(0,0)点,而是以左上角为(0,0)点,这样就使得在实际运用中,需要对这个算法做很大的改进。

        另外,如果完全按照Bresenham画圆算法,那么就会涉及到浮点运算,这使得嵌入式编程十分烦琐,因为本系统中所有数据都是整型的,因此在这方面也要作一定的改进。下面根据本系统中嵌入式硬件特点和数据结构得特点,对这个算法进行改进。

        2、改进的Bresenham画圆算法。先假设起始点为(R,0),令Pi=(xi,yi)为当前的一点,那么我们就需要在Ti=(xi,yi+1)和Si=(xi-1,yi+1)中选取一点,如图2所示。

        图2 嵌入式LCD画圆时点的选取

        设(xi-1/2+e,yi+1)为S和T之间圆上的点,e是S、T中点到圆上点的误差,带入圆的方程(1)得:

        f(xi-1/2+e,yi+1)=(xi-1/2+e)2+(yi+1)2-R2=f(xi-1/2,yi+1)+2(xi-1/2)e+e2=0   (3)

        在式(3)中,令

        di="f"(xi-1/2,yi+1)=-2(xi-1/2)e-e2                                    (4)

        如果e<0,那么di>0,因此选择S=(xi-1,yi+1),根据(3)与(4)得:

        di+1=f(xi-1-1/2,yi+1+1)=di-2(xi-1)+2(yi+1)+1=di+2(yi+1-xi+1)+1         (5)

        如果e30,那么di£0,因此选择T=(xi,yi+1),根据(3)与(4)得:

        di+1=f(xi-1/2,yi+1+1)=di+2yi+1+1                                  (6)

        起始点是(R,0)的时候,根据(4)得di的初始值d0就是:

        d0=f(R-1/2,0+1)=(R-1/2)2+1-R2=5/4-R=1-R(由于编程中所用数据类型均为整型,故取1-R)。

        综合上述情况,得:

        当选取S=(xi-1,yi+1)时,那么di+1=di+2(yi+1-xi+1)+1;

        当选取T=(xi,yi+1)时,那么di+1=di+2yi+1+1;

        然后将选取的点坐标作为当前坐标,重复上述过程直至x=y,而不是xi=或者yi=,这样就可以不用作浮点数计算了。

        本项目中的LCD像素为640×480点阵,并且数据是八位的,当横坐标和纵坐标超过255时,那么数据就不能一次传送成功,因此需要通过字节操作来设定高字节,然后再传送低字节。因此,每次画圆上的点时要传送的参数至少是六个,圆心坐标是四个(因为要考虑圆心坐标可能大于255,因此要对其圆心坐标设置高、低字节),另外两个是圆上的点相对于圆心的坐标,但是最后要画一个点,需要四个参数,即改进的画圆算法为六个参数输入,四个参数输出。

    (注:转载自http://blog.csdn.net/Charistain_huang/archive/2010/05/02/5549848.aspx

    #include <graphics.h>
    #include <math.h>

    void MidPointCircle(int r, int color);     /*中点bresenham算法*/
    void CirclePoints(int x,int y,int color);
    void BresenhamCircle(int xc,int yc,int r,int color);
    void plot_cicle_point(int xc,int yc,int x,int y,int color);

    main()
    {
       int gdriver=DETECT,gmode;
       initgraph(&gdriver,&gmode," ");
       cleardevice();
       setbkcolor(2);
       MidPointCircle(100,4);
       getch();
       cleardevice();
       BresenhamCircle(100,100,50,5);
       getch();
       closegraph();

    }
    void MidPointCircle(int r,int color)
    {
      int x,y;
      float d;
      x=0;y=r;
      d=1.25-r;
      CirclePoints(x,y,color);
      while(x<=y)
      {
        if(d<0)
           d+=2*x+3;
        else
        {
           d+=2*(x-y)+5;
           y--;
        }
        x++;
        CirclePoints(x,y,color);
      }
    }
    void CirclePoints(int x,int y,int color)
    {
       putpixel(x,y,color);
       putpixel(y,x,color);
       putpixel(-x,y,color);
       putpixel(y,-x,color);
       putpixel(x,-y,color);
       putpixel(-y,x,color);
       putpixel(-x,-y,color);
       putpixel(-y,-x,color);
    }
    void plot_circle_point(int xc,int yc,int x,int y,int color)
    {
        putpixel(xc+x,yc+y,color);
        putpixel(xc-x,yc+y,color);
        putpixel(xc+x,yc-y,color);
        putpixel(xc-x,yc-y,color);
        putpixel(xc+y,yc+x,color);
        putpixel(xc-y,yc+x,color);
        putpixel(xc+y,yc-x,color);
        putpixel(xc-y,yc-x,color);
    }

    void BresenhamCircle(int xc,int yc,int r,int color)
    {
      int x,y,d;
      x=0;y=r;
      d=3-2*r;
      while(x<y)
      {
         plot_circle_point(xc,yc,x,y,color);
         if(d<0)
     d=d+4*x+6;
         else
         {
     d=d+4*(x-y)+10;
     y--;
         }
         x++;
      }
      if(x==y)
        plot_circle_point(xc,yc,x,y,color);

    }

    PASCAL程序

    program circlebre;
    uses crt,graph;
    var
      gd,gm:integer;
      xasp,yasp:word;
      ratio:real;

      procedure bresenham_circle(x0,y0,r:integer);
      var
        x,y,D:integer;
      begin
        x:=0;
        y:=r;
        d:=3-r-r;
        while x<=y do
        begin
          putpixel(x0+x,round((y0+y)*ratio),white);
          putpixel(x0-x,round((y0+y)*ratio),white);
          putpixel(x0+x,round((y0-y)*ratio),white);
          putpixel(x0-x,round((y0-y)*ratio),white);
          putpixel(x0+y,round((y0+x)*ratio),white);
          putpixel(x0-y,round((y0+x)*ratio),white);
          putpixel(x0+y,round((y0-x)*ratio),white);
          putpixel(x0-y,round((y0-x)*ratio),white);
          if d<0 then
            inc(d,4*x+6)
          else
          begin
            inc(d,4*(x-y)+10);
            dec(y);
          end;
          inc(x);
        end;
      end;

    begin
      gd:=detect;
      initgraph(gd,gm,'D:\tp\bgi');
      getaspectratio(xasp,yasp);
      ratio :=xasp/yasp;
      bresenham_circle(300,100,50);
      Repeat until Keypressed;
      closegraph;
    end.

  • 相关阅读:
    JPA总结——实体关系映射(一对多@OneToMany)
    JPA——映射持久化对象(Entity)
    jackson annotations注解详解
    Spring Data JPA
    Spring Data JPA初使用
    Spring注解Annotion详解
    JPA概要
    The requested resource is not available错误
    Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 标签
    Spring——Eclipse上安装springsource-tool-suite与jar包详解
  • 原文地址:https://www.cnblogs.com/djcsch2001/p/1964220.html
Copyright © 2011-2022 走看看