1. 问题描述:
理解基本图形元素光栅化的基本原理,实现直线绘制的中点画线算法、Bresenham算法、圆弧生成的中点画圆算法。掌握OpenGL画线及设置线的属性(颜色、线宽、线型)方法。
2. 算法描述:
1) 中心画线算法:
下面展示一些 伪代码
。
void MidPLine(int x0,int y0,int x1,int y1,void (*setPixel)(int x,int y))
{
a⬅abs(y0 - y1); b⬅abs(x0 - x1); d⬅a + b / 2;
if(y0 > y1)
{
x⬅x0; y⬅y0;
setPixel(x, y);
while (x < x1) {
if (d < 0) {
x++; y++;
d⬅d + a + b; // 取直线上方的像素点
}
else {
x++;
d += a; // 取直线下方的像素点
}
if (abs(斜率) >= 1) setPixel(y, x);
else setPixel(x, y);
}
else {
// 与上一种情况类似
}
}
2) Bresenham算法:
下面展示一些 伪代码
。
void BresLine(int x0, int y0, int x1, int y1, void (*setPixel)(int x, int y)) {
SetPixel(x0, y0); // 绘出起始点(x0,y0)
dx⬅abs(x0 - x1); // 表示两点x轴方向上的差值
dy⬅abs(y0 - y1); // 表示两点y轴方向上的差值
// 当(x0,y0)(x1,y1)表示同一个点时,退出函数。
if (dx < dy){ // 下面将斜率变换至0≤丨k丨≤1区间
flag = 1; // 此情况下丨k丨>=1,以x1,x2表示y轴的点;y1,y2表示x轴的点,以y轴为计长方向
swap_value(&x0, &y0);
swap_value(&x1, &y1);
swap_value(&dx, &dy);
}
int tx⬅ (x1 - x0) > 0 ? 1 : -1; // tx表示直线相对于起点在x轴的方向
int ty⬅ (y1 - y0) > 0 ? 1 : -1; // ty表示直线相对于起点在y轴的方向
int curx = x0;
int cury = y0;
int dS⬅2 * dy; // 用于表示迭代式中的项
int dT⬅2 * (dy - dx); // 用于表示迭代式中的项
int d⬅dS - dx; // 用于表示迭代式中的项
while (curx != x1){
if (d < 0) // 取直线下方的像素点
d += dS;
else{ // 取直线上方的像素点
cury += ty;
d += dT;
}
if(flag)
SetPixel(cury, curx);
else
SetPixel(curx, cury);
curx += tx;
}
}
3) 中心画圆算法:
下面展示一些 伪代码
。
void MidPoint_Circle(int x0,int y0,int x1,int y1,void (*setPixel)(int x,int y))
{
r⬅sqrt((1.0 * x1 - x0) * (1.0 * x1 - x0) + (1.0 * y1 - y0) * (1.0 * y1 - y0)); // 计算半径
x⬅0; y⬅r; d⬅1 - r; // 是公式中 1.25-r 取整后的结果
Cirpot(x0, y0, x, y, SetPixel); // 进行8路对称
while (x < y)
{
if (d < 0)
d += 2 * x + 3; // 表明当前中点在圆内,下一个点亮的像素点选取圆外的像素点
else {
d += 2 * (x - y) + 5; // 表明当前中点在圆外,下一个点亮的像素点选取圆内的像素点
y--;
}
x++;
Cirpot(x0, y0, x, y, SetPixel);
}
}
测试结果:
1) 使用中点画线算法(任意斜率均可以画出,函数名:MidPLine)完成画线:
实际运行结果:
2) 使用Bresenham算法(任意斜率均可以画出,函数名:BresLine)完成画线:
实际运行结果:
3) 使用中点画圆算法(函数名:MidPoint_Circle)完成画圆:
实际运行结果:
4) 用OpenGL画直线方法(函数名:OpenGLLine)完成画线:
实际运行结果:
分析与评论:
1) 中点画线算法:
本算法以起点到终点的计长方向距离 = max{|x1-x0|,|y1-y0|} 来进行扫描画线,时间复杂度为O(max{|x1-x0|,|y1-y0|})。
2) Bresenham算法:
Bresenham算法与中点画线算法一样,扫描的像素点是以起点到终点的计长方向距离 = max{|x1-x0|,|y1-y0|},所以时间复杂度也为O(max{|x1-x0|,|y1-y0|})。
3) 中点画圆算法:
以起点(x0,y0)为圆心,线段两端的距离为半径画圆。在画圆的过程中以x轴的计长方向上的值来扫描像素点,所以总的时间复杂度是O(|x结束-x起始|)。但是由于本算法中有一步将”1.25-r”取整为”1-r”将导致出现误差,如果用双精度存不取整将更精确。
4) 用OpenGL画直线方法完成画线:
相比于中间画线算法和Bresenham算法,这种算法是封装好的函数,对于初学者来说很友好,只需修改对应参数即可,可操控性强。
附录: Source Code(in C)
链接: 直线和圆弧绘制算法实现.rar
(代码仅供参考)
没有币的同学来Gitee吧!记得留下Star噢~
Jack-lllll 的Gitee仓库