以下摘录自《计算机图形学》
对于特殊情况(非斜率为0~1区间情况)
注意,正在计算的P,是在决定下一个点在哪里。
附上栅格地图的画线算法以更新free:
std::vector<GridIndex> TraceLine(int x0, int y0, int x1, int y1) // 划线算法
{
GridIndex tmpIndex;
std::vector<GridIndex> gridIndexVector;
bool steep = abs(y1 - y0) > abs(x1 - x0); // 斜率是否在一定范围内
// 如果超过45度,则交换
if (steep)
{
std::swap(x0, y0);
std::swap(x1, y1);
}
// 保证x0小于x1
if (x0 > x1)
{
std::swap(x0, x1);
std::swap(y0, y1);
}
// 以上工作均是为了约束问题条件
int deltaX = x1 - x0;
int deltaY = abs(y1 - y0);
int error = 0;
int ystep;
int y = y0;
if (y0 < y1)
{
ystep = 1;
}
else
{
ystep = -1;
}
int pointX;
int pointY;
for (int x = x0; x <= x1; x++)
{
if (steep)
{
pointX = y;
pointY = x;
}
else
{
pointX = x;
pointY = y;
}
error += deltaY;
if (2 * error >= deltaX)
{
y += ystep;
error -= deltaX;
}
//不包含最后一个点.
if(pointX == x1 && pointY == y1) continue;
//保存所有的点
tmpIndex.SetIndex(pointX,pointY);
gridIndexVector.push_back(tmpIndex);
}
return gridIndexVector;
}
但是发现有一丝小bug,当x0大于x1时从终点开始画线,但是不记录的是起点,因为此时起点才是occupied。
debug后:
std::vector<GridIndex> TraceLine(int x0, int y0, int x1, int y1) // 画线算法 《计算机图形学》 https://blog.csdn.net/weixin_44684139/article/details/105828962
{
GridIndex tmpIndex;
std::vector<GridIndex> gridIndexVector;
bool steep = abs(y1 - y0) > abs(x1 - x0); // 斜率的绝对值是否在0-1内
// 如果超过1,则交换xy,因为Bresenham画线算法定义于斜率0-1中
if (steep)
{
std::swap(x0, y0);
std::swap(x1, y1);
}
// 保证x0小于x1,也是为了迁就算法的使用条件——这里可以理解为从终点向起点画线,是一样的
// 但是要打个标记
int flag = 0;
if (x0 > x1)
{
std::swap(x0, x1);
std::swap(y0, y1);
flag = 1;
}
// 以上工作均是为了约束问题条件
int deltaX = x1 - x0;
int deltaY = abs(y1 - y0);
int error = 0;
int ystep;
int y = y0;
// 决定y的扫描是递增还是递减
if (y0 < y1)
{
ystep = 1;
}
else
{
ystep = -1;
}
int pointX;
int pointY;
for (int x = x0; x <= x1; x++)
{
if (steep) // 斜率绝对值大于1的情况,之前交换了xy坐标,因此在这里要交换回来
{
pointX = y;
pointY = x;
}
else
{
pointX = x;
pointY = y;
}
error += deltaY;
if (2 * error >= deltaX) // 记得,正在计算的Pk,是要决定下一个点画在哪里
{
y += ystep;
error -= deltaX;
}
//不包含最后一个点.
// 这里貌似有bug?x0>x1的情况将起点终点交换
// 那么这种情况应该不考虑起点才对
// 所以设置一个flag
if (flag==0)
{if(pointX == x1 && pointY == y1) continue;}
else
{if(pointX == x0 && pointY == y0) continue;}
//保存所有的点
tmpIndex.SetIndex(pointX,pointY);
gridIndexVector.push_back(tmpIndex);
}
return gridIndexVector;
}
python实现画线算法:
# 通用的Bresenham算法
def GenericBresenhamLine(x1, y1, x2, y2):
dx = abs(x2 - x1)
dy = abs(y2 - y1)
# 根据直线的走势方向,设置变化的单位是正是负
s1 = 1 if ((x2 - x1) > 0) else -1
s2 = 1 if ((y2 - y1) > 0) else -1
# 根据斜率的大小,交换dx和dy,可以理解为变化x轴和y轴使得斜率的绝对值为[0,1]
boolInterChange = False
if dy > dx:
np.swapaxes(dx, dy)
boolInterChange = True
# 初始误差
e = 2 * dy - dx
x = x1
y = y1
plt.plot([x1,x2],[y1,y2])
for i in range(0, int(dx + 1)):
plt.scatter(x, y, color='red')
if e >= 0:
# 此时要选择横纵坐标都不同的点,根据斜率的不同,让变化小的一边变化一个单位
if boolInterChange:
x += s1
else:
y += s2
e -= 2 * dx
# 根据斜率的不同,让变化大的方向改变一单位,保证两边的变化小于等于1单位,让直线更加均匀
if boolInterChange:
y += s2
else:
x += s1
e += 2 * dy
plt.grid()
plt.show()