计算机图形学——Bresenham画线算法

38 篇文章 17 订阅
29 篇文章 2 订阅

以下摘录自《计算机图形学》
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对于特殊情况(非斜率为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()
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值