Bresenham直线插补算法

Bresenham直线插补算法原理与matlab实现

问题说明:近期研究双振镜(四轴)激光加工系统。由于振镜有最小的脉冲当量(即最小的移动单位),需要使用到插补算法对期望直线进行处理。以下是对Bresenham直线插补算法的学习笔记。

参考资料

clever101博客

算法原理

情景:

加工直线起始点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),终止点 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)

理论部分

Bresenham算法是DDA算法画线算法的一种改进算法。本质上它也是采取了步进的思想。不过它比DDA算法作了优化,避免了步进时浮点数运算,同时为选取符合直线方程的点提供了一个好思路。首先通过直线的斜率确定了在x方向进行单位步进还是y方向进行单位步进:当斜率k的绝对值|k|<1时,在x方向进行单位步进;当斜率k的绝对值|k|>1时,在y方向进行单位步进。

d y = x 2 − x 1 dy=x_2-x_1 dy=x2x1 d x = y 2 − y 1 dx=y_2-y_1 dx=y2y1
该算法是将直线方程转换为一个迭代的过程。迭代过程是:在计长方向上(设x方向),每次坐标必变化一个单位步长(通常单位步长取1),即 x i = x i − 1 + 1 x_i=x_{i - 1} + 1 xi=xi1+1 (加、减1视dx的正负而定)。
在非计长方向上(设y方向),每次坐标值是否变化一个单位步长视误差项d而定。
d i > = 0 d_i>=0 di>=0时,即 y i = y i − 1 + 1 y_i=y_{i-1}+1 yi=yi1+1(加、减1视dy的正负而定),产生新的误差 d i + 1 = d i + 2 ( d y − d x ) d_{i+1}=d_i+2(dy-dx) di+1=di+2(dydx)
d i < 0 d_i<0 di<0时,即 y i = y i − 1 y_i=y_{i-1} yi=yi1,产生新的误差 d i + 1 = d i + 2 d y d_{i+1}=d_i+2dy di+1=di+2dy
误差项d是在同计长方向垂直的方向上,是直线的精确路径同实际产生点之间的距离,如下图所示。
在这里插入图片描述
误差项d的推导过程如下:
d x > d y dx>dy dx>dy(即斜率k<1,x方向上的总行驶路径要大于y方向)且dx,dy>0,单位步长为t(设t=1),当前点 ( x i − 1 , y i − 1 ) (x_{i-1},y_{i-1}) (xi1,yi1)是离直线最近的点。
计算下一点的坐标值,由下图可知

在这里插入图片描述
S i > = T i S_i>=T_i Si>=Ti,下一点 ( x i − 1 + 1 , y i − 1 + 1 ) (x_{i-1}+1,y_{i-1}+1) (xi1+1,yi1+1)更接近直线。
S i < T i S_i<T_i Si<Ti,下一点 ( x i − 1 + 1 , y i − 1 ) (x_{i-1}+1,y_{i-1}) (xi1+1,yi1)更接近直线。

