Bresenham 算法画线 & 画圆

不问归期 提交于 2019-12-23 21:15:00

 

最近作业在做 graphics driver 涉及到 Bresenham 画线以及画圆算法,以防自己忘记了总结一些知识点以及源码。

 所有代码的输入参数类型都是 unsinged int 

  • Bresenham 直线算法

在给出直线两个端点(x1, y1) 和 (x2, y2) 的情况下,选取 (x1, y1) 作为起始点, 依次确认相应的像素点。选取哪个端点作为起点是没有关系的,因为线段并不存在方向这一说,只是和斜率有关系,下面会提到。

 

以点 (xi, yi) 为例,以 y 为步进单位, (xi, yi) 的下一个像素点为 (xi+1, yi+1) 和 (xi+1, yi) 中的一个点,那么为了确认到底应该选哪一个点,这时就要比较垂直距离 d1 和 d2 的关系。设直线的方程为 y = kx + b,其中 k=Δy/Δx, Δy = abs(y2 - y1), Δx = abs(x2 - x1)。此时

, , 

接下来可以得到

在上面这个表达式中,可以发现我们涉及到了除法运算,为了消除除法运算可能引入的误差,在等式两边同时乘 Δx, 并命名为一个新的变量

 

其中c是最终化简得到的总的常数。此时 pi 和(d1 - d2) 同号,我们可以根据 pi 的正负来判断下一个像素点的位置:

 当 pi > 0 时, d1 > d2,, 

 当 pi <= 0 时,d1 <= d2,, 

 

由于直线起点为 (x1, y1), 那么将起点坐标带入 p 的表达式后可以得出 p1 的值:

, 其中 , 化简得 

以上为 Bresenham 算法的基本思想,由于我们只讨论了步进单位为 y 的情况,也就是说以上情况中我们能得到的直线最大斜率为 1(也就是说上述过程都是在讨论 Δx > Δy 的情况)。那么对于直线斜率小于等于 1 的情况, 只需要把步进单位改成 x 就可以了。

以下为源代码:

可以直接定义 void 类型,不用返回值。

 

  • Bresenham 画圆算法

圆形算法和直线算法思想差不多,都是根据前一个像素点来选取后一个像素点的位置。由于圆的对称性,在得到圆上的一个点的同时,相当于我们同时得到了圆上互相对称的八个点,可以看下图理解一下 (坐标轴我忘画了嘻嘻嘻)

 

和直线算法同理,在点 (xi, yi) 的基础上,在 (xi+1, yi+1) 和(xi+1, yi) 中确定下一个像素点,那么按理说还是应该比较 d1 和 d2 的大小,但是这俩值并不好求(涉及到浮点数运算 blablabla),所以在这里做一个近似,令 d1 = d3 = |AC|, d2 = d4 = |BD|, , 。 同样的引入一个变量 p 来表示差值 ,情况如下:

当 pi > 0 时,选取点 (xi+1, yi+1), 

当 pi <= 0 时, 选取点 (xi+1, yi), 

 

将起始点设为 (0, r),

根据圆的八分对称性,先设置八个部分的坐标值(圆心可以任意选取), 这部分可以单独写一个函数也可以和画圆合并。代码如下:

如果想要对圆进行填充,可以选取外接正方形,判断正方形内的像素点是否在圆内来填充,也可以用 Bresenham 法画 n 个圆来填充, 由于我用第二种方法填充有部分像素点填不满,所以就先放第一种方法的代码:

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!