Bresenham直线
算法思想:
设直线的起点为(x1, y1),终点为(x2, y2),则直线可表示为方程 y=mx+b,其中 b=y1-m∙x1, m = (y2-y1)/(x2-x1)=dy/dx。
首先讨论直线方向位于1a象限(),在这种情况下,当直线光栅化时,x每次都增加1个单元,即xi+1 = xi + 1,而y的相应增加值是多什么呢?
为了光栅化,yi+1只可能选择下图两种位置之一
yi+1的位置选择yi+1 =yi或者yi+1=yi+1,选择的原则是看精确值y与yi及yi+1的距离d1及d2的大小而定。
计算公式为
y = m(xi + 1) + b (2.1)
d1 = y - yi (2.2)
d2 = yi +1 - y (2.3)
如果d1-d2>0,则yi+1=yi+1,
否则yi+1=yi.
将式(2.1)、(2.2)、(2.3)代入d1-d2,再用dx乘等式两边,并以Pi=(d1-d2) dx代入上述等式,得
Pi = 2xidy-2yidx+2dy+(2b-1) dx
d1-d2是用以判断符号的误差。由于在1a象限,dx总大于0,所以Pi仍旧可以用作判断符号的误差。
Pi>0,则yi+1=yi+1,否则yi+1=yi.
求误差的初值P1,可将x1、y1和b代入式中的xi、yi而得到
P1 = 2dy-dx
综述上面的推导,第1a象限内的直线Bresenham算法思想如下:
- 计算两个方向的变化量:dx = x2- x1,dy= y2- y1.
- 计算误差初值P= 2dy-dx
- 求直线的下一点位置 xi+1 = xi + 1如果Pi>0,则yi+1=yi+1,否则yi+1=yi
- 画点(xi+1, yi+1);
- 然后进入循环 i=i+1求下一个误差如果Pi>0,则Pi+1=Pi+2dy-2dx,否则Pi+1=Pi+2dy;
i<x2则跳出循环结束绘制。
代码如下:
#include "graphics.h"
#include <conio.h>
#include "windows.h"
#include <math.h>
void lineBres(int x0, int y0, int xEnd, int yEnd,int c)
{
int dx = fabs (xEnd -x0), dy = fabs (yEnd-y0);
int p =2* dy-dx;
int twoDy = 2*dy, twoDyMinusDx = 2* (dy - dx);
int x,y;
if (x0>xEnd)
{
x=xEnd;
y=yEnd;
xEnd=x0;
}
else{
x=x0;
y=y0;
}
putpixel (x,y,c);
while (x<xEnd)
{
x++;
if(p<0)
p+=twoDy;
else{
y++;
p+=twoDyMinusDx;
}
putpixel (x,y,c);
}
}
void main()
{
int gd=DETECT,gm; /*图形屏幕初始化*/
initgraph(&gd,&gm,"");
lineBres(0,0,500,300,YELLOW);
lineBres(0,0,500,400,BLUE);
getch();
closegraph();
}
最终效果: