通过单位间隔
来确定线段的点,默认间隔为1,如图:
此时,已知的点为 ( x 0 , y 0 ) , ( x e n d , y e n d ) (x_0,y_0), (x_{end},y_{end}) (x0,y0),(xend,yend),假设 y k 与 y k + 1 y_k与y_{k+1} yk与yk+1是两点连线上的点的纵坐标
设直线方程为: y = m x + b , m = y e n d − y 0 x e n d − x 0 y = mx + b,m=\frac{y_{end}-y0}{x_{end}-x_0} y=mx+b,m=xend−x0yend−y0
此时进行分类讨论:
当m大小小于等于
1时,则 x x x每次递增1,即 Δ x = 1 \Delta x=1 Δx=1, y y y每次递增为 m m m,公式如下:
y k + 1 = y k + m Δ x ( Δ x = 1 ) y_{k+1} = y_k + m\Delta x(\Delta x=1) yk+1=yk+mΔx(Δx=1)
反之,当m大小大于
1时,则 y y y每次递增1,即 Δ y = 1 \Delta y=1 Δy=1, x x x每次递增为 1 m \frac{1}{m} m1,
x k + 1 = x k + 1 m Δ y ( Δ y = 1 ) x_{k+1}=x_k+\frac{1}{m}\Delta y(\Delta y=1) xk+1=xk+m1Δy(Δy=1)
#include
#include
#include
#include
#include
#include
// 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算法采用的是逐步递推的方法来确定下一个像素点的位置.注:像素点只能取整数坐标!!!!!
整数点
的像素坐标, 由于第k个像素点与 ( x k , y k ) (x_k,y_k) (xk,yk)点最为接近,所以先假设第k个像素点坐标为 ( x k , y k ) (x_k,y_k) (xk,yk),那么第k+1个像素点的位置可能为 ( x k + 1 , y k ) 或 ( x k + 1 , y k + 1 ) (x_{k+1},y_k)或(x_{k+1},y_{k+1}) (xk+1,yk)或(xk+1,yk+1),这是我们需要计算该点与上述两点哪个最为接近
.垂直与水平偏移量
, m = Δ y Δ x m=\frac{\Delta y}{\Delta x} m=ΔxΔy,那么在 x k + 1 x_{k+1} xk+1处的y的坐标为: y = m ( x k + 1 ) + b = m ( x k + 1 ) + b y=m(x_{k+1})+b=m(x_k+1)+b y=m(xk+1)+b=m(xk+1)+b
小于0
,说明跟下面的像素点最接近,就选择 ( x k + 1 , y k ) (x_{k+1},y_k) (xk+1,yk)大于等于0
,则选择 ( x k + 1 , y k + 1 ) (x_{k+1},y_{k+1}) (xk+1,yk+1)像素点的选择只取决于
( d l o w e r − d u p p e r ) (d_{lower}-d_{upper}) (dlower−dupper)的符号且通过 ( x k , y k ) (x_k,y_k) (xk,yk)便可以确定下一个点
的位置,为了方便我们的计算,引入了新的变量 p k p_k pk,作为我们的决策参数注:由于Δ x>0,所以对pk的正负符号无影响
#include
#include
#include
#include
#include
#include
// 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