直线的扫描转换

直接计算法

假定直线的起点、终点分别为:(x1,y1), (x2,y2),且都为整数。
计算出斜率k=(y2-y1)/(x2-x1) ,
在Y轴的截距b=y1-k*x1 
这里写图片描述

这样一来,只要给定 x的值,根据解析式立即可以计算出对应的y值,然后输出(x,round(y))。这种方法直观,但效率太低,因为每一步需要一次浮点乘法、一次浮点加法和一次舍入运算。

数值微分法(DDA)

假定直线的起点、终点分别为:(x1,y1), (x2,y2),且都为整数。 
这里写图片描述

已知过端点P0 (x1, y1), P1(x2, y2)的直线段L:y=kx+b
直线斜率为:k=(y2-y1)/(x2-x1)
考虑当x从xi xi+1时y的变化规律:
设:
Δx=xi+1xi Δ x = x i + 1 − x i
xi+1=xi+Δx x i + 1 = x i + Δ x

计算:
yi+1=kxi+1+b=k(xi+Δx)+b=kxi+b+kΔx=yi+kΔx y i + 1 = k x i + 1 + b = k ( x i + Δ x ) + b = k x i + b + k Δ x = y i + k Δ x
Δx=1;yi+1=yi+k Δ x = 1 ; y i + 1 = y i + k
即:当x每递增1,y递增k(即直线斜率);
注意上述分析的算法仅适用于|k|≤1的情形。在这种情况下,x每增加1,y最多增加1。
当 |k|>1时,必须把x,y地位互换。

DDA算法就是一个增量算法

void DDALine(int x0,int y0,int x1,int y1,int color) {    
  int x;                       
    float dx, dy, y, k;                     
    dx= x1-x0, dy=y1-y0;                   
    k=dy/dx, y=y0;                     
    for (x=x0; x<=x1; x++){     
      drawpixel (x, int(y+0.5), color); 
        y=y+k;
     }
}

中点Bresenham算法

原理:每次在主位移方向上走一步,另一个方向上走不走步取决于中点误差项的值。给定理想直线的起点坐标为P0(x0,y0),终点坐标为P1(x1,y1),则直线的隐函数方程为:
F(x,y)=ykxb=0 F ( x , y ) = y − k x − b = 0
其中,直线的斜率: k=ΔyΔx=y1y0x1x0 k = Δ y Δ x = y 1 − y 0 x 1 − x 0
直线水平方向位移: Δx=x1x0 Δ x = x 1 − x 0
直线垂直方向位移: Δy=y1y0 Δ y = y 1 − y 0

理想直线将平面划分成三个区域:对于直线上的点,F(x,y)=0;对于直线上方的点,F(x,y)>0;对于直线下方的点,F(x,y)<0。
假设直线的斜率为0≤k≤1,则Δx≥Δy,所以确定x方向为主位移方向。按照Bresenham原理,x方向上每次加1,y方向上加不加1取决于中点误差项的值。
这里写图片描述

假定直线的当前点是P,沿主位移x方向走一步,下一点只能在Pu和Pd两点中选取,Pu和Pd的中点为M。显然,若中点M在理想直线的下方,则Pu点距离直线近,否则选取Pd。(u代表up,上面的像素;d代表down,下面的像素)

构造中点误差项:

Pi(xi,yi)PuPdM(xi1,yi0.5)di 从 P i ( x i , y i ) 点 出 发 选 取 下 一 像 素 时 , 需 将 P u 和 P d 的 中 点 M ( x i + 1 , y i + 0.5 ) 代 入 隐 函 数 方 程 , 构 造 中 点 误 差 项 d i 。
di=F(xi+1,yi+0.5)=yi+0.5k(xi+1)b d i = F ( x i + 1 , y i + 0.5 ) = y i + 0.5 − k ( x i + 1 ) − b

yi+1={yi+1,yi,di<0di0 y i + 1 = { y i + 1 , d i < 0 y i , d i ≥ 0

中点误差项的递推公式

  1. di<0M(xi+2yi+1.5) 当 d i < 0 时 , 下 一 步 的 中 点 坐 标 为 M ( x i + 2 , y i + 1.5 ) , 下 一 步 中 点 误 差 项 为
    di+1=F(xi+2,yi+1.5)=yi+1.5k(xi+2)b d i + 1 = F ( x i + 2 , y i + 1.5 ) = y i + 1.5 − k ( x i + 2 ) − b
    =yi+0.5k(xi+1)b+1k = y i + 0.5 − k ( x i + 1 ) − b + 1 − k
    =di+1k = d i + 1 − k
  2. di0M(xi+2yi+0.5) 当 d i ≥ 0 , 时 下 一 步 的 中 点 坐 标 为 M ( x i + 2 , y i + 0.5 ) , 下 一 步 中 点 误 差 项 为
    di+1=F(xi+2,yi+0.5)=yi+0.5k(xi+2)b d i + 1 = F ( x i + 2 , y i + 0.5 ) = y i + 0.5 − k ( x i + 2 ) − b
    =yi+0.5k(xi+1)bk = y i + 0.5 − k ( x i + 1 ) − b − k
    =dik = d i − k

中点误差项的初始值

线P0(x0,y0)xM(x0+1,y0+0.5)di 直 线 的 起 点 坐 标 为 P 0 ( x 0 , y 0 ) , x 为 主 位 移 方 向 。 因 此 , 第 一 个 中 点 是 M ( x 0 + 1 , y 0 + 0.5 ) , 相 应 的 d i 的 初 始 值 为 :
d0=F(x0+1,y0+0.5)=y0+0.5k(x0+1)b d 0 = F ( x 0 + 1 , y 0 + 0.5 ) = y 0 + 0.5 − k ( x 0 + 1 ) − b
=y0kx0bk+0.5 = y 0 − k x 0 − b − k + 0.5
x0y0线y0kx0b=0 其 中 , 因 为 ( x 0 , y 0 ) 在 直 线 上 , 所 以 y 0 − k x 0 − b = 0
d0=0.5k 所 以 d 0 = 0.5 − k

由于使用的是di的符号,可以用 2diΔx 2 d i Δ x 代替 di d i 来摆脱小数,使得算法只涉及整数运算。现有的研究已经证明:端点采用整数坐标没有什么益处,因为现在的CPU可以按照与处理整数同样的速度处理浮点数。

posted @ 2018-06-18 10:52  qianbuhan  阅读(414)  评论(0)    收藏  举报