OPENGL-学习计算机图形学

本文介绍了使用OpenGL图形接口实现的三种画直线算法:数值微分法(DDA)、中点画线法及Bresenham算法。通过具体实现代码,详细阐述了如何在屏幕上通过鼠标点击绘制直线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用OPENGL图形接口实现三种画直线算法,并用鼠标在屏幕上点击画线。

数值微分法-DDA

给定两点,算出直线的斜率K,根据步长,x每变化1步,y增加k,判断y的大小与下一个点的距离远近,取相应的像素点。根据K大小不同,选取不同的变化方向。

void DDALine(Point p1,Point p2){
        glBegin(GL_POINTS);
        float dx, dy, y, k,x;
        dx = p1.x - p2.x, dy = p1.y - p2.y;
        k = dy / dx;
        if (k >= -1 && k <= 1){
            if (p1.x > p2.x)swapPoint(p1, p2);
            y = p1.y;
            for (x = p1.x; x <= p2.x; x++)
            {
                glVertex2d(x, int(y + 0.5));
                y = y + k;
            }
        }
        else{
            if (p1.y > p2.y)swapPoint(p1, p2);
            x = p1.x;
            for (y = p1.y; y <= p2.y; y++)
            {
                glVertex2d(x + 0.5, y);
                x += 1 / k;
            }
        }
        glEnd();
        glFlush();
}

中点画线法

根据直线的函数f(x,y) = a*x + b*y + c= 0判断。
将(x+1,y+0.5)带入函数去计算:

  • 如果大于0则该点在直线上方,取(x+1,y)为下一个点,再取(x+2,y+0.5)进去判断。
  • 如果小于0则该点在直线下方,取(x+1,y+1)为下一个点,再取(x+2,y+1.5)进去判断。

将其改写为增量表达式,其他情况类似分析,实现代码如下:

void midPoint(Point p1, Point p2){
    glBegin(GL_POINTS);
    if (p1.x > p2.x) swapPoint(p1, p2);
    int a, b, c, d1, d2, d, x, y;
    a = p1.y - p2.y, b = p2.x - p1.x;
    x = p1.x, y = p1.y;
    glVertex2d(x, y);
    if (a*b > 0){
        if (a / b < 1){
            d = 2 * a - b;
            d1 = 2 * a, d2 = 2 * (a - b);
            while (x < p2.x)
            {
                if (d > 0)
                {
                    x++, y--;
                    d += d2;
                }
                else
                    x++, d += d1;
                glVertex2d(x, y);
            }
        }
        if (a / b >= 1){
            d = a - 2 * b;
            d1 = -2 * b, d2 = 2 * (a - b);
            while (y > p2.y)
            {
                if (d < 0)
                {
                    x++, y--;
                    d += d2;
                }
                else
                    y--, d += d1;
                glVertex2d(x, y);
            }
        }
    }
    else if (a*b <= 0) {
        if (a / b > -1){
            d = 2 * a + b;
            d1 = 2 * a, d2 = 2 * (a + b);
            while (x < p2.x)
            {
                if (d < 0)
                {
                    x++, y++;
                    d += d2;
                }
                else
                    x++, d += d1;
                glVertex2d(x, y);
            }
        }
        if (a / b <= -1){
            d = a + 2 * b;
            d1 = 2 * b, d2 = 2 * (a + b);
            while (y < p2.y)
            {
                if (d > 0)
                {
                    x++, y++;
                    d += d2;
                }
                else
                    y++, d += d1;
                glVertex2d(x, y);
            }
        }
    }
    glEnd();
    glFlush();
}

Bresenham算法

与DDA算法不同,算出两直线的K值之后,设定一个误差项e,与k进行增量计算。由于只是用到了误差项e的符号,可以替换后免去除法和小数。
误差项e初值为-dx,e的增量为2dy,如果e>0,e = e - 2dx。

void Bresenham(Point p1, Point p2){
    glBegin(GL_POINTS);
    if (p1.x > p2.x) swapPoint(p1, p2);
    int x, y, dx, dy, e;
    dx = p2.x - p1.x;
    dy = p2.y - p1.y;
    x = p1.x, y = p1.y;
    if (dy*dx > 0 && dy < dx){
        e = -dx;
        for (int i = 0; i <= dx; i++){
            glVertex2d(x, y);
            x++, e += 2 * dy;
            if (e >= 0){ y++; e -= 2 * dx; }
        }
    }
    else if (dy*dx > 0 && dy >= dx){
        e = -dy;
        for (int i = 0; i <= dy; i++){
            glVertex2d(x, y);
            y++, e += 2 * dx;
            if (e >= 0){ x++; e -= 2 * dy; }
        }
    }
    else if (dy*dx <= 0 && dy / dx > -1){
        e = dx;
        for (int i = 0; i <= dx; i++){
            glVertex2d(x, y);
            x++, e += 2 * dy;
            if (e <= 0){ y--; e += 2 * dx; }
        }
    }
    else if (dy*dx <= 0 && dy / dx <= -1){
        e = dy;
        for (int i = 0; i >= dy; i--){
            glVertex2d(x, y);
            y--, e += 2 * dx;
            if (e >= 0){ x++; e += 2 * dy; }
        }
    }
    glEnd();
    glFlush();

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值