计算机图形学OpenGL-DDA直线绘制和Bresenham直线绘制-付老师的实验二

1、用OpenGL实现微分法(DDA)直线绘制算法绘制一条直线,并用鼠标写出自己的名字。

#include <GL/glut.h>
#include <math.h>

#define MAX_LINES 100  // lines数组能保存的最大直线数量
bool isDrawing = false;  // 是否正在进行绘制
int startX, startY;      // 起始点坐标
int currentX, currentY;              // 当前点坐标
int lines[MAX_LINES][4];             // 已绘制的直线,每条直线使用4个整数表示
int lineCount = 0;                   // 已绘制的直线数量

void DDALine(int x0,int y0,int x1,int y1)  //书本DDA算法绘制直线
{
    glLineWidth(5.0f);
    glBegin(GL_LINE_STRIP);
    int dx, dy, eps1, k;
    float x, y, xIncre, yIncre;
    dx = x1 - x0;
    dy = y1 - y0;
    x = x0;
    y = y0;
    if (abs(dx) > abs(dy))
        eps1 = abs(dx);
    else
        eps1 = abs(dy);
    xIncre = (float)dx / (float)eps1;
    yIncre = (float)dy / (float)eps1;
  
    for (k = 0; k <= eps1; k++)
    {
        glVertex2f(int(x + 0.5), int(y + 0.5));
        x += xIncre;
        y += yIncre;
    }
    
    glEnd();
}



void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0f, 0.0f, 0.0f);
    // 绘制已保存的直线
    for (int i = 0; i < lineCount; i++)
    {
        DDALine(lines[i][0], lines[i][1], lines[i][2], lines[i][3]);
    }
    if (isDrawing)
        DDALine(startX, startY, currentX,currentY);

    glFlush();
}

void mouse(int button, int state, int x, int y)
{
	int height = glutGet(GLUT_WINDOW_HEIGHT);  // 获取窗口高度
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			startX = x;
			startY = height - y - 1;
            currentX = startX;
            currentY = startY;
			isDrawing = true;
		}
		else if (state == GLUT_UP)
		{
            isDrawing = false;
            lines[lineCount][0] = startX;    //每次绘制完,将直线的两点保存到lines数组中
            lines[lineCount][1] = startY;
            lines[lineCount][2] = currentX;
            lines[lineCount][3] = currentY;
            lineCount++;
		}
	}

    glutPostRedisplay();
}

void motion(int x, int y)
{
    int height = glutGet(GLUT_WINDOW_HEIGHT);  // 获取窗口高度
    if (isDrawing)
    {
		currentX = x;
		currentY = height - y - 1;
    }

    glutPostRedisplay();
}


void reshape(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, width, 0, height);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(1280, 720);
    glutCreateWindow("DDALine算法绘制线段");
   

    glClearColor(1.0f, 1.0f, 1.0f, 0.0);

    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutReshapeFunc(reshape);
    glutMainLoop();

    return 0;
}

第一道题目用DDA算法绘制直线,DDA算法实现实现的绘制并不难,只要把书本中的代码中的putpixel部分换成opengl库中绘制顶点的glVertex2f函数就行了。

由于是第一次绘制直线,难的在直线如何绘制?考虑鼠标的捕捉,如果鼠标左键按下就要记住当前的直线起点位置,需要注意的是,x轴的坐标与屏幕上的x轴坐标一致,但y轴的坐标需要通过openGL窗口的高度减去Windows窗口的鼠标光标的坐标,才能得出正确的y轴坐标。依次赋值给startX和startY。然后再把获取的坐标赋值给当前x、y的坐标currentX和currentY,然后在每次鼠标左键没有被按下的时候,需要将直线的起点和终点分别保存到一个lines数组中,这个数组是100行四列的数组,记载了最多能在窗口上绘制100条直线。数组作为记忆,以便绘制的时候,每绘制一条直线,它不会消失。在DDAline函数中,第一行我将绘制线条的线宽度设置为5.0f,用glLineWidth函数实现。

在鼠标移动motion函数记载中也是要获取当前x、y的坐标,赋值给currentX和currentY,也需要注意y轴的坐标需要通过窗口高度减去y轴坐标。

还要注意最后执行一个reshape函数调整下窗口进行矩阵投影,即窗口再整形回调函数reshape。

2.用OpenGL实现Bresenham直线绘制算法绘制一条直线,并用鼠标写出自己的名字。

#include <GL/glut.h>
#include <math.h>

#define MAX_LINES 100  // lines数组能保存的最大直线数量
bool isDrawing = false;  // 是否正在进行绘制
int startX, startY;      // 起始点坐标
int currentX, currentY;              // 当前点坐标
int lines[MAX_LINES][4];             // 已绘制的直线,每条直线使用4个整数表示
int lineCount = 0;                   // 已绘制的直线数量

void BresenhamLine0to1(int x0, int y0, int x1, int y1)
{
    glLineWidth(5.0f);
    glBegin(GL_LINE_STRIP);
    int dx = x1 - x0;
    int dy = y1 - y0;
    int e = -dx;
    int x = x0;
    int y = y0;
    if (dx >= 0)
    {
        for (; x <= x1; x++)
        {
            glVertex2f(x, y);

            e = e + 2 * dy;
            if (e > 0)
            {
                y++;
                e = e - 2 * dx;
            }
        }
    }
    else
    {
        for (; x >= x1; x--)
        {
            glVertex2f(x, y);

            e = e - 2 * dy;
            if (e > 0)
            {
                y--;
                e = e + 2 * dx;
            }
        }
    }
    glEnd();
}
void BresenhamLine1ToInfinity(int x0, int y0, int x1, int y1)
{
    glLineWidth(5.0f);
    glBegin(GL_LINE_STRIP);

    int dx = x1 - x0;
    int dy = y1 - y0;
    int e = -dy;
    int x = x0;
    int y = y0;
    if (dx >= 0)
    {
        for (; y <= y1; y++)
        {
            glVertex2f(x, y);

            e = e + 2 * dx;
            if (e > 0)
            {
                x++;
                e = e - 2 * dy;
            }
        }
    }
    else
    {
        for (; y >= y1; y--)
        {
            glVertex2f(x, y);

            e = e - 2 * dx;
            if (e > 0)
            {
                x--;
                e = e + 2 * dy;
            }
        }
    }
    glEnd();
}
void BresenhamLineMinus1to0(int x0, int y0, int x1, int y1)
{
    glLineWidth(5.0f);
    glBegin(GL_LINE_STRIP);
    int dx = x1 - x0;
    int dy = y1 - y0;
    int e = -dx;
    int x = x0;
    int y = y0;
    if (dx >= 0)
    {
        for (; x <= x1; x++)
        {
            glVertex2f(x, y);

            e = e - 2 * dy;
            if (e >= 0)
            {
                y--;
                e = e - 2 * dx;
            }
        }
    }
    else
    {
        for (; x >= x1; x--)
        {
            glVertex2f(x, y);

            e = e + 2 * dy;
            if (e >= 0)
            {
                y++;
                e = e + 2 * dx;
            }
        }
    }
    glEnd();
}
void BresenhamLineMinusInfinityToMinus1(int x0, int y0, int x1, int y1)
{
    glLineWidth(5.0f);
    glBegin(GL_LINE_STRIP);

    int dx = x1 - x0;
    int dy = y1 - y0;
    int e = -dy;
    int x = x0;
    int y = y0;
    if (dx >= 0)
    {
        for (; y >= y1; y--)
        {
            glVertex2f(x, y);

            e = e + 2 * dx;
            if (e > 0)
            {
                x++;
                e = e + 2 * dy;
            }
        }
    }
    else
    {
        for (; y <= y1; y++)
        {
            glVertex2f(x, y);

            e = e - 2 * dx;
            if (e >= 0)
            {
                x--;
                e = e - 2 * dy;
            }
        }
    }
    glEnd();
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0f, 0.0f, 0.0f);
    // 绘制已保存的直线
    int dx, dy;
    float k;
    for (int i = 0; i < lineCount; i++)
    {
        int x0 = lines[i][0];
        int y0 = lines[i][1];
        int x1 = lines[i][2];
        int y1 = lines[i][3];
        dx = x1 - x0;
        dy = y1 - y0;
        k = (float)dy / dx;
        if (k >= 0)
        {
            if (k <= 1)
                BresenhamLine0to1(x0, y0, x1, y1);
            else
                BresenhamLine1ToInfinity(x0, y0, x1, y1);

        }
        else
        {
            if (k >= -1)
                BresenhamLineMinus1to0(x0, y0, x1, y1);
            else
                BresenhamLineMinusInfinityToMinus1(x0, y0, x1, y1);
        }
    }
    if (isDrawing)
    {
        int x0 = startX;
        int y0 = startY;
        int x1 = currentX;
        int y1 = currentY;
        dx = x1 - x0;
        dy = y1 - y0;
        k = (float)dy / dx;
        if (k >= 0)
        {
            if (k <= 1)
                BresenhamLine0to1(x0, y0, x1, y1);
            else
                BresenhamLine1ToInfinity(x0, y0, x1, y1);

        }
        else
        {
            if (k >= -1)
                BresenhamLineMinus1to0(x0, y0, x1, y1);
            else
                BresenhamLineMinusInfinityToMinus1(x0, y0, x1, y1);
        }
    }
    glFlush();
}

void mouse(int button, int state, int x, int y)
{
    int height = glutGet(GLUT_WINDOW_HEIGHT);  // 获取窗口高度
    if (button == GLUT_LEFT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            startX = x;
            startY = height - y - 1;
            currentX = startX;
            currentY = startY;
            isDrawing = true;
        }
        else if (state == GLUT_UP)
        {
            isDrawing = false;
            lines[lineCount][0] = startX;    //每次绘制完,将直线的两点保存到lines数组中
            lines[lineCount][1] = startY;
            lines[lineCount][2] = currentX;
            lines[lineCount][3] = currentY;
            lineCount++;
        }
    }
    glutPostRedisplay();
}
void motion(int x, int y)
{
    int height = glutGet(GLUT_WINDOW_HEIGHT);  // 获取窗口高度
    if (isDrawing)
    {
        currentX = x;
        currentY = height - y - 1;
    }
    glutPostRedisplay();
}
void reshape(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, width, 0, height);
}
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(1280, 720);
    glutCreateWindow("Bresenham算法绘制线段");
    glClearColor(1.0f, 1.0f, 1.0f, 0.0);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}

第二个题目是使用Bresenham算法实现鼠标的绘制。他比第一个题目难的在这个算法的实现需要用四个函数,每个函数要分两个区域。由于Bensenham算法是根据直线斜率进行判断的,需要分四个函数。斜率范围依次是0<=k<=1,-1<=k<=0,-∞<=k<-1,1<k<=+∞。而每个函数也要通过X轴变化的增量进行判断。根据书本只给出的0<=k<=1斜率变化的代码,书本只给出的是在这个斜率范围朝右向上角延伸的,并没有给出朝左下角延伸的这个区间。所以通过x轴变化的增量,用dx>0或者dx<0判断,而dx<0的部分,要对for循环中的一些正负号和变量进行变换,才能实现在这个斜率范围的直线绘制,后面每一个函数都按这样的套路来,如果正负号变量弄反了,直线是会绘制错误的,所以这部分特别耗时间。凡是以x轴的步长为循环的变量,e的初始值都为-dx,还是以y轴的部长为循环的变量e的初始值都为-dy。

在绘制完四个函数之后,再直线绘制显示的部分display函数需要将绘制的点的斜率计算出来,把每一个点的斜率计算出来,注意计算出斜率的部分k=dy/dx,需要用浮点数进行计算。根据它的斜率在负无穷~-1~0~1~正无穷,这四个区间判断该使用哪个函数。其余的步骤跟第一个题目的一样。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值