DDA画线算法
定义
通过单位间隔
来确定线段的点,默认间隔为1,如图:
此时,已知的点为
,假设
是两点连线上的点的纵坐标
公式推导
设直线方程为:
此时进行分类讨论:
当m大小小于等于
1时,则
每次递增1,即
,
每次递增为
,公式如下:
反之,当m大小大于
1时,则
每次递增1,即
,
每次递增为
,
代码实现
#include <windows.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
// DDA算法
void lineDDA(int x0, int y0, int xend, int yend) {
int dx = xend - x0, dy = yend - y0; // 两点间的横,纵坐标间隔
float xIncrement, yIncrement, x = x0, y = y0; // 初始化x,y
int steps;
if (fabs(dx) >= dy) { // 当斜率小于等于1时
steps = fabs(dx);
}
else // 当斜率大小大于1时
{
steps = fabs(dy);
}
// 设置 Δx, Δy 的大小
xIncrement = float(dx) / float(steps);
yIncrement = float(dy) / float(steps);
//开始画点
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
glVertex2i(x0, y0);
for (int i = 0; i < steps; i++)
{
x += xIncrement;
y += yIncrement;
glVertex2f(x, y);
}
glVertex2i(xend, yend);
glEnd();
glFlush();
}
// 主方法
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glViewport(100, 100, 500, 500);
lineDDA(30, 35, 140, 200);
}
// 初始化该方法
void Init() {
glClearColor(1.0, 1.0, 1.0, 0.0);
glPointSize(5.0);
glColor3f(0.0, 0.0, 0.0);
gluOrtho2D(0.0, 600.0, 0.0, 600.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0, 0);
glutCreateWindow("lineDDA");
glutDisplayFunc(display);
Init();
glutMainLoop();
return 0;
}
效果
缺点
在浮点增量的连续叠加中,会造成取整的误差问题,是像素位置偏离实际线段,而且该过程的取整与浮点运算仍十分耗时
Bresenham画线算法
定义
该算法属于增量整数计算,不会涉及浮点数的叠加问题.Bresenham算法采用的是逐步递推的方法来确定下一个像素点的位置.注:像素点只能取整数坐标!!!!!
公式推导
- 首先我们来看一个示例:
在该图中只能取整数点
的像素坐标, 由于第k个像素点与 点最为接近,所以先假设第k个像素点坐标为 ,那么第k+1个像素点的位置可能为 ,这是我们需要计算该点与上述两点哪个最为接近
. - 我们知道该直线方程为:
,
为两端点
垂直与水平偏移量
, ,那么在 处的y的坐标为:- 该点到 的距离为:
- 该点到 的距离为:
- 然后我们就可以比较他们距离的大小
- 若结果
小于0
,说明跟下面的像素点最接近,就选择 - 若
大于等于0
,则选择
- 若结果
- 通过上述公式的对比可以发现,
像素点的选择只取决于
的符号且通过 便可以确定下一个点
的位置,为了方便我们的计算,引入了新的变量 ,作为我们的决策参数 -
,其中
为常数,我们用
来代替,于是
注:由于Δ x>0,所以对pk的正负符号无影响
- 同理
-
- 当
- 当
- 求初始值
- :
代码实现
#include <windows.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
// Bresenham 算法
void lineBresenham(int x0, int y0, int xend, int yend) {
int dx = fabs(xend - x0), dy = fabs(yend - y0);
int p = 2 * dy - dx;
int twoDy = 2 * dy, twoDyMinusDx = 2 * (dy - dx);
int x, y;
// 确定开始位置
if (x0 > xend) // x0在右侧
{
x = xend;
y = yend;
xend = x0;
}
else // x0在左侧
{
x = x0;
y = y0;
}
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
glVertex2f(x, y);
while (x<xend)
{
x++;
if (p<0)
{
p += twoDy;
}
else {
y++;
p += twoDyMinusDx;
}
glVertex2f(x, y);
}
glEnd();
glFlush();
}
// 主方法
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glViewport(100, 100, 500, 500);
lineBresenham(40, 45, 140, 135);
}
// 初始化该方法
void Init() {
glClearColor(1.0, 1.0, 1.0, 0.0);
glPointSize(5.0);
glColor3f(0.0, 0.0, 0.0);
gluOrtho2D(0.0, 600.0, 0.0, 600.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0, 0);
glutCreateWindow("lineDDA");
glutDisplayFunc(display);
Init();
glutMainLoop();
return 0;
}