所以
S i > = T i S_i>=T_i Si>=Ti,下一点为 ( x i − 1 + 1 , y i − 1 + 1 ) (x_{i-1}+1,y_{i-1}+1) (xi1+1,yi1+1)
S i < T i S_i<T_i Si<Ti,下一点为 ( x i − 1 + 1 , y i − 1 + 1 ) (x_{i-1}+1,y_{i-1}+1) (xi1+1,yi1+1)
由相似三角形得:
S i / t = d y / d x S_i/t=dy/dx Si/t=dy/dx
S i = ( d y / d x ) t S_i=(dy/dx)t Si=(dy/dx)t
T i = t − S i T_i=t-S_i Ti=tSi
T i = t − ( d y / d x ) t T_i=t-(dy/dx)t Ti=t(dy/dx)t
因此 S i − T i = ( 2 d y / d x ) t − t S_i-T_i=(2dy/dx)t-t SiTi=(2dy/dx)tt
可以看出 ( S i − T i ) (S_i-T_i) (SiTi)的正负决定了坐标值的变化,而与 S i − T i S_i-T_i SiTi的大小无关。因此 d x ( S i − T i ) / t dx(S_i-T_i)/t dx(SiTi)/t并不影响 S i − T i S_i-T_i SiTi的正负值。
d i = d x ( S i − T i ) / t = 2 d y − d x d_i=dx(S_i-T_i)/t=2dy-dx di=dx(SiTi)/t=2dydx
则当 d i > = 0 d_i>=0 di>=0时,走步到点
x i = x i − 1 + 1 x_i = x_{i-1}+1 xi=xi1+1
y i = y i − 1 + 1 y_i = y_{i-1}+1 yi=yi1+1
此时产生新的误差项d_{i+1},如下图所示:
在这里插入图片描述
由于 d i + 1 = d x ( S i + 1 − T i + 1 ) / t d_{i+1} = dx(S_{i+1}-T_{i+1})/t di+1=dx(Si+1Ti+1)/t
从相似三角形的关系得:
( S i + 1 + t ) / 2 t = d y / d x (S_{i+1}+t)/2t=dy/dx (Si+1+t)/2t=dy/dx
S i + 1 = d y / d x ∗ 2 t − t S_{i+1}=dy/dx * 2t - t Si+1=dy/dx2tt
T i + 1 = t − S i + 1 T_{i+1}=t-S_i+1 Ti+1=tSi+1
T i + 1 = 2 t − d y / d x ∗ 2 t T_{i+1}=2t-dy/dx*2t Ti+1=2tdy/dx2t
S i + 1 − T i + 1 = d y / d x ∗ 2 t − t − 2 t + d y / d x ∗ 2 t S_{i+1}-T_{i+1}=dy/dx*2t-t-2t+dy/dx*2t Si+1Ti+1=dy/dx2tt2t+dy/dx2t
因此 d i + 1 = 2 d y − d x − 2 d x + 2 d y = d i + 1 ∗ ( d y − d x ) d_{i+1} = 2dy-dx-2dx+2dy=d_{i+1}*(dy-dx) di+1=2dydx2dx+2dy=di+1(dydx)
d i < 0 d_i<0 di<0时,走步到点x_i=x_{i-1}+1,y_i=y_{i-1}
此时产生新的误差项 d i + 1 d_{i+1} di+1
S i + 1 / 2 t = d y / d x S_{i+1}/2t=dy/dx Si+1/2t=dy/dx
S i + 1 = d y / d x ∗ 2 t S_{i+1}=dy/dx*2t Si+1=dy/dx2t
T i + 1 = t − S i + 1 T_{i+1}=t-S_{i+1} Ti+1=tSi+1
T i + 1 = t − d y / d x ∗ 2 t T_{i+1}=t-dy/dx*2t Ti+1=tdy/dx2t
d i + 1 = 2 d y − d x + 2 d y = d i + 2 d y d_{i+1}=2dy-dx+2dy=d_i+2dy di+1=2dydx+2dy=di+2dy

结论:当i=1时, d i d_i di的初值为
d 1 = 2 d y − d x d_1=2dy-dx d1=2dydx
d i > = 0 d_i>=0 di>=0时,x,y方向坐标值都将会发生改变
x i = x i − 1 + − 1 x_i=x_{i-1}+-1 xi=xi1+1
y i = y i − 1 + − 1 y_i=y_{i-1}+-1 yi=yi1+1
加减1根据dx,dy的正负而确定。
产生新的误差项 d i + 1 = d i + 2 ( d y − d x ) d_{i+1}=d_i+2(dy-dx) di+1=di+2(dydx)
d i < 0 d_i<0 di<0时,y方向坐标值不发生改变
x i = x i − 1 + − 1 x_i=x_{i-1}+-1 xi=xi1+1
y i = y i − 1 y_i=y_{i-1} yi=yi1
产生新误差项
d i + 1 = d i + 2 d y d_{i+1}=d_i+2dy di+1=di+2dy

可以将上述结论推广为适应于 d y > d x dy>dx dy>dx不同走向的直线。此时以y方向为计长方向,每次坐标值变化一个单位步长(加减视dy的正负而定)
在x方向,坐标值是否变化一个单位步长,视误差项d而定。
d i > = 0 d_i>=0 di>=0时,
x i = x i − 1 + − 1 x_i=x_{i-1}+-1 xi=xi1+1
y i = y i − 1 + − 1 y_i=y_{i-1}+-1 yi=yi1+1
产生新的误差
d i + 1 = d i + 2 ( d x − d y ) d_{i+1}=d_i+2(dx-dy) di+1=di+2(dxdy)
d i < 0 d_i<0 di<0
x i = x i + 1 x_i=x_{i+1} xi=xi+1
y i = y i − 1 + − 1 y_i=y_{i-1}+-1 yi=yi1+1
产生新误差
d i + 1 = d i + 2 d x d_{i+1}=d_i+2dx di+1=di+2dx
当i=1
当i=1时, d的初值为 d 1 = 2 d x − d y d_1=2dx-dy d1=2dxdy。从该式中可看出,当dx<dy时,只要将x与y的坐标值进行交换,就可直接使用dx>dy时的结论来画直线。同时只要用|dy|与|dx|就可以画出不同走向的直线。
下图为用Bresenham算法画直线的流程图。

程序流程图

