OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 11187|回复: 20

谁能帮忙解释下,原子哥TFT画直线和画圆的代码?

[复制链接]

1

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2013-10-1
在线时间
0 小时
发表于 2013-10-6 16:31:22 | 显示全部楼层 |阅读模式
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标  
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
u16 t; 
int xerr=0,yerr=0,delta_x,delta_y,distance; 
int incx,incy,uRow,uCol; 
delta_x=x2-x1; //计算坐标增量 
delta_y=y2-y1; 
uRow=x1; 
uCol=y1; 
if(delta_x>0)incx=1; //设置单步方向 
else if(delta_x==0)incx=0;//垂直线 
else {incx=-1;delta_x=-delta_x;} 
if(delta_y>0)incy=1; 
else if(delta_y==0)incy=0;//水平线 
else{incy=-1;delta_y=-delta_y;} 
if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
else distance=delta_y; 
for(t=0;t<=distance+1;t++ )//画线输出 
{  
LCD_DrawPoint(uRow,uCol);//画点 
xerr+=delta_x ; 
yerr+=delta_y ; 
if(xerr>distance) 
xerr-=distance; 
uRow+=incx; 
if(yerr>distance) 
yerr-=distance; 
uCol+=incy; 
}  
}    
以上画线的这段代码,我想了很长时间,还是没想明白。不过,画出来的线,的确很直!







画园的这段代码,很多网友说是先把园分成八段,然后再画的。问题是,我依然很疑惑!求解答!

//在指定位置画一个指定大小的圆
//(x,y):中心点
//r   :半径
void Draw_Circle(u16 x0,u16 y0,u8 r)
{
int a,b;
int di;
a=0;b=r;  
di=3-(r<<1);             //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint(x0+a,y0-b);             //5
  LCD_DrawPoint(x0+b,y0-a);             //0           
LCD_DrawPoint(x0+b,y0+a);             //4               
LCD_DrawPoint(x0+a,y0+b);             //6 
LCD_DrawPoint(x0-a,y0+b);             //1       
  LCD_DrawPoint(x0-b,y0+a);             
LCD_DrawPoint(x0-a,y0-b);             //2             
  LCD_DrawPoint(x0-b,y0-a);             //7             
a++;
//使用Bresenham算法画圆     
if(di<0)di +=4*a+6;  
else
{
di+=10+4*(a-b);   
b--;
}    
}
}
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2016-2-18 14:41:47 | 显示全部楼层
本帖最后由 EDA3rd 于 2016-2-19 09:16 编辑

自己算了一下,原子哥画直线的代码,下一个点不是取最逼近的点,而是:只要下一个实际点没超过y+1,都选择不加1。

举例,(0,0)  到 (3,1)这条直线,原子哥的程序走的路径为:
(0,0 ) (1,0) (2,0) (2,1)

而实际上,第3点(2,0)的实际点为(2, 0.66),所以应该取(2, 1)才更逼近实际点。

大概摸索出原子哥画直线的思路:
仍然选择画(0,0)  到 (3,1)这条直线,设e为累加误差,初始值为0, m = dy/dx =1/3

e+=m;
if(( y + e) < y+1)
    y = y;
else
{
    y+=1;
    e -= m;
}
y + e + m < y+1 等价于 : (e+m) * dx <dx

或者

if(( y + e + m) < y+1)
{
    e += m
    y = y;
}
else
{
    y+=1;
}

而标准的bresenham算法的判断方法是if e+m<0.5 ,这样才能保证选取最逼近的点。

而画圆的代码也有bug,a++应该放在while最末尾的位置,我修改后的代码为:
[mw_shl_code=c,true]//画线
//x1,y1:起点坐标
//x2,y2:终点坐标  
void draw_Line(u32 x1, u32 y1, u32 x2, u32 y2, u32 color)
{
        u32 t;
        int xerr=0,yerr=0,delta_x,delta_y,distance;
        int incx,incy,uRow,uCol;

        delta_x=x2-x1; //计算坐标增量
        delta_y=y2-y1;
        uRow=x1;
        uCol=y1;
        if(delta_x>0)incx=1; //设置单步方向
        else if(delta_x==0)incx=0;//垂直线
        else {incx=-1;delta_x=-delta_x;}
        
        if(delta_y>0)incy=1;
        else if(delta_y==0)incy=0;//水平线
        else{incy=-1;delta_y=-delta_y;}
        
        if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
        else distance=delta_y;
        
        //假设x为较长边
        //distance为x方向的最大位移delta_x,delta_x为x方向最大位移dx,delta_y为y最大位移dy,均为常量
        //incx为方向,绝对值为1,用来每次递增
        for(t=0;t<=distance+1;t++ )//沿基轴画线输出
        {  
                draw_pixel(uRow, uCol, color);//画点
                xerr+=delta_x ; //xerr 为累积误差,每次递增delta_x,判断误差后选择是否恢复旧值
                yerr+=delta_y ; //yerr 为累积误差,每次递增delta_y,即 E + dy
                if(2 * (xerr) > distance) //
                {
                        xerr-=distance; //恢复xerr
                        uRow+=incx; //如果x为较长边,每次循环uRow总是+1
                }

                if(2 * (yerr) > distance) //如果2(E + dy )< dx, 则y++
                {
                        yerr-=distance; //减delta_x,恢复yerr
                        uCol+=incy; //
                }
        }  
}   

