任意斜率下的Bresenham算法实现


本书3.5.3介绍了Bresenham算法,并给出代码。但是,这个代码只适用于斜率m在0<m<1.0的情况(而非书中说的|m|<1),并且只能用于从左向右画线(从右到左时依靠强制调换两点的方法,不自然,有潜在麻烦)。
结合习题,我们可以讨论其他情况(-1.0<m<0及从右向左画),并看看能否把多种情况整合到统一的过程里。使用书中的方法推导决策参数p(可以使用上下点之差,或者中点决策法),可以对|m|<0时总结下面四种情况:

      1) 0<m<1.0,从左向右画。这是书中给出的情况,关键数据如下:
           p(0) = 2Δy-Δx
           p(k)<0: p(k+1) = p(k)+2Δy,下一点(x(k)+1, y(k))
           p(k)>0: p(k+1) = p(k)+2Δy-2Δx,下一点(x(k)+1, y(k)+1)

       2) 0<m<1.0,从右向左画。
           p(0) =  Δx-2Δy
           p(k)<0: p(k+1) = p(k)-2Δy,下一点(x(k)-1, y(k))
           p(k)>0: p(k+1) = p(k)-2Δy+2Δx,下一点(x(k)-1, y(k)-1)
           注意,此处Δx,Δy均为负值,与1)相比较,p(k)的实际值完全一样。不一样处只是下一点的选取。
 
 
3) -1.0<m<0,从左向右画。 p(0) = -Δx-2Δy p(k)<0: p(k+1) = p(k)-2Δy,下一点(x(k)+1, y(k)) p(k)>0: p(k+1) = p(k)-2Δy-2Δx,下一点(x(k)+1, y(k)-1) 为了与前面判断情况尽量保持一致,3)对中p(k)的推导中乘以了-1。此处Δx为正,Δy为负。
4) -1.0<m<0,从右向左画。 p(0) = 2Δy+Δx p(k)<0: p(k+1) = p(k)+2Δy,下一点(x(k)-1, y(k)) p(k)>0: p(k+1) = p(k)+2Δy+2Δx,下一点(x(k)-1, y(k)+1) 为了与前面判断情况尽量保持一致,4)对中p(k)的推导中乘以了-1。此处Δx为负,Δy为正。 总结:结合以上四种情况中Δx,Δy的正负和p的表达式: p(0)=2|Δy|-|Δx| p(k)<0: p(k+1) = p(k)+2|Δy| p(k)>0: p(k+1) = p(k)+2|Δy|-2|Δx|
       可见其内部是完全统一的。对点的选取其实也不难处理,下一点是+1还是-1,与Δx,Δy的正负是一致的,这样就好办了。
       最后,利用对称性对|m|>1的情况的处理,我使用了递归,在递归中将x,y位置调换,并在画点的时候将二者再调换后来即可。为效率与代码安全起见,斜率为1和0时的情况单独处理。斜率为无穷大时在递归中等同于斜率为0。

void Bresenham(GLint x0, GLint y0, GLint x1, GLint y1)
{
	int static converse = 0;
	GLint const dy = y1 - y0, dx = x1 - x0;
	GLint const dxAbs = abs(dx);
	GLint const dyAbs = abs(dy);
	GLint const twoDyAbs = dyAbs * 2, twoDyMinusDxAbs = 2 * (dyAbs - dxAbs);
	GLint const stepX = ((dx == 0) ? 0 : dx / dxAbs);
	GLint const stepY = ((dy == 0) ? 0 : dy / dyAbs);
	GLfloat pk = twoDyAbs - dxAbs;
	GLint x = x0, y = y0;
	int i;


	if (dxAbs < dyAbs){
		converse = 1;
		Bresenham(y0, x0, y1, x1);
		converse = 0;
		return;
	}
	/*first, draw the initial point, it's MUST-DO*/
	if (converse == 1)
		setPixel(y, x);
	else
		setPixel(x, y);


	/*horizontal line and 45-slope-line are represented specifically for effeciency.*/
	if (dyAbs == dxAbs || dyAbs == 0 || dxAbs == 0){
		for (i = 0 ; i < dxAbs ; i++)
			if (converse == 1)
				setPixel (y += stepY, x += stepX);
			else
				setPixel (x += stepX, y += stepY);
		return;
	}


	/*Bresenham algrithm*/
	for (i = 0; i < dxAbs; i++, x += stepX){
		if (pk < 0){
			pk += twoDyAbs;
		}else {
			y += stepY;
			pk += twoDyMinusDxAbs;
		}
		if (converse == 1)
			setPixel(y, x);
		else
			setPixel(x , y);
	}
}




  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值