淮海工学院计算机工程学院
实验报告书
课程名: 计算机图形学
题 目: 绘制任意斜率的直线 班 级: 学 号: 2012122827 姓 名:
一、实验目的或要求
1. 掌握任意斜率直线的绘制算法。
2. 掌握直线中点Bresenham 算法的基本原理,能够用VC++实现该算法。
二、 实验内容
1、掌握直线段的生成算法,并用C++实现算法,包括中点法生成
直线。
2、编程实现DDA 算法、Bresenham 算法、中点画线法绘制直线段 三、实验代码
1、生成直线的DDA 算法
算法思想:一个坐标轴上以单位间隔增量,决定另一个坐标轴上最靠近线段路径的对应整数值。假定x2﹣x1的绝对值大于y2﹣y1的绝对值,取x 为一个象素单位长,即x 每次递增一个象素,然后利用下式计算相应的y 值:yk+1﹦yk ﹢△y ﹦yk ﹢m ·△x
对于|m|>1的线段,可通过计算由Y 方向的增量△y 引起的改变来生成直线: xk+1﹦xk ﹢△x ﹦xk ﹢m ·△y
生成直线的DDA 算法思想是源用初中直线的方程得出来的,而生成直线的中点算法是通过将DDA 算法的方程式改为隐函数形式,然后通过与中点的比较确定该取的像素,绘制图线。 /* DDA */
#include
void linedda(int x0,int y0,int x1,int y1,int color) {
int x,dy,dx,y; float m; dx=x1-x0; dy=y1-y0; m=dy/dx; y=y0;
for(x=x0;x
putpixel(x,(int)(y+0.5),color); y+=m; }
main() {
int a,b,c,d,e;
int graphdriver=DETECT; int graphmode=0;
initgraph(&graphdriver,&graphmode,""); cleardevice(); a=0; b=100; c=200; d=300; e=200;
linedda(a,b,c,d,e); getch(); closegraph(); }
运行结果:
VC++环境:
#include #include
// 四舍五入 int Round(float x) { }
// 使用 DDA 算法画任意斜率的直线(包括起始点,不包括终止点) void Line_DDA(int x1, int y1, int x2, int y2, int color) {
float x, y;
// 当前坐标点
return (int)(x
int steps = abs(x2 - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1);
x = (float)x1; y = (float)y1;
cx = (float)(x2 - x1) / steps; cy = (float)(y2 - y1) / steps;
for(int i = 0; i
putpixel(Round(x), Round(y), color);
颜色的点 x += cx; y += cy;
}
}
// 主函数 void main() { initgraph(640, 480);
// 测试画线
Line_DDA(100, 100, 100, 478, RED);
// 按任意键退出 getch(); }
// 在坐标 (x, y) 处画一个 color
2、Bresenham 直线算法是用来描绘由两点所决定的直线的算法,它会算出一条线段在 n 维光栅上最接近的点。这个算法只会用到较为快速的整数加法、减法和位元移位,常用于绘制电脑画面中的直线。是计算机图形学中最先发展出来的算法。 Bresenham 画法与中点法相似,都是通过每列象素中确定与理想直线最近的像素来进行直线的扫描的转换的。通过各行、各列的象素中心构造一组虚拟网格线的交点,然后确定该列象素中与此交点最近的像素。该算法的巧妙之处在于可以采用增量计算,使得对于每一列,只需要检查一个误差项的符号,就可以确定该列的所有对象。
根据直线的斜率确定选择变量在X 方向上或在Y 方向上每次递增一个单位,另一变量的增量为0或1,它取决于实际直线与最近网格点位置的距离,这一距离称为误差。设第k 步的误差为ek ,选取上面象素点后的积累误差为:ek+1﹦ek ﹢(m ﹣1)选取下面的象素点后的积累误差为:ek+1﹦ek ﹢m
/* Bresenham */程序代码如下: #include #include
// 使用 Bresenham 算法画任意斜率的直线(包括起始点,不包括终止点) void Line_Bresenham(int x1, int y1, int x2, int y2, int color) {
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;
bool interchange = false; // 默认不互换 dx、dy if (dy > dx) { }
int temp = dx; dx = dy; dy = temp;
interchange = true;
// 当斜率大于 1 时,dx 、dy 互换
}
int p = 2 * dy - dx; for(int i = 0; i
putpixel(x, y, color); if (p >= 0) { }
if (!interchange)
x += s1;
// 当斜率
if (!interchange)
y += s2;
// 当斜率 > 1 时,选取左右象素点 // 当斜率
else
x += s1;
p -= 2 * dx;
else
y += s2;
// 当斜率 > 1 时,选取 y 为步长
p += 2 * dy;
// 主函数 void main() { }
运行结果如下:
initgraph(640, 480);
// 测试画线
Line_Bresenham(10, 100, 100, 478,BLUE); Line_Bresenham(10, 478, 638, 1, RED);
// 按任意键退出 getch();
3、生成直线的中点算法
算法思想:
中点算法主要是利用椭圆的正负划分性,利用已知或以求出的点,根据递推关系来判断下一个点的位置。
中点算法有效地消除了DDA 浮点运算效率低下的问题,将直线的斜率m 转化为可加的数,然后通过中点来确定要选择的点,这样使得中点算法的效率大大提高,使之成为被图形软件广泛采用的算法之一。
代码如下:
#include #include
// 使用中点算法画任意斜率的直线(包括起始点,不包括终止点) void Line_Midpoint(int x1, int y1, int x2, int y2, int color) {
int d, d1, d2; if (-a
d = 2 * a + b; d1 = 2 * a; d2 = 2 * (a + b); while(x != x2) {
if (d
y += cy, d += d2;
// 斜率绝对值
putpixel(x, y, color); int x = x1, y = y1;
int a = y1 - y2, b = x2 - x1; int cx = (b >= 0 ? 1 : (b = -b, -1)); int cy = (a
else
}
}
}
x += cx;
putpixel(x, y, color);
else { }
// 斜率绝对值 > 1
d = 2 * b + a; d1 = 2 * b; d2 = 2 * (a + b); while(y != y2) { }
if(d
d += d1;
else
x += cx, d += d2;
y += cy;
putpixel(x, y, color);
// 主函数 void main() {
initgraph(640, 480);
// 测试画线
Line_Midpoint(100, 50, 100, 478, GREEN); Line_Midpoint(1, 478, 638, 1, BLUE);
// 按任意键退出 getch();
四、实验结果
1、 该程序实现了三种算法的直线段绘制 2、 比较三种算法的结果:
像素逼近效果由好到差依次为:Bresenham 算法、DDA 算法、中点算法 执行速度由快到慢依次为: 中点算法、DDA 算法、Bresenham 算法
五、实验分析与体会
通过此次实验我对计算机图形学有了实际的认识,计算机图形学对我们的生活有很多的益处。学习之后我知道了计算机图形学是研究怎样利用计算机来显示,生成和处理图形的原理,方法和技术的一门学科。虽然一开始有些许不懂和茫然,但是经过老师的指导,我还是完成了这次的实验。
淮海工学院计算机工程学院
实验报告书
课程名: 计算机图形学
题 目: 绘制任意斜率的直线 班 级: 学 号: 2012122827 姓 名:
一、实验目的或要求
1. 掌握任意斜率直线的绘制算法。
2. 掌握直线中点Bresenham 算法的基本原理,能够用VC++实现该算法。
二、 实验内容
1、掌握直线段的生成算法,并用C++实现算法,包括中点法生成
直线。
2、编程实现DDA 算法、Bresenham 算法、中点画线法绘制直线段 三、实验代码
1、生成直线的DDA 算法
算法思想:一个坐标轴上以单位间隔增量,决定另一个坐标轴上最靠近线段路径的对应整数值。假定x2﹣x1的绝对值大于y2﹣y1的绝对值,取x 为一个象素单位长,即x 每次递增一个象素,然后利用下式计算相应的y 值:yk+1﹦yk ﹢△y ﹦yk ﹢m ·△x
对于|m|>1的线段,可通过计算由Y 方向的增量△y 引起的改变来生成直线: xk+1﹦xk ﹢△x ﹦xk ﹢m ·△y
生成直线的DDA 算法思想是源用初中直线的方程得出来的,而生成直线的中点算法是通过将DDA 算法的方程式改为隐函数形式,然后通过与中点的比较确定该取的像素,绘制图线。 /* DDA */
#include
void linedda(int x0,int y0,int x1,int y1,int color) {
int x,dy,dx,y; float m; dx=x1-x0; dy=y1-y0; m=dy/dx; y=y0;
for(x=x0;x
putpixel(x,(int)(y+0.5),color); y+=m; }
main() {
int a,b,c,d,e;
int graphdriver=DETECT; int graphmode=0;
initgraph(&graphdriver,&graphmode,""); cleardevice(); a=0; b=100; c=200; d=300; e=200;
linedda(a,b,c,d,e); getch(); closegraph(); }
运行结果:
VC++环境:
#include #include
// 四舍五入 int Round(float x) { }
// 使用 DDA 算法画任意斜率的直线(包括起始点,不包括终止点) void Line_DDA(int x1, int y1, int x2, int y2, int color) {
float x, y;
// 当前坐标点
return (int)(x
int steps = abs(x2 - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1);
x = (float)x1; y = (float)y1;
cx = (float)(x2 - x1) / steps; cy = (float)(y2 - y1) / steps;
for(int i = 0; i
putpixel(Round(x), Round(y), color);
颜色的点 x += cx; y += cy;
}
}
// 主函数 void main() { initgraph(640, 480);
// 测试画线
Line_DDA(100, 100, 100, 478, RED);
// 按任意键退出 getch(); }
// 在坐标 (x, y) 处画一个 color
2、Bresenham 直线算法是用来描绘由两点所决定的直线的算法,它会算出一条线段在 n 维光栅上最接近的点。这个算法只会用到较为快速的整数加法、减法和位元移位,常用于绘制电脑画面中的直线。是计算机图形学中最先发展出来的算法。 Bresenham 画法与中点法相似,都是通过每列象素中确定与理想直线最近的像素来进行直线的扫描的转换的。通过各行、各列的象素中心构造一组虚拟网格线的交点,然后确定该列象素中与此交点最近的像素。该算法的巧妙之处在于可以采用增量计算,使得对于每一列,只需要检查一个误差项的符号,就可以确定该列的所有对象。
根据直线的斜率确定选择变量在X 方向上或在Y 方向上每次递增一个单位,另一变量的增量为0或1,它取决于实际直线与最近网格点位置的距离,这一距离称为误差。设第k 步的误差为ek ,选取上面象素点后的积累误差为:ek+1﹦ek ﹢(m ﹣1)选取下面的象素点后的积累误差为:ek+1﹦ek ﹢m
/* Bresenham */程序代码如下: #include #include
// 使用 Bresenham 算法画任意斜率的直线(包括起始点,不包括终止点) void Line_Bresenham(int x1, int y1, int x2, int y2, int color) {
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;
bool interchange = false; // 默认不互换 dx、dy if (dy > dx) { }
int temp = dx; dx = dy; dy = temp;
interchange = true;
// 当斜率大于 1 时,dx 、dy 互换
}
int p = 2 * dy - dx; for(int i = 0; i
putpixel(x, y, color); if (p >= 0) { }
if (!interchange)
x += s1;
// 当斜率
if (!interchange)
y += s2;
// 当斜率 > 1 时,选取左右象素点 // 当斜率
else
x += s1;
p -= 2 * dx;
else
y += s2;
// 当斜率 > 1 时,选取 y 为步长
p += 2 * dy;
// 主函数 void main() { }
运行结果如下:
initgraph(640, 480);
// 测试画线
Line_Bresenham(10, 100, 100, 478,BLUE); Line_Bresenham(10, 478, 638, 1, RED);
// 按任意键退出 getch();
3、生成直线的中点算法
算法思想:
中点算法主要是利用椭圆的正负划分性,利用已知或以求出的点,根据递推关系来判断下一个点的位置。
中点算法有效地消除了DDA 浮点运算效率低下的问题,将直线的斜率m 转化为可加的数,然后通过中点来确定要选择的点,这样使得中点算法的效率大大提高,使之成为被图形软件广泛采用的算法之一。
代码如下:
#include #include
// 使用中点算法画任意斜率的直线(包括起始点,不包括终止点) void Line_Midpoint(int x1, int y1, int x2, int y2, int color) {
int d, d1, d2; if (-a
d = 2 * a + b; d1 = 2 * a; d2 = 2 * (a + b); while(x != x2) {
if (d
y += cy, d += d2;
// 斜率绝对值
putpixel(x, y, color); int x = x1, y = y1;
int a = y1 - y2, b = x2 - x1; int cx = (b >= 0 ? 1 : (b = -b, -1)); int cy = (a
else
}
}
}
x += cx;
putpixel(x, y, color);
else { }
// 斜率绝对值 > 1
d = 2 * b + a; d1 = 2 * b; d2 = 2 * (a + b); while(y != y2) { }
if(d
d += d1;
else
x += cx, d += d2;
y += cy;
putpixel(x, y, color);
// 主函数 void main() {
initgraph(640, 480);
// 测试画线
Line_Midpoint(100, 50, 100, 478, GREEN); Line_Midpoint(1, 478, 638, 1, BLUE);
// 按任意键退出 getch();
四、实验结果
1、 该程序实现了三种算法的直线段绘制 2、 比较三种算法的结果:
像素逼近效果由好到差依次为:Bresenham 算法、DDA 算法、中点算法 执行速度由快到慢依次为: 中点算法、DDA 算法、Bresenham 算法
五、实验分析与体会
通过此次实验我对计算机图形学有了实际的认识,计算机图形学对我们的生活有很多的益处。学习之后我知道了计算机图形学是研究怎样利用计算机来显示,生成和处理图形的原理,方法和技术的一门学科。虽然一开始有些许不懂和茫然,但是经过老师的指导,我还是完成了这次的实验。