于画线函数Glib_Line算法的研究

本文详细解读了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/2;

while(x1<=x2)

{

PutPixel(x1,y1,color);

   if(e>0){y1+=1;e-=dx;}

       x1+=1;

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

这些环境变量和自动检测结果(`ac_cv_*` 和 `glib_cv_*`)通常用于 **GLib 库的编译配置过程**,它们会覆盖 `configure` 脚本的自动检测逻辑,直接指定某些功能的可用性或系统特性。以下是详细解析: --- ### **1. 变量分类与作用** | 变量 | 类型 | 含义 | |------|------|------| | **`glib_cv_long_long_format=ll`** | 数据类型支持 | 指定 `long long` 类型的格式符为 `"ll"`(如 `printf("%lld", ...)`) | | **`glib_cv_stack_grows=no`** | 系统特性 | 声明栈的生长方向为**向下**(常见于x86/ARM架构) | | **`glib_cv_have_strlcpy=no`** | 函数检测 | 强制声明系统**无** `strlcpy` 函数(避免自动检测) | | **`glib_cv_have_qsort_r=yes`** | 函数检测 | 声明系统**有** `qsort_r` 函数(GNU扩展的线程安全排序) | | **`glib_cv_va_val_copy=yes`** | 编译器特性 | 声明编译器支持 `va_arg` 值拷贝(可变参数处理) | | **`glib_cv_uscore=no`** | 符号规则 | 声明C符号(函数名)**不**需要加下划线前缀 | | **`glib_cv_rtldglobal_broken=no`** | 动态链接器 | 声明动态链接器(如 `ld.so`)能正确处理 `RTLD_GLOBAL` | | **`ac_cv_func_posix_getpwuid_r=yes`** | 函数检测 | 声明系统有 POSIX 标准的 `getpwuid_r` 函数 | | **`ac_cv_func_posix_getgrgid_r=yes`** | 函数检测 | 声明系统有 POSIX 标准的 `getgrgid_r` 函数 | --- ### **2. 典型应用场景** #### **(1) 跨平台编译时绕过自动检测** ```bash # 在交叉编译环境中,直接指定已知结果以避免检测失败 export glib_cv_have_strlcpy=no export ac_cv_func_posix_getpwuid_r=yes ./configure --host=arm-linux-gnueabihf ``` #### **(2) 解决不一致的系统环境问题** ```bash # 当系统实际有函数但检测错误时,强制启用 export glib_cv_have_qsort_r=yes ./configure ``` --- ### **3. 注意事项** - **优先级**:这些变量会**覆盖** `configure` 的检测逻辑,需确保值与目标系统一致。 - **依赖关系**:例如 `qsort_r` 的可用性可能影响 GLib 的线程安全实现。 - **格式要求**: - 布尔值必须为 `yes`/`no`(不能是 `true`/`false`)。 - 字符串值如 `ll` 需符合预期(如 `printf` 格式符)。 --- ### **4. 如何验证检测结果** 检查 `config.log` 或生成的 `config.h`: ```bash grep "checking for qsort_r" config.log # 查看原始检测过程 grep "#define HAVE_QSORT_R" config.h # 确认最终结果 ``` --- ### **5. 常见问题** - **错误:`undefined reference to 'qsort_r'`** 若实际系统无此函数但强制设为 `yes`,需改为 `no` 并重新编译。 - **栈方向错误**:若误设 `glib_cv_stack_grows=yes` 可能导致内存错误。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值