void GridLineTraversal::gridLineCore( IntPoint start, IntPoint end, GridLineTraversalLine *line )
{
int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
int cnt = 0;
dx = abs(end.x-start.x); dy = abs(end.y-start.y);
if (dy <= dx) {
d = 2*dy - dx; incr1 = 2 * dy; incr2 = 2 * (dy - dx);
if (start.x > end.x) {
x = end.x; y = end.y;
ydirflag = (-1);
xend = start.x;
} else {
x = start.x; y = start.y;
ydirflag = 1;
xend = end.x;
}
line->points[cnt].x=x;
line->points[cnt].y=y;
cnt++;
if (((end.y - start.y) * ydirflag) > 0) {
while (x < xend) {
x++;
if (d <0) {
d+=incr1;
} else {
y++; d+=incr2;
}
line->points[cnt].x=x;
line->points[cnt].y=y;
cnt++;
}
} else {
while (x < xend) {
x++;
if (d <0) {
d+=incr1;
} else {
y--; d+=incr2;
}
line->points[cnt].x=x;
line->points[cnt].y=y;
cnt++;
}
}
} else {
d = 2*dx - dy;
incr1 = 2*dx; incr2 = 2 * (dx - dy);
if (start.y > end.y) {
y = end.y; x = end.x;
yend = start.y;
xdirflag = (-1);
} else {
y = start.y; x = start.x;
yend = end.y;
xdirflag = 1;
}
line->points[cnt].x=x;
line->points[cnt].y=y;
cnt++;
if (((end.x - start.x) * xdirflag) > 0) {
while (y < yend) {
y++;
if (d <0) {
d+=incr1;
} else {
x++; d+=incr2;
}
line->points[cnt].x=x;
line->points[cnt].y=y;
cnt++;
}
} else {
while (y < yend) {
y++;
if (d <0) {
d+=incr1;
} else {
x--; d+=incr2;
}
line->points[cnt].x=x;
line->points[cnt].y=y;
cnt++;
}
}
}
line->num_points = cnt;
}
//最终在外面被使用的bresenham画线算法
void GridLineTraversal::gridLine( IntPoint start, IntPoint end, GridLineTraversalLine *line ) {
int i,j;
int half;
IntPoint v;
gridLineCore( start, end, line );
if ( start.x!=line->points[0].x ||
start.y!=line->points[0].y ) {
half = line->num_points/2;
for (i=0,j=line->num_points - 1;i<half; i++,j--) {
v = line->points[i];
line->points[i] = line->points[j];
line->points[j] = v;
}
}
}
代码来源:openslam_gmapping/gridlinetraversal.h
原理:
二、直线Bresenham算法思想之一:
由于显示直线的象素点只能取整数值座标,可以假设直线上第i个象素点座标为(xi,yi),它是直线上点(xi,yi)的最佳近似,并且xi=xi(假设m<1),如下图所示。那么,直线上下一个象素点的可能位置是(xi+1,yi)或(xi+1,yi+1)。
由图中可以知道,在x=xi+1处,直线上点的y值是y=m(xi+1)+b,该点离象素点(xi+1,yi)和象素点(xi+1,yi+1)的距离分别是d1和d2:
d1=y-yi=m(xi+1)+b-yi (2-8)
d2=(yi+1)-y=(yi+1)-m(xi+1)-b (2-9)
这两个距离差是
d1-d2=2m(xi+1)-2yi+2b-1 (2-10)
我们来分析公式(2-10):
(1)当此值为正时,d1>d2,说明直线上理论点离(xi+1,yi+1)象素较近,下一个象素点应取(xi+1,yi+1)。
(2)当此值为负时,d1<d2,说明直线上理论点离(xi+1,yi)象素较近,则下一个象素点应取(xi+1,yi)。
(3)当此值为零时,说明直线上理论点离上、下两个象素点的距离相等,取哪个点都行,假设算法规定这种情况下取(xi+1,yi+1)作为下一个象素点。
因此只要利用(d1-d2)的符号就可以决定下一个象素点的选择。为此,我们进一步定义一个新的判别式:
pi=△x×(d1-d2)=2△y·xi-2△x·yi+c (2-11)
式(2-11)中的△x=(x2-x1)>0,因此pi与(d1-d2)有相同的符号;
这里△y=y2-y1,m=△y/△x;c=2△y+△x(2b-1)。
下面对式(2-11)作进一步处理,以便得出误差判别递推公式并消除常数c。
将式(2-11)中的下标i改写成i+1,得到:
pi+1=2△y·xi+1-2△x·yi+1+c (2-12)
将式(2-12)减去(2-11),并利用xi+1=xi+1,可得:
pi+1= pi+2△y-2△x·(yi+1-yi) (2-13)
再假设直线的初始端点恰好是其象素点的座标,即满足:
y1=mx1+b (2-14)
由式(2-11)和式(2-14)得到p1的初始值:
p1=2△y-△x (2-15)
这样,我们可利用误差判别变量,得到如下算法表示:
初始 p1=2△y-△x (2-16)
当pi≥0时: yi+1=yi+1,
xi+1=xi+1,
pi+1=pi+2(△y-△x)
否则: yi+1=yi,
xi+1=xi+1,
pi+1=pi+2△y
从式(2-16)可以看出,第i+1步的判别变量pi+1仅与第i步的判别变量pi、直线的两个端点座标分量差△x和△y有关,运算中只含有整数相加和乘2运算,而乘2可利用算术左移一位来完成,因此这个算法速度快并易于硬件实现。
原理来源:https://blog.csdn.net/kakaxi2222/article/details/50708552?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task