针对20届微缩赛道,对于元素的处理,我认为拉线是一个必要的操作。
特别是直角固定差速的方法在高速下十分容易打滑,所以拉线是一个必要的操作,拉线比固定差速要稳定丝滑很多,而在往年的大赛到中也有补线这一思路,这两则其实思路是一样的,都是连接两个点。
有很多方法都能连接出来这两个点,无非都是那一个简单的数学公式的变种。
但是今天我想分享的一个在计算机图形学中绘制直线的一个很经典的光栅化算法,通过整数运算和误差积累确定最佳像素的位置。
首先来举个例子来详细的介绍一下这算法的原理,以及如何使用,以及具体的c语言代码。
一:算法原理
1.假设
直线起点为 (x0,y0),终点为 (x1,y1),且 0≤∣斜率∣≤1。
每次在x方向移动1个像素(主方向),y方向可能移动0或1个像素(从方向)。
2.误差的累计
定义 dx=x1−x0,dy=y1−y0。
决策参数 p 初始化为 2dy−dx。
3.每次迭代
若 p≥0,选择上方像素,更新 p=p+2(dy−dx),且 y 增加1。
若 p<0,选择下方像素,更新 p=p+2dy,且 y 不变。
-----------------------------------------------------------------------------
似乎有点抽象?不急在具体的讲解一下
二:计算逻辑
1.输入起点 (x0,y0) 和终点 (x1,y1)。
2.计算差值:
dx=∣x1−x0∣
dy=∣y1−y0∣
3.确定步长:
sx=1(若 x1>x0)或 −1(若 x1<x0)
sy=1(若 y1>y0)或 −1(若 y1<y0)
4.初始化决策参数:
p=2dy−dx
5.迭代绘制像素:
从 x0 到 x1,每次 x 增加 sx,根据 p 的值调整 y 和更新 p。
绘制每个 (x,y) 点。
----------------------------------------------
还不够详细?不急下面还有具体的运算过程
三:具体运算
比如我们绘制(0,0)到(5,3)的直线
dx=5,dy=3,初始p=2*3-5=1
1.具体逻辑
-----------------------------------------------------
到这里应该都是很清楚明了,如果你还觉得抽象?那没办法了,直接用我下面的代码吧
/*----------------------------------------------------------
** 函数名称: Bresenham_Line
** 功能描述: 使用Bresenham算法绘制高质量直线
** 输入参数:
** x0,y0 - 起点坐标
** x1,y1 - 终点坐标
** array - 目标数组(Left_Line/Right_Line)
** array_size - 数组尺寸
** 输出参数: 无
** 作者: 白一雨
----------------------------------------------------------*/
void Bresenham_Line(int x0, int y0, int x1, int y1,
int array[], int array_size)
{
// (保证y0 <= y1)
if(y0 > y1)
{
swap(&x0, &x1);
swap(&y0, &y1);
}
// 坐标边界约束
x0 = clamp(x0, 0, image_w-1);
y0 = clamp(y0, 0, image_h-1);
x1 = clamp(x1, 0, image_w-1);
y1 = clamp(y1, 0, image_h-1);
// 算法核心参数
int dx = abs(x1 - x0);
int dy = y1 - y0; // 保证dy>=0
int sx = (x0 < x1) ? 1 : -1;
int err = dx - dy;
// 垂直直线特化处理
if(dx == 0)
{
for(int y = y0; y <= y1; y++)
{
array[y] = x0;
}
return;
}
// 通用Bresenham算法
while(y0 <= y1)
{
// 写入数组并保护索引
if(y0 >= 0 && y0 < array_size)
{
array[y0] = clamp(x0, 0, image_w-1);
}
// 误差判断
int e2 = 2 * err;
if(e2 > -dy)
{
err -= dy;
x0 += sx;
}
if(e2 < dx)
{
err += dx;
y0++;
}
}
}
本人很菜,如果有不对的地方欢迎指导我