前言
由于项目上遇到了棘手的问题,给定坐标需要实现C绘制直线的驱动函数,绘制直线一般都是显示屏的底层函数,本想着找个显示屏的驱动看下drawline源码,但仔细想一想会不会底层用的是汇编尼,于是便放弃了这种想法。通过百度学习到这是计算机图形学方面的,寻找到了解决办法就是自己用C实现,网上有三种方法:
- 数值微分DDA(Digital Differential Analyzer)算法
- 中点画线算法
- Bresenham算法
这三种方法的优缺点知乎——《不调用画图 API,用C 或 C++ 如何实现画一条线?》上面说的很清楚,还有腾讯的游戏开发、计算机图形学方面的高级工程师也有在知乎讲到《用 C 语言画直线》,我是采用了最后一种方法。
一. 代码
// 来自知乎
char pic[50][50] = {0};
void show_pic(){
for(int i=49;i>=0;--i){
for(int j=0;j<50;j++){
if(pic[i][j]==1) printf("x ");
else printf("o ");
}
printf("\n");
}
}
void drawline_old(int x0,int y0,int x1,int y1){
int dx = abs(x0-x1);
int dy = abs(y0-y1);
printf("dx: %d,dy: %d \n",dx,dy);
int y = y0,e = -2*dx;
for(int x=x0; x<=x1;++x){
pic[y][x] = 1;
e += 2*dy;
if(e > 0) ++y;
if(e >= dx) e -= 2*dx;
}
}
// 使用 Bresenham 算法画任意斜率的直线(包括起始点,不包括终止点)
void Line_Bresenham(int x1, int y1, int x2, int y2){
int x = x1;
int y = y1;
int dx = abs(x2 - x1);
int dy = abs(y2 - y1);
int s1 = x2 > x1 ? 1 : -1;
int s2 = y2 > y1 ? 1 : -1;
char interchange = 0; // 默认不互换 dx、dy
if (dy > dx) // 当斜率大于 1 时,dx、dy 互换
{
int temp = dx;
dx = dy;
dy = temp;
interchange = 1;
}
int p = 2 * dy - dx;
for(int i = 0; i < dx; i++)
{
pic[y][x] = 1;
if (p >= 0)
{
if (!interchange) // 当斜率 < 1 时,选取上下象素点
y += s2;
else // 当斜率 > 1 时,选取左右象素点
x += s1;
p -= 2 * dx;
}
if (!interchange)
x += s1; // 当斜率 < 1 时,选取 x 为步长
else
y += s2; // 当斜率 > 1 时,选取 y 为步长
p += 2 * dy;
}
}
int main(void) {
//drawline_old(2,2,50,10);
Line_Bresenham(2,2,50,10);
show_pic();
return EXIT_SUCCESS;
}
二. 实测效果
实际测试了两个函数,easyx给出的方法可靠考虑的比较全面,可以拿过来移植。最近工作收获挺多的,也不知道未来会深入到哪一个方向,先记下来,图形学还是蛮好玩的。最后推荐一下EasyX ,看他文章虽然比较老了,但是都是精华。
EasyX Library for C++ 是针对 VC 的一套绘图库,接口简单易用,用起来很像 TC 的 graphics.h 绘图。