#define FILL_MODE 1
#define HOLLOW_MODE 0


//在指定位置画一个指定大小的圆
//(x,y):中心点
//r    :半径
void draw_circle(u32 x0,u32 y0,u8 r,u32 color, u32 fill)
{
        int a,b,bi;
        int di;
        a=0;b=r;         
        di=3-(r<<1);             //判断下个点位置的标志
        while(a<=b)
        {
                if(fill)
                {
                        for(bi = a; bi <= b; bi ++)  
                        {                  
                                draw_pixel(x0+bi, y0-a, color);                        //0        
                                draw_pixel(x0-a, y0+bi, color);                        //1         
                                draw_pixel(x0-a, y0-bi, color);                        //2               
                                draw_pixel(x0-bi, y0+a, color);                        //3
                                draw_pixel(x0+bi, y0+a, color);                        //4        
                                draw_pixel(x0+a, y0-bi, color);                        //5                 
                                draw_pixel(x0+a, y0+bi, color);                        //6
                                draw_pixel(x0-bi, y0-a, color);                        //7        
                        }  
                } else {
                        draw_pixel(x0-b,y0-a,color);             //3           
                        draw_pixel(x0+b,y0-a,color);             //0           
                        draw_pixel(x0-a,y0+b,color);             //1      
                        draw_pixel(x0-b,y0-a,color);             //7           
                        draw_pixel(x0-a,y0-b,color);             //2            
                        draw_pixel(x0+b,y0+a,color);             //4               
                        draw_pixel(x0+a,y0-b,color);             //5
                        draw_pixel(x0+a,y0+b,color);             //6
                        draw_pixel(x0-b,y0+a,color);            
                }
                //使用Bresenham算法画圆     
                if(di<0)di +=4*a+6;         
                else
                {
                        di+=10+4*(a-b);   
                        b--;
                }
                a++;
        }
}[/mw_shl_code]


回复 支持 1 反对 0

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-6 19:46:42 | 显示全部楼层
回复【楼主位】萧狼1989:
---------------------------------
我也是“借来”的,没去搞懂...直接用,O(∩_∩)O哈哈~
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2013-10-1
在线时间
0 小时
 楼主| 发表于 2013-10-6 20:02:37 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
原子哥的图标真个性!感谢原子哥的回复。确实直接用就行了,貌似过程挺繁琐的,原出处居然是一篇论文! 
关于TFT型LCD画圆的算法改进http://www.docin.com/p-246528188.html
以上是画圆的算法出处,貌似他没讲,为什么下一个最接近圆上的点只有那么两个,而不是三个或者是多个?
回复 支持 反对

使用道具 举报

1

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2013-10-1
在线时间
0 小时
 楼主| 发表于 2013-10-6 20:06:18 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
原子哥是湖南的吗?我湖南常德的,有可能明年回长沙。湖南人,不怕死、掐得苦、霸得蛮、耐得烦!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-6 20:19:49 | 显示全部楼层
回复【4楼】萧狼1989:
---------------------------------
湖南湘潭。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
86
金钱
86
注册时间
2013-9-13
在线时间
3 小时
发表于 2013-10-6 20:35:25 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
我也在湘潭,刚和我同学一起买了原子哥的战舰板
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-7 11:57:55 | 显示全部楼层
回复【6楼】王二狗子:
---------------------------------
谢谢支持
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

51

主题

1455

帖子

3

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2613
金钱
2613
注册时间
2011-1-25
在线时间
176 小时
发表于 2013-10-7 12:34:37 | 显示全部楼层
Brescnham算法,详情请百度这个。
一直努力就很好。
回复 支持 反对

使用道具 举报

1

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2013-10-1
在线时间
0 小时
 楼主| 发表于 2013-10-7 14:03:20 | 显示全部楼层
回复【8楼】qq942266575:
---------------------------------
恩 你说的对 的确都是改进型的 bresenham算法 谢谢你啊  我已经找到解说处了
画圆算法解说处http://www.docin.com/p-246528188.html
画线算法解说处http://wenku.baidu.com/view/75ddb8faaef8941ea76e05db.html
回复 支持 反对

使用道具 举报

1

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2013-10-1
在线时间
0 小时
 楼主| 发表于 2013-10-7 14:10:10 | 显示全部楼层
关于画线算法 我觉得用条件(xerr*2>=distance)  (yerr*2>=distance)更平滑些 实际结果是和用条件(xerr>distance)  (yerr>distance)两者相差不算大  


原画圆算法加一点点 就可以画实心圆了

