直线段的扫描算法——数值微分法

直线方程

根据直线的几何特征可确定直线路径的像素位置。直线的笛卡尔斜率截距方程为

y = k * m + b

其中,k 表示直线的斜率,b 是y 轴的截距。通过给定直线上的两点坐标可以计算出k 和b 的值:
k = (y1 - y0) / (x1 - x0)

b = y0 - k x0*

显示直线的算法则以以上三个式子给说的计算方法作为基础,对于任何沿直线给定的x 增量 ∆x,可以从等式 k = (y1 - y0) / (x1 - x0) 中计算出对应的y 的增量 ∆y:
∆y = k * ∆x

同上,指定的∆y 的x 增量 ∆x:
∆x= ∆y /k

这些方程形成了模拟设备中确定偏转电压的基础,其中有可能造成微小偏转的电压变化。对于具有斜率绝对值 |k| < 1 的直线可以设置一个较小水平的偏转电压 ∆x,对应的垂直偏转电压则由以上等式计算出来设定。同样的方法可以设定
|k| > 1 的直线。


以上介绍绘制直线的主要过程,下面将介绍数值微分法(DDA)

主要思想:增量思想


对于上面直线方程部分内容,可以看出在每次寻找像素点时,计算机需要进行加法和乘法运算。学过计算机组成原理的同学都会知道,计算机做加法运算是最快的,所以有没有一种方法可以将其简化成只做加法运算。

设直线上两点 (xi,yi), (xi+1,yi+1).


yi = k * xi +b(一)
yi+1 = k * xi+1 +b(二)
=k * (xi+1) + b
=k * xi + b + k
=yi + k

即,yi+1=yi + k,表示当前步的y 值等于前一步y 值加上斜率k 。最终只剩加法运算,则达到了加快运算速度的目的。

这个算法可以概括为下面的过程:
       输入线段两端点的像素位置,端点位置间的水平和垂直差值赋值给参数dx 和 dy。 绝对值大的参数确定steps 的值。从像素位置(x0,y0)开始,确定沿线段生成下一个像素位置的每一步所需的偏移量,并循环上述过程seteps 次。假如dx 的绝对值大于 dy 的绝对值,且x0 小于xEnd,那么x和y方向的增量值分别为1 和 m 。假如x方向的变化较大,但x0 大于xEnd, 那么就此啊用减量 -1 和 -m 来生成线段上的每个点。在其他情况下,y 方向使用单位增量(或减量),x 方向使用1/m 的增量(或减量)。

算法实现代码:

#include<stdlib.h>
#include<math.h>
inline int round(const float a){
    return int (a+0.5);
     }
void lineDDA(int x0, int y0, int xEnd, int yEnd){
    int dx = xEnd - x0, dy = yEnd - y0;
    int steps, k;
    float xIncrement, yIncrement, x = x0,y = y0;
    if(fabs(dx) > fabs(dy))
        steps = fabs(dx);
    else 
        steps = fabs(dy);
    xIncrement = float(dx) / float(steps);
    yIncrement = float(dy) /float(steps);
    setPixel(round(x),round(y));
    for(k=0; k<steps; k++){
        x += xIncrement;
        y += yIncrement;
        setPixel(round(x),round(y));
     }
} 
posted @ 2017-07-29 15:44  壹言  阅读(910)  评论(0编辑  收藏  举报