在这里插入图片描述
为了简化Bresenham算法,可把对误差项d的计算与判别式转变为不断比较直线所对的水平距离上的测试值(x,y),并重复对该测试值进行增加并测试。每当x,y的值增加到一个可能的新点时,就在屏幕上画出这个点。测试值(x,y)的增量与dx,dy有关。下面是简化后的Bresenham算法流程图
在这里插入图片描述
设从点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)到点 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)
d x = x 2 − x 1 dx=x_2-x_1 dx=x2x1, i x = ∣ d x ∣ ix=|dx| ix=dx
d y = y 2 − y 1 dy=y_2-y_1 dy=y2y1, i y = ∣ d y ∣ iy=|dy| iy=dy
设x,y为测试值,初值为0,0;plot为逻辑量。当plot为真时,画新点;plot为假时,不画新点。(plotx,ploty)为标识一个新点的坐标,初值为 p l o t x = x 1 plotx=x_1 plotxx1 p l o t y = y 1 ploty=y_1 plotyy1 i n c = m a x ( ∣ d x ∣ , ∣ d y ∣ ) inc=max(|dx|,|dy|) incmax(dx,dy)为终点判断条件。依据两种不同的Bresenham算法画直线(2,7)到(7,3)时所生成的数值,以及由直线算法选择的像素所绘制的直线,在所走路径上有些小小的区别,如下图所示。
在这里插入图片描述

总结

  1. 输入线段的起点和终点。

  2. 判断线段的斜率是否存在(即起点和终点的x坐标是否相同),若相同,即斜率不存在,
    只需计算y方向的单位步进(△Y+1次),x方向的坐标保持不变即可绘制直线。

  3. 计算线段的斜率k,分为下面几种情况处理

    a. k等于0,即线段平行于x轴,即程序只需计算x方向的单位步进,y方向的值不变

    b. |k|等于1,即线段的x方向的单位步进和y方向的单位步进一样,皆为1。直接循环△X次计算x和y坐标。

  4. 根据输入的起点和终点的x、y坐标值的大小决定x方向和y方向的单位步进是1还是-1

  5. 画出第一个点。

  6. 若|k| <1,设m =0,计算P0,如果Pm>0,下一个要绘制的点为(Xm+单位步进,Ym),
    Pm+1 = Pm -2△Y;
    否则要绘制的点为(Xm+单位步进,Ym+单位步进)
    Pm+1 = Pm+2
    △X-2*△Y;

  7. 重复执行第七步△X-1次;

  8. 若|k| >1,设m =0,计算Q0,如果Qm>0,下一个要绘制的点为(Xm,Ym+单位步进),
    Pm+1 = Pm -2△X;
    否则要绘制的点为(Xm+单位步进,Ym+单位步进)
    Pm+1 = Pm+2
    △Y-2*△X;

matlab实现

% AUTHOR    :CHANDAN KUMAR 
% TITLE     :BRESENHAM LINE ALGORITHM
% SUBJECT   :COMPUTER GRAPHICS AND SOLID MODELLING
% DISCLAIMER:CODE DRAWS A LINE USING BRESENHAM LINE ALGORITHM.

function bresenham_line()
clc
clear all
point = input('Give coord[ x0 y0 x1 y1]: ');

if (abs(point(4)-point(2)) > abs(point(3)-point(1)))       % If the line is steep                                
    x0 = point(2);y0 = point(1); x1 = point(4);y1=point(3);% then it would be converted to 
    token =1;                                              % non steep by changing coordinate
else
    x0 = point(1);y0 = point(2); x1 = point(3);y1=point(4);
    token = 0; 
end
if(x0 >x1)
    temp1 = x0; x0 = x1; x1 = temp1;
    temp2 = y0; y0 = y1; y1 = temp2;
end
dx = abs(x1 - x0) ;                              % Distance to travel in x-direction
dy = abs(y1 - y0);                               % Distance to travel in y-direction
sx = sign(x1 - x0);                              % sx indicates direction of travel in X-dir
sy = sign(y1 - y0);                              % Ensures positive slope line

clf, subplot(2,1,1) ,hold on , grid on ,axis([x0-1 x1+1 y0-1 y1+1]);
title('Bresenham Line Generation Algorithm: Point form')
x = x0; y = y0;                                  % Initialization of line
param = 2*dy - dx ;                              % Initialization of error parameter
for i = 0:dx-1                                   % FOR loop to travel along X
    x_coord(i+1) = x;                            % Saving in matrix form for plot
    y_coord(i+1) = y;
    if (token ==0)                               % Plotting in point form 
        plot(x,y,'r*');                          % For steep line coordinate is again
    else                                         % converted for actual line drawing.
        plot(y,x,'r*');
    end
    param = param + 2*dy;                        % parameter value is modified
    if (param >0)                                % if parameter value is exceeded
        y = y +1*sy;                             % then y coordinate is increased
        param = param - 2*(dx );                 % and parameter value is decreased
        
    end
    x = x + 1*sx;                                % X-coordinate is increased for next point
end
subplot(2,1,2)                                   % Plotting in line fragment form
if (token ==0)
    plot(x_coord,y_coord,'r-','LineWidth',2);
else
    plot(y_coord,x_coord,'r-','LineWidth',2);
end
grid on
axis([x0-1 x1+1 y0-1 y1+1]);
title('Bresenham Line Generation Algorithm: Line fragment form')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值