//在指定位置画一个指定大小的圆
//(x,y):中心点
//r :半径
//fill:圆是否为实心圆,fill为1时,实心圆,fill为非1时画空心圆
void Draw_Circle(u16 x0,u16 y0,u8 r,u8 fill)
{
int a,b,bi;
int di;
a=0;b=r;   
di=3-(r<<1);             //判断下个点位置的标志

while(a<=b)
{
    if(fill==1)
        for(bi = a; bi <= b; bi ++)  
        {         
LCD_DrawPoint(x0+a,y0-bi);             //5
  LCD_DrawPoint(x0+bi,y0-a);             //0           
LCD_DrawPoint(x0+bi,y0+a);             //4               
LCD_DrawPoint(x0+a,y0+bi);             //6 
LCD_DrawPoint(x0-a,y0+bi);             //1       
  LCD_DrawPoint(x0-bi,y0+a);             
LCD_DrawPoint(x0-a,y0-bi);             //2             
   LCD_DrawPoint(x0-bi,y0-a);             //7   

else
{
LCD_DrawPoint(x0+a,y0-b);             //5
  LCD_DrawPoint(x0+b,y0-a);             //0           
LCD_DrawPoint(x0+b,y0+a);             //4               
LCD_DrawPoint(x0+a,y0+b);             //6 
LCD_DrawPoint(x0-a,y0+b);             //1       
  LCD_DrawPoint(x0-b,y0+a);             
LCD_DrawPoint(x0-a,y0-b);             //2             
   LCD_DrawPoint(x0-b,y0-a);             //7   
}           
a++;
//使用Bresenham算法画圆     
if(di<0)di +=4*a+6;   
else
{
di+=10+4*(a-b);   
b--;
}      
}
}
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-7 14:22:31 | 显示全部楼层
回复【10楼】萧狼1989:
---------------------------------
谢谢分享
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2013-10-1
在线时间
0 小时
 楼主| 发表于 2013-10-7 16:37:16 | 显示全部楼层
回复【11楼】正点原子:
---------------------------------
原子哥客气了!
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2016-2-17 11:15:08 | 显示全部楼层
本帖最后由 EDA3rd 于 2016-2-19 09:18 编辑

bresenham算法画直线和圆,  思路类似, 都是使用误差判断下一个点位置,这样可以避免浮点运算.画圆还需要利用勾股定理推导,利用八对称性简化代码.
这些文章讲得很清楚:
中点画圆法分析:
http://www.cnblogs.com/gamesky/archive/2012/09/03/2668932.html

bresenham画直线算法分析
http://www.cnblogs.com/sky1991/archive/2012/07/09/2583620.html

3种画圆算法分析和比较,包含bresenham画圆:
http://wenku.baidu.com/link?url=0SFLQcJS8-W3nDqg66HWQBZ7lyS1HfrHVbWwbtjPjLTzJjak55upYtXu6zRkMPdEYdwfTkcmk9j-eJxgpLzbVguPx3DfqEe0qBEkgIGjO8y

原子哥画圆的算法用的是改进的中点画圆法,也就是用bresenham画圆,实际上就是通过比较y^2 - R^2来计算误差,而中点画圆是比较x^2 + y^2 - R^2来计算误差。所以最终2者的初值和累加值相似但不一样。

百度百科bresenham画圆,和原子哥代码完全一样:
http://baike.baidu.com/link?url= ... yl4Ar3uYj-7QV7mJ8WK
回复 支持 反对

使用道具 举报

32

主题

883

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4036
金钱
4036
注册时间
2015-11-14
在线时间
545 小时
发表于 2016-2-17 13:30:10 | 显示全部楼层
我也是湖南人啊!划线的函数还能理解,画圆就复杂了,我在线调试过,确实是几个段完成画圆的
回复 支持 反对

使用道具 举报

16

主题

253

帖子

0

精华

高级会员

Rank: 4

积分
565
金钱
565
注册时间
2013-10-16
在线时间
52 小时
发表于 2016-8-8 22:02:37 | 显示全部楼层
谢谢分享,看了半天画直线代码,愣是搞不明白。原来还有算法出处的。
回复 支持 反对

使用道具 举报

74

主题

334

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
436
金钱
436
注册时间
2015-5-28
在线时间
144 小时
发表于 2016-11-21 21:40:34 | 显示全部楼层
Mark,画圆画直线算法
回复 支持 反对

使用道具 举报

1

主题

17

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2017-7-29
在线时间
18 小时
发表于 2017-8-14 22:25:09 | 显示全部楼层
mark!!
回复 支持 反对

使用道具 举报

32

主题

300

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1049
金钱
1049
注册时间
2012-3-30
在线时间
321 小时
发表于 2017-8-14 23:05:26 | 显示全部楼层
画出来的线,的确很直!
回复 支持 反对

使用道具 举报

18

主题

84

帖子

0

精华

初级会员

Rank: 2

积分
181
金钱
181
注册时间
2016-7-4
在线时间
56 小时
发表于 2018-10-5 13:29:05 | 显示全部楼层
以前面试有碰到一道面试题,说是已经有了画点的函数,叫我自己实现画线的函数,当时就没做出来。今天才发现原来这里面的水那么深
回复 支持 反对

使用道具 举报

5

主题

59

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
276
金钱
276
注册时间
2018-1-15
在线时间
34 小时
发表于 2018-10-11 09:22:19 | 显示全部楼层
学习一下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-7 22:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表