从零开始构建计算机系统——二维图形库(圆边)

三、绘制圆

圆的方程可以描述为( x - x0 )2 + ( y - y0 )2= r2 ,其中 ( x0, y0) 为圆心,r为圆的半径。为了简化问题,我们假设圆心就在坐标中心(0, 0),那么

( x0, y0 )= ( 0, 0 ),那么圆的方程为:x2 + y2= r2 。

圆心不在坐标原点时,只需要做简单的平移即可。

从零开始构建计算机系统——二维图形库(圆边)_第1张图片

如上图所示,圆心处于坐标原点处,此时圆具有四条对称轴:

①x = 0、②y = 0、③x = y、④x = -y

这四条对称轴将整个圆分成了八段圆弧,设圆上一点( x, y ),其对称点分别为:

( x, -y )、( -x, y )、( -x, -y ) 、( y, x )、( y, -x )、( -y, x )、( -y, -x )

这叫做圆的八分对称性。只要我们画出八段圆弧中的一段,其余七段可利用八分对称性进行变化得到。

(一)中点画圆法

我们首先画第一段圆弧,草图如下所示,从点( 0, 0 )到( ri, ri )圆弧与线段P1P2相交于一点,M点为线段P1P2中点,假设当前点为Pi( xi, yi),由于每次步进一个像素,因此,

M点坐标为( xi + 1, yi– 0.5 ),P1点坐标为( xi + 1, yi),P2点坐标为( xi+ 1, yi+ 1 )。

从图上我们可以知道,下一个坐标点要么是P1,要么是P2,到底哪个点离圆弧最近,线段中点M点在圆弧与线段交点的Y坐标情况。

从零开始构建计算机系统——二维图形库(圆边)_第2张图片

设圆的判别函数为:

F( x, y ) = x2 + y2 -r

我们知道,对于圆上任何一点F( x, y ) = 0,圆外的一点F( x, y ) > 0,圆内的一点F( x, y ) < 0。

我们将M点的坐标代入,如果F( xi+ 1, yi–0.5 ) < 0,说明M点在圆内,下一个点为P2,因为它离圆弧最近。如果F(xi+ 1, yi–0.5 ) > 0,说明M点在圆外,下一个点为P1,因为它离圆弧最近。设

di= F(xi+1, yi– 0.5)= (xi+1)2+ (yi– 0.5)2– r2

di < 0,则取P1为下一个点,即

xi+1 = xi + 1

yi+1 = yi

此时P1的下一个点的判别式为:

    di+1= F(xi+ 2, yi– 0.5)= (xi+ 2)2+ (yi–0.5)2– r2

展开后将di带入可得到判别式的递推关系:

di+1 = di + 2xi+ 3

di > 0,则取P2为下一个点,即

xi+1 = xi + 1

yi+1 = yi – 1

此时P2的下一个点的判别式为:

di+1 = F(xi+ 2, yi– 1.5)= (xi+ 2)2+ (yi–1.5)2– r2

展开后将di带入可得到判别式的递推关系:

di+1 = di + 2(xi- yi) + 5

在第一个象限的第一个点(0, R)时,即当i=0,x0=0,y0=r,判别式d的初始值d0:

d0= F(1, r – 0.5) = 1 – (r– 0.5)2– r2= 1.25 - r

我们对上面的推导加以整理,可以得出:对于(0, R)至( ri, ri)的圆弧,

x0 = 0,y0=r,d0= 1.25 - r

di < 0,

xi+1= xi + 1

yi+1= yi

di+1 = di + 2xi+ 3

否则,di > 0

xi+1= xi + 1

yi+1= yi – 1

di+1 = di + 2(xi- yi)+ 5

设圆心坐标为( ∆x, ∆y ),那么相当于对圆心在坐标原点的圆进行平移( ∆x, ∆y ),设原坐标为( x, y ),与偏移后的坐标( X, Y )满足如下关系:

X = x +∆x,Y = y + ∆y

同时,其它七段圆弧满足对称关系,也可以很容易得出:

( X, -Y )、( -X, Y)、( -X, -Y ) 、( Y, X )、( Y, -X )、( -Y, X )、( -Y, -X )

上面计算判别时使用了浮点数,即d0= 1.25 – r,因此我们需要做进一步优化。

(二)Bresenham画圆法

Bresenham画圆法主要针对中点画圆法进行了改进,将d的计算放大两倍,同时将初始值改成3–2r,这样避免了浮点运算,乘二运算也可以用移位快速代替,采用3–2r为初始值的改进算法。还有一种方法是将d的初始值由1.25–r改成1–r,考虑到圆的半径r总是大于2(像素的最小单位是1),因此这个修改不会影响d的初始值的符号,同时可以避免浮点运算。

根据Bresenham算法,将d放大两倍,可得到:

x0 = 0,y0=r,d0= 3 - 2r

di < 0,

xi+1= xi + 1

yi+1= yi

di+1 = di + 4xi+ 6

否则,di > 0

xi+1= xi + 1

yi+1= yi – 1

di+1 = di + 4(xi- yi)+ 10

(三)正负判定画圆法

在上述画法中,主要的判断依据是哪个点距离圆弧近。在像素的世界里,一个一个点将整个平面切分成了离散的网格,这些像素点要么在圆弧内,要么在圆弧外,要么在圆弧上。无论在哪,始终都是聚集在圆弧的附近,而且尽可能的近。之前的分析中我们知道,已知当前一点Pi( xi, yi),那么下一个点可选位置有两个:P1 ( xi+1, yi)或者P2 (xi+1, yi+1)。为了确保每个点“始终都是聚集在圆弧的附近”,我们采用一种修正的方式,即:如果当前点Pi在圆内,说明当前向着圆心的方向远离了圆弧,为了修正,那么下一个点就应该选取背离圆心方向的点;如果当前点Pi在圆外,说明当前背离圆心的方向远离了圆弧,为了修正,那么下一个点就应该选取向着圆心方向的点。因此,我们可以看出,每次在选取点的时候,都是对当前点的一种修正,修正量为1个单位,要么在Y方向,要么在X方向。如下图所示:

从零开始构建计算机系统——二维图形库(圆边)_第3张图片

具体的实现方式,将当前点Pi( xi, yi)代入判别式,

①当F(xi, yi)≤ 0,

取xi+1 = xi+1,yi+1= yi。即向右走一步,从圆内走向圆外。对应图(a)中的从Pi到Pi+1。

F(xi+1, yi+1)= F(xi+1,yi) = (xi+1)2+yi2-R2 = (xi2+yi2-R2)+2xi+1 = F(xi,yi)+2xi+1

②当F(xi, yi)> 0,

取xi+1 = xi,yi+1= yi- 1。即向下走一步,从圆外走向圆内。对应图(b)中的从Pi到Pi+1。

F(xi+1, yi+1)= F(xi,yi-1) = xi2+(yi-1)2 - R2 = (xi2+yi2-R2) - 2yi + 1 = F(xi,yi) - 2yi+1

对上面分析进行整理,得到

x0 = 0,y0=r,d0= 0

di ≤ 0,

xi+1= xi + 1

yi+1= yi

di+1 = di + 2xi+ 1

否则,di > 0

xi+1= xi

yi+1= yi – 1

di+1 = di- 2yi + 1

需要注意的是:改进的中点划线算法和正负法虽然都避免了浮点运算,并且计算判别式时用到的乘法都是乘2运算,可以用移位代替,但是实际效率缺有很大差别。因为正负法并不是严格按照x方向步进的,因此就会出现在某个点的下一个点在两个位置上重复画点的问题,增加了不必要的计算,可见下图。此外,从生成圆的质量看,中点画圆法和改进的中点画圆法都比正负法效果好。

从零开始构建计算机系统——二维图形库(圆边)_第4张图片

防止格式错误,下面是排好版的图片:

从零开始构建计算机系统——二维图形库(圆边)_第5张图片
从零开始构建计算机系统——二维图形库(圆边)_第6张图片
从零开始构建计算机系统——二维图形库(圆边)_第7张图片
从零开始构建计算机系统——二维图形库(圆边)_第8张图片
从零开始构建计算机系统——二维图形库(圆边)_第9张图片
从零开始构建计算机系统——二维图形库(圆边)_第10张图片

你可能感兴趣的:(从零开始构建计算机系统——二维图形库(圆边))