计算机图形学基础 : 基本图形生成算法之圆的扫描转换


圆的扫描转换

前置声明:我们只考虑圆心在原点,半径为整数R的圆x^2 + y^2 = R^2。 对于中心不在原点的圆,可以通过相应的平移变换来转化为圆心在原点的圆。

中点画圆法

我们考虑中心在原点,半径为R的圆的第二8分圆,如下有图所示:




讨论从(0, R) 到 (R/√2, R/√2)顺时针的确定最佳逼近于圆弧的像素序列。

假设x坐标为Xp的像素中与圆弧最近者已确定为P(xp, yp),那么下一个像素只能是正右方的P1(xp + 1, yp) 或者是右下方的 P2(xp +1, yp - 1)两者之一。
构造函数: F(x, y) = x^2 + y^2 - R^2



类似于中点画线法, M坐标为(xp + 1, yp - 0.5),F(M) < 0, M在圆内,则P1离圆弧更近,F(M) > 0,M在圆外,则P2离圆弧更近,F(M) = 0,约定取P2。

构造判别式: d = F(M) = F(xp + 1, yp - 0.5) = (xp + 1)^2 + (yp - 0.5)^2 - R^2.

如果d < 0 则P1 为下一个像素点,而且再下一个像素的判别式为:
d = F(M) = F(xp + 1 + 1, yp - 0.5) = (xp + 1 + 1)^2 + (yp - 0.5)^2 - R^2 = d + 2*xp + 3.
因此,沿正右方,d的增量为 2*xp + 3。

如果d > 0 则P2 为下一个像素点,而且再下一个像素的判别式为:
d = F(M) = F(xp + 1 + 1, yp - 1 - 0.5) = (xp + 1 + 1)^2 + (yp - 1 - 0.5)^2 - R^2 = d + (2*xp + 3) + (-2*yp + 2).
因此,沿正右方,d的增量为 2*(xp - yp) + 5。

d0 = F(1, R - 0.5) = 1.25 - R.

可以看到,d的初始值使用了浮点数来表示,会了简化算法,摆脱浮点数使用整数,我们使用e = d - 0.25代替d。因此,初始化运算d = 1.25 - r对应于e = 1 - r,判别式d < 0 对应于e < -0.25,由于e的值为整数,因此 e < -0.25 等价于 e < 0,算法中e仍用d 来表示,根据上述分析,中点画圆法的算法如下:

void MidPointCircle(int r, int color)
{
	int x, y, d;
	x = 0;
	y = r;
	d = 1 - r;
	DrawPixel(x, y, color);
	while (x < y)
	{
		if (d < 0)
		{
			d += 2 * x + 3;
			++x;
		}
		else
		{
			d += 2 * (x - y) + 5;
			++x;
			--y;
		}
		DrawPixel(x, y, color);
	}
}


Bresenham画圆算法

讨论圆心在原点,半径为整数R的第一个4分圆。取(0, R)为起点,按顺时针方向生成圆。



如上图右,假定(x, y)为已经确定的点,那么下一个像素点可能为正右方的H(x + 1, y)、右下方D(x + 1, y - 1)或者V(x, y - 1)。
理想圆弧与这三个候选点之间的关系有下列五点情况:
1. H、D、V全在圆内
2. H在圆外,D、V在圆内
3. D在圆上,H在圆外,V在圆内
4. H、D在圆外,V在圆内
5. H、D、V全在圆外

上述三点到圆心的距离平方与圆弧上一点到圆心的距离平方之差分别为:
△H = (x + 1)^2 + y^2 - R^2
D = (x + 1)^2 + (y - 1)^2 - R^2
V = x^2 + (y - 1)^2 - R^2

如果△D < 0,那么右下方像素D在圆内,圆弧与候选点的关系只可能是 1 和 2的情形。显然,这时最逼近圆弧的像素只可能是H或者D这两个像素之一。
令 △HD = | △H | - | △D | = | (x + 1)^2 + y^2 - R^2 | - | (x + 1)^2 - (y - 1)^2 - R^2 |, 若△HD < 0,则圆到正右方像素H的距离小于圆到D的距离,这时应取H为下一个像素;若△HD > 0,则选取D为下一个像素点,当△HD = 0时,约定取正右方像素H。

对于情形2,H总在圆外,D总在圆内,因此△H >= 0, △D < 0,所以△HD可以简化为:△HD = △H + △D = 2*△D + 2*y - 1.
对于情形1,这时,H、D都在圆内,而在这段圆弧上,y是x的单调递减函数,所以只能取H为下一像素。 由于△H < 0且 △D < 0,因此2*△D + 2*y - 1 < 0。 
可见△D < 0的情况下,若2(△D + y) - 1 <= 0,则应取H为下一像素,否则应取D为下一像素。

再讨论△D > 0的情况,这时,右下方像素D在圆外,最佳逼近圆弧的像素只可能是D与V二者之一。

先考虑情形4,令△DV = | △D | - | △V | = | (x + 1)^2 + (y - 1)^2 - R^2 | - | x^2 + (y - 1)^2 - R^2 |
如果△DV < 0,即圆到右下方像素距离较小,应取右下方像素D;如果△DV > 0,圆到正下方像素V的距离较小,应取V;当△DV = 0时,约定取右下方像素D。
由于右下方像素D在圆外,而正下方像素V在圆内,所以△D >= 0, △v < 0 因此:
DV = △D + △V = 2(△D - x) - 1

对于情形5,D和V都在圆外,显然应取V作为下一个像素。这时△D > 0且 △V > 0,因此 2(△D - x) - 1 > 0
可见,在△D > 0的情况下,若2(△D - x) - 1 <= 0,应取D为下一像素,否则去V作为下一像素。

归纳一下,计算下一像素的算法为:
当△D > 0, 若△DV <= 0,则取D,否则取V
当△D < 0, 若△HD <= 0,则取H,否则去D
当△D = 0,取D


△HD和△DV 可由△D推算出来:
1. 考虑下一个像素为H的情况,像素H(x', y') = (x + 1, y),误差项为: △D' = ((x + 1) + 1)^2 + (y + 1)^2 - R^2 = △D + 2(x + 1) + 1 = △D + 2*x' + 1
2. 再考虑下一个像素为D的情况,像素D(x', y') = (x + 1, y - 1), △D' = △D + 2x' -2y' + 2
3. 下一个像素为V的情况,像素V(x', y') = (x, y - 1),△D‘ = △D - 2y' = 1

综上所述,完整的Bresenham算法为:

void BresenhamCircle(int r, int color)
{
	int x, y, delta, delta1, delta2, direction;
	x = 0;
	y = r;
	delta = 2*(1-r); // △D的初始值
	while( y >= 0)
	{
		DrawPixel(x, y, color);
		if (delta < 0)
		{
			delta1 = 2 * (delta + y) - 1;
			if (delta1 <= 0) 
				direction = 1;
			else
				direction = 2;
		}
		else if (delta > 0)
		{
			delta2 = 2 * (delta - x) - 1;
			if (delta2 <= 0)
				direction = 2;
			else
				direction = 3;
		}
		else 
			direction = 3;

		switch(direction)
		{
			case 1:
				++x;
				delta += 2 * x + 1;
				break;
			case 2:
				++x;
				--y;
				delta += 2 * (x - y + 1);
				break;
			case 3:
				--y;
				delta += (-2 * y + 1);
				break;
		}
	}
}


  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值