画线函数Glib_Line算法的研究
在这里首先先简单把我对函数的功能的理解阐述一下,方便后面的分析:Glib_Line函数实现的功能是通过参数给定(x1,y1,x2,y2,color),来确定起点(x1,y1)和终点(x2,y2)两点之间的一条直线,并通过color参数来确定这条直线的颜色。这里这条语句的算法重点在于如何给像素点填充对应的颜色来画出任意直线,至于颜色具体值的确定会在后续的配色原理中阐述。首先先来看两幅图片:
他们是相同的一个图片,图片2是图片1放大后的情况。
我们平时在LCD上画直线还无所谓,但是如果画斜线,由于LCD上没有半个像素点,所以,当x或y增加一个像素点之后,对应的y或x要么增加一个像素点,要么保持原来的像素点不动,举个例子:假设:x1=1,x2=320,y1=1,y2=2,那么画线后的情况是x轴的前面160个像素点,y轴的是1,在x轴的后面160个像素点,y轴是2。
我们根据图3来仔细分析画斜线时可能出现的问题,以及处理的算法。这里我们取众多情况中的一种来分析,即dx>=0 ,dy >= 0,dx>=dy的情况。
我们把像素点放大抽象为图3,其中黑点定为起始点,灰色线所指的点为第二个像素点的理论位置,绿色点和黄色点为实际像素点可能赋值的点,并且我们这里规定,绿色点到灰色点的距离为a,黄色点到灰色点的距离为b。灰色点坐标为(x,y),绿色点坐标为(x1+1,y1+1),黄色点坐标为(x1+1,y1)。并且规定所画直线在x轴上的投影为dx=x2-x1,在y轴上的投影为dy=y2-y1。
理论上,灰色点才是理论点,但是由于像素点不能有小数,所以只可能是上面的绿点或者下面的黄点选一个,具体选哪个要由谁更靠近灰点(误差小)决定
这里我们根据数学知识可以得到:
a=(y+1)-(x+1)×(dy/dx)
b=(x+1)×(dy/dx)- y
下面我们只需要判断a和b谁大谁小便可以决定到底选黄点还是绿点。
这里我们选用差值法来判断a,b的大小:
为了去掉小数点,因为dx>0,所以有d=dx*(b-a)= 2*(xdy-ydx)+2dy-dx;
接下来我们只需要判断dx*(b-a)>0还是dx*(b-a)<0;
这个时候我们用相对坐标来考虑,把起始点(x1,y1)平移到(0,0)点,整条直线虽然也随之平移,这个时候黄点和绿点的坐标也随之改变,但是不改变第二个点到底是在绿点还是黄点的位置。同理也不改变后面其他像素点的选择。所以采用相对坐标后x1=0,y1=0, d1=dx*(b-a)=2dy-dx,通过判断这个d1与0的大小关系就可以知道是图3中的绿点还是黄点了。这个地方我们用到的d1/2就是程序中的变量e.即e=d1/2=dy-dx/2.
下面我们就对照着函数代码来分析程序中算法的实现。同样我们取众多情况中的一种来分析,即dx>=0 ,dy >= 0,dx>=dy的情况,和上面算法对应起来.
e=dy-dx/;
while(x1<=x2)
{
PutPixel(x1,y1,color);
if(e>){y1+=;e-=dx;}
x1+=;
e+=dy;
}
这段程序就是在满足dx>=0 ,dy >= 0,dx>=dy的情况下,需要执行的内容。
首先是把和a,b差值有直接联系的e求出来,接下来便进入while循环, while循环的作用是对从x1到x2之间所有的像素点赋值。
因为dx>dy,结合图3我们知道在x1和x2之间对应要赋值的有x2-x1个像素点,所以这就是while语句括号中判断的作用,就是对x1和x2之间的x2-x1个像素点赋值,因此每次x1+=1语句的作用就是对x2-x1这个数进行计数,每次加1直到等于x2为止,等于x2了就算把所有该赋值的像素点都赋值了。
while语句里,先是对(x1,y1)这个位置的像素点赋值,然后如果横坐标没到终点的横坐标x2,就一直赋值,期间要对下一个点的位置做判断,即if(e>0)语句:
1.第一次判断如果b>a,即b-a>0,也就e>0,这个时候我们肯定是选择绿点,所以第二点的坐标为(x1+1,y1+1),x1+1在整个while中的x1+=1中实现,y1+1在if语句中的y1+=1中实现,然后便是改变判断第三点的位置时要用到的e。
因为d2=2*(x2dy-y2dx)+2dy-dx,因为第一点相对坐标为(0,0),则第二点的相对坐标为(1,1),所以d2=4dy-3dx,此时的e2=d2/2=2dy-3/2dx=e+dy-dx;e2中对原来的e+dy是在整个while中的e+=dy中实现的,对原来的e-dx是在在if语句中的e-=dx中实现的。
2.第一次判断如果b<a,即b-a<0,也就是e<0,这个时候我们肯定选择黄点,所以第二点的坐标为(x1+1,y1),x1+1在整个while中的x1+=1中实现,此时不进入if语句,然后便是改变判断第三点的位置时要用到的e。
因为d2=2*(x2dy-y2dx)+2dy-dx,因为第一点相对坐标为(0,0),则第二点的相对坐标为(1,0),所以d2=4dy-dx,此时的e2=d2/2=2dy-dx/2=e+dy;e2中对原来的e+dy是在整个while中的e+=dy中实现的,此时不进入if语句,dx不增加。
同样的道理,到了判断e的时候,重复上面的过程,d=2*(xdy-ydx)+2dy-dx;x,y分别为当时判断点的相对坐标。
例如,第二点选择的是黄点,第三点选择的是绿点,通过算法我们得到e2=e1+dy;e3=e2+dy-dx=e1+2dy-dx=e+2dy-dx=3dy-3/2dx;
下面通过对e的定义来验证一下:
第二点的相对坐标为(1,0),则第三点的坐标为(2,1)
e3=d3/2=(x3dy-y3dx)+dy-dx/2=2dy-dx+dy-dx/2=3dy-3/2dx;
两种方法的e3值完全一样,以此类推证明了程序与算法的吻合,程序完全可以实现算法所需要的功能。
以上只是分析了其中dx>=0 ,dy >= 0,dx>=dy一种情况,我们仔细分析发现,其他的七种情况的数学含义以及分析方法和第一种完全一样,只是斜线的斜率,以及dx,dy长短等不同而以,这里不做过多的赘述。
所有的情况分别为8种:
1.dx>=0,dy>0 ,dx>=dy
2.dx>=0,dy>0 ,dx<dy
3.dx>=0,dy<0 ,dx>=dy
4.dx>=0,dy<0 ,dx<dy
5.dx<0, dy>0 ,dx>=dy
6.dx<0, dy>0 ,dx<dy
7.dx<0, dy<0 ,dx>=dy
8.dx<0, dy<0 ,dx<dy
具体代码如下:
// glib库中的画线函数,可以画斜线,线两端分别是(x1, y1)和(x2, y2)
void glib_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int color)
{
int dx,dy,e;
dx=x2-x1;
dy=y2-y1; if(dx>=)
{
if(dy >= ) // dy>=0
{
if(dx>=dy) // 1/8 octant
{
e=dy-dx/;
while(x1<=x2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){y1+=;e-=dx;}
x1+=;
e+=dy;
}
}
else // 2/8 octant
{
e=dx-dy/;
while(y1<=y2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){x1+=;e-=dy;}
y1+=;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy) if(dx>=dy) // 8/8 octant
{
e=dy-dx/;
while(x1<=x2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){y1-=;e-=dx;}
x1+=;
e+=dy;
}
}
else // 7/8 octant
{
e=dx-dy/;
while(y1>=y2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){x1+=;e-=dy;}
y1-=;
e+=dx;
}
}
}
}
else //dx<0
{
dx=-dx; //dx=abs(dx)
if(dy >= ) // dy>=0
{
if(dx>=dy) // 4/8 octant
{
e=dy-dx/;
while(x1>=x2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){y1+=;e-=dx;}
x1-=;
e+=dy;
}
}
else // 3/8 octant
{
e=dx-dy/;
while(y1<=y2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){x1-=;e-=dy;}
y1+=;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy) if(dx>=dy) // 5/8 octant
{
e=dy-dx/;
while(x1>=x2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){y1-=;e-=dx;}
x1-=;
e+=dy;
}
}
else // 6/8 octant
{
e=dx-dy/;
while(y1>=y2)
{
lcd_draw_pixel(x1,y1,color);
if(e>){x1-=;e-=dy;}
y1-=;
e+=dx;
}
}
}
}
}
本文转自:http://blog.chinaunix.net/uid-26435987-id-3077711.html
画线函数Glib_Line算法的研究的更多相关文章
- [stm32] 利用uc-gui封装画图和画线函数移植51上的模拟动画
>_<:这里的动画是黄色矩形区域中一个模仿俯视图的起重机运作动画,一个是模仿主视图的吊钩的运动.通过改变初始Init函数中的数据b_x,b_y实现矩形区域的移动.当实时采集时要首先根据起重 ...
- Bezier画线算法
编译器:VS2013 描述:Bezier画线是利用导数相同拼接曲线,使曲线十分光滑,而不是随意拼接观赏性很差 主函数段 #include "stdafx.h" #include&l ...
- matlab练习程序(Bresenham画线)
Bresenham画线算图形学中最基础的知识了,可惜我并没有选修过图形学,所有还是有必要熟悉一下. 上一篇用到的画线函数应该算是数值微分法,也是我最常用的一种方法,不过这种方法似乎并不是很好. 这里的 ...
- 计算机图形学DDA画线法+中点画线法+Bresenham画线法
#include <cstdio> #include <cstring> #include <conio.h> #include <graphics.h> ...
- 中点Brehensam画线算法
#include<stdio.h> #include<stdlib.h> #include"graphics.h" //函数声明 void MidBreha ...
- 【液晶模块系列基础视频】4.1.X-GUI图形界面库-画线画圆等函数简介
[液晶模块系列基础视频]4.1.X-GUI图形界面库-画线画圆等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地 ...
- 两种画线算法(DDA&Bersenham)
DDA(digital differential analyzer) 由直线的斜截式方程引入 对于正斜率的线段,如果斜率<=1,则以单位x间隔(δx=1)取样,并逐个计算每一个y值 Yk+1 = ...
- Bresenham画线算法
[Bresenham画线算法] Bresenham是一种光栅化算法.不仅可以用于画线,也可以用用画圆及其它曲线. 通过lower与upper的差,可以知道哪一个点更接近线段: 参考:<计算机图形 ...
- win32画线考虑去锯齿
整理日: 2015年2月16日 这几天一直在研究win32 SDk下画线去锯齿,之前一直用的QT的画线接口函数,里面有去锯齿的效果,可是突然项目要求不能用QT的只能用win32 SDK下的GDI画线接 ...
随机推荐
- 【转】ASP.NET Core 依赖注入
DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET Core的DI实现以及对实例 ...
- ArcGIS Portal与Adapter安装问题
1. WIN2008R2 80端口被system占用解决办法 修改注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP右侧的star ...
- Linux 磁盘使用查看 查看使用磁盘程序 Monitoring disk activity in linux
5 TOOLS FOR MONITORING DISK ACTIVITY IN LINUX Here is a quick overview of 5 command-line tools that ...
- OSPF协议总结
总结: 1.ospf协议报文不会泛洪扩散,而是逐级路由器处理后,再从所有ospf启用端口发送出去,也就是说,只能从邻居接收到ospf报文,报文的源ip是邻居的ip地址,目的ip是组播ip. 2.开启o ...
- PL/SQL 查询的数据出现乱码
解决方法: 1.首先在查询出Oracle数据库的字符集. select userenv('language') from dual; 2.新建系统变量 NLS_LANG,变量值为第一步查询出来的字符集 ...
- (网页)Java程序员们最常犯的10个错误(转)
转自CSDN: 1.将数组转化为列表 将数组转化为一个列表时,程序员们经常这样做: List<String> list = Arrays.asList(arr); Arrays.asLis ...
- 利用python中的gensim模块训练和测试word2vec
word2vec的基础知识介绍参考上一篇博客和列举的参考资料. 首先利用安装gensim模块,相关依赖如下,注意版本要一致: Python >= 2.7 (tested with version ...
- 用条件属性而不是#if
使用#if #endif可以在同样源码上生成不同的编辑(结果),通常是调式(debug)和发布(release)版本. 但是#if/#endif很容易被滥用,使得编写的代码难以理解和调式,所以C# ...
- Python scikit-learn (metrics): difference between r2_score and explained_variance_score?
I noticed that that 'r2_score' and 'explained_variance_score' are both build-in sklearn.metrics meth ...
- linux运行apache出现403错误
1.文档权限问题,这是linux操作系统下经常会遇到的问题,需要使用chmod的指令把网站所在目录的权限提升到755.2.SElinux,开启它也会导致403错误的产生. 查看SELinux状态:1. ...