【计算机图形学】【实验报告】DDA画线算法、Bresenham中点画线算法、多边形填充算法(附代码)

实 验 报 告

一、实验目的

  1. 了解光栅化图形学的主要理论和知识。
  2. 了解OpenGL图形库的构成,会设计OpenGL的程序。
  3. 掌握基本图形的生成原理,学会设计基本图形的生成算法。包括画线算法、画圆算法和多边形填充算法的原理和实现方法。
  4. 设计中点画线算法,对给定的任意起点和终点的线段,采用中点画线算法设计画线程序,并能保证程序的正确性。
  5. 掌握多边形填充算法的基本原理和方法,掌握有序边表法和扫描线种子填充算法的原理。根据给定的类设计实现有序边表法填充多边形的程序 

二、实验内容与实验步骤

中点画线算法:

  1. 完成中点画线算法的设计,调用OpenGL的画点的函数,采用中点画线算法完成二维线段的绘制算法。
  2. 补全了lineBres函数以及pointFun函数。
    1. lineBres函数:一共有四个参数,表示起始点和终止点的坐标信息。分四种情况实现中点画线算法,分别是:0<=m<=1,m>=1,-1<=m<=0以及m<=-1。在函数中调用glVertex2d(x, y)函数,对每个坐标点(x,y)进行绘制。
    2. pointFun函数:利用glColor3f(GLfloat, GLfloat, GLfloat)函数设置画线颜色,之后调用lineBres函数绘制每条线。
  3. 实现后调用OpenGL的画线函数画线对比自己的实验结果。

DDA画线算法:

  1. 完成DDA画线算法的设计,调用OpenGL的画点的函数,采用DDA画线算法完成二维线段的绘制算法。
  2. 调用文件里所给的lineDDA函数,并创建与pointFun函数具有相同功能的DDALine函数。
    1. lineDDA函数:一共有四个参数,表示起始点和终止点的坐标信息。
    2. DDALine函数:利用glColor3f(GLfloat, GLfloat, GLfloat)函数设置画线颜色,之后调用lineDDA函数绘制每条线。

多边形填充算法:       

  1. 根据给定的类设计实现有序边表法填充多边形的程序
  2. 创建drawFrame()函数,用以勾画填充图形的外轮廓。
  3. 导入参考文件里的myclass.h以及myclass.cpp文件,调用其中的类以及函数,在main.cpp文件内创建新函数scanFill()函数,实现多边形填充。
  4. 在main()函数内调用drawFrame()函数以及scanFill()函数,实现描边以及填充。

三、实验环境

  1. 操作系统:macOS Big Sur Version 11.6
  2. 调试软件:Xcode Version 13.0
  3. 上机地点:xxx
  4. 机器台号:xxx

四、实验过程与分析

中点画线算法:

lineBres函数:

 流程图

 调试中的问题

  •  环境配置错误

      修改:Build Settings --> Linking --> Other Linker Flags 添加 “-framework OpenGL”

  • 定义函数出错

​​​​​​​ 

修改:将函数改名为ro(猜测round和其他功能重名)

 坐标信息

原点位置:视口中央

X正方向:视口内右方向

Y正方向:视口内上方向

视口大小:600*600


DDA画线算法:

lineDDA函数:

 流程图

 调试中的问题

  • 最开始文件中给的循环代码为:while (x <= x2),运行结果:

缺少斜率为负的情况。

修改:将循环判定部分修改为for (int i=1; i<=epsl; i++),即可绘制出正确图案。

坐标信息

 坐标原点位置:视口中央

X正方向:视口内右方向

Y正方向:视口内上方向

视口大小:600*600


多边形填充算法:

scanFill函数:

 流程图

 调试中的问题

  •  问题:输入的数据类型和定义不符

       修改:将point均改为引用类型。

 

  •   问题:指针应采用->样式调用 

       修改:把head.GetNextedge改为head->GetNextedge

  •  问题:运行函数后没有图形。

       修改:在myDisplay()函数末尾添加glFlush()函数调用。

 坐标信息

 坐标原点位置:视口中央

X正方向:视口内右方向

Y正方向:视口内上方向

视口大小:600*600


五、实验结果总结

中点画线算法:

DDA画线算法:

多边形填充算法:

代码:

// 画线算法

#define GL_SILENCE_DEPRECATION

#include<iostream>
#include<GLUT/glut.h> //windows改成<GL/glut.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>

using namespace std;


void init(void)
{
    glClearColor(1.0, 1.0, 1.0, 0.0);  // Set display-window color to white.
    glMatrixMode(GL_PROJECTION);       // Set projection parameters.
    glPointSize(2.0f);
    gluOrtho2D(-200, 200, -200, 200);
    GLfloat sizes[2];
    GLfloat step;
        glGetFloatv(1.0f,sizes);
        glGetFloatv(1.0f, & step);
    
}


int ro(const float a)
{
    int b = int(a+0.5);
    return b;
}


void lineDDA(int x1, int y1, int x2, int y2);
void lineBres(int x1, int y1, int x2, int y2);

void myReshape(GLsizei w, GLsizei h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w/2, w/2, -h/2, h/2, -10, 10);
}

void myDisplay() {
    glClearColor(0.0, 0.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    //glRectf(100, 100, 20, 20);
    lineDDA(10, 10, 200, 150);
    lineBres(10, 30, 200, 170);
    glFlush();
}


void lineDDA(int x1, int y1, int x2, int y2) {
    float dx, dy;
    int epsl;
    float xIncre, yIncre;
    dx = x2 - x1;
    dy = y2 - y1;
    float x = x1;
    float y = y1;
    if (abs(dx) > abs(dy))
        epsl = abs(dx);
    else
        epsl = abs(dy);
    xIncre = (float)dx / epsl;
    yIncre = (float)dy / epsl;
    glBegin(GL_POINTS);
    for (int i=1; i<=epsl; i++)
    {
        glVertex2i(int(x + 0.5), int(y + 0.5));
        x += xIncre;
        y += yIncre;
    }

}

void lineBres(int x1, int y1, int x2, int y2)
{
    int x = x1;
    int y = y1;
    if (x1 > x2)
    {
        x = x1; x1 = x2; x2 = x; x = x1;
        y = y1; y1 = y2; y2 = y; y = y1;
    }
    glBegin(GL_POINTS);
    int a = y1 - y2;
    int b = x2 - x1;
    float k = 0;
    int d;
    if (x1 != x2)
    {
        k = -1.0 * a / b;
    }
    else
    {
        if (y2 >= 0)
        {
            while (y < y2)
            {
                glVertex2i(x, y);
                y++;
            }
        }
        else
        {
            while (y > y2)
            {
                glVertex2i(x, y);
                y--;
            }
        }
    }

    if (k >= 0.0 && k < 1.0)
    {
        d = 2 * a + b;
        while (x <= x2)
        {
            glVertex2i(x, y);
            if (d >= 0)
            {
                d += 2 * a;
                x++;
            }
            else {
                d += 2 * a + 2 * b;
                x++;
                y++;
            }


        }



    }
    else if (k >= 1.0)
    {
        d = 2 * b + a;
        while (y <= y2)
        {
            glVertex2i(x, y);
            if (d >= 0)
            {
                d += 2 * b + 2 * a;
                x++;
                y++;
            }
            else {
                d += 2 * b;
                y++;
            }



        }


    }
    else if (k > -1.0 && k <= 0.0)
    {
        d = 2 * a - b;
        while (x <= x2)
        {
            glVertex2i(x, y);
            if (d >= 0)
            {
                d += 2 * a - 2 * b;
                x++;
                y--;
            }
            else {
                d += 2 * a;
                x++;

            }


        }

    }
    
    else
    {
        d = a - 2 * b;
        while (y >= y2)
        {
            glVertex2i(x, y);
            if (d >= 0)
            {
                d += -2 * b;
                y--;
            }
            else {
                d += 2 * a - 2 * b;
                x++;
                y--;
            }
        }

    }
    glEnd();


}


void pointFun(void)

{
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    glColor3f(1.0, 0.0, 0.0);//红
    lineBres(1, 1, 100, 50);//(1,1)    (100,50)
    glColor3f(1.0, 0.5, 0.0);//橙
    lineBres(1, 1, 50, 100);//(1,1)    (50,100)
    glColor3f(1.0, 1.0, 0.0);//黄
    lineBres(-1, 1, -100, 50);//(-1,1)    (-100,50)
    glColor3f(0.0, 1.0, 0.0);//绿
    lineBres(-1, 1, -50, 100);//(-1,1)    (-50,100)
    glColor3f(0.0, 1.0, 1.0);//青
    lineBres(-1, -1, -100, -50);//(-1,-1)    (-100,-50)
    glColor3f(0.0, 0.0, 1.0);//蓝
    lineBres(-1, -1, -50, -100);//(-1,-1)    (-50,-100)
    glColor3f(1.0, 0.0, 1.0);//紫
    lineBres(1, -1, 100, -50);//(1,-1)    (100,-50)
    glColor3f(0.0, 0.0, 0.0);//黑
    lineBres(1, -1, 50, -100);//(1,-1)    (50,-100)
    glColor3f(0.0, 0.0, 0.0);//黑
    lineBres(0, 0, 100, 0);//(0,0)    (100,0)
    glColor3f(0.0, 0.0, 0.0);//黑
    lineBres(0, 0, 0, 100);//(0,0)    (0,100)
    glEnd();
    glFlush();

        
}

void DDALine(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    glColor3f(1.0, 0.0, 0.0);//红
    lineDDA(1, 1, 100, 50);//(1,1)    (100,50)
    glColor3f(1.0, 0.5, 0.0);//橙
    lineDDA(1, 1, 50, 100);//(1,1)    (50,100)
    glColor3f(1.0, 1.0, 0.0);//黄
    lineDDA(-1, 1, -100, 50);//(-1,1)    (-100,50)
    glColor3f(0.0, 1.0, 0.0);//绿
    lineDDA(-1, 1, -50, 100);//(-1,1)    (-50,100)
    glColor3f(0.0, 1.0, 1.0);//青
    lineDDA(-1, -1, -100, -50);//(-1,-1)    (-100,-50)
    glColor3f(0.0, 0.0, 1.0);//蓝
    lineDDA(-1, -1, -50, -100);//(-1,-1)    (-50,-100)
    glColor3f(1.0, 0.0, 1.0);//紫
    lineDDA(1, -1, 100, -50);//(1,-1)    (100,-50)
    glColor3f(0.0, 0.0, 0.0);//黑
    lineDDA(1, -1, 50, -100);//(1,-1)    (50,-100)
    glColor3f(0.0, 0.0, 0.0);//黑
    lineDDA(0, 0, 100, 0);//(0,0)    (100,0)
    glColor3f(0.0, 0.0, 0.0);//黑
    lineBres(0, 0, 0, 100);//(0,0)    (0,100)
    glEnd();
    glFlush();
}

void sysLine(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINES);
    glColor3f(1.0, 0.0, 0.0);//红
    glVertex2f(1, 1);
    glVertex2f(100, 50);
    glColor3f(1.0, 0.5, 0.0);//橙
    glVertex2f(1, 1);
    glVertex2f(50, 100);
    glColor3f(1.0, 1.0, 0.0);//黄
    glVertex2f(-1, 1);
    glVertex2f(-100, 50);
    glColor3f(0.0, 1.0, 0.0);//绿
    glVertex2f(-1, 1);
    glVertex2f(-50, 100);
    glColor3f(0.0, 1.0, 1.0);//青
    glVertex2f(-1, -1);
    glVertex2f(-100, -50);
    glColor3f(0.0, 0.0, 1.0);//蓝
    glVertex2f(-1, -1);
    glVertex2f(-50, -100);
    glColor3f(1.0, 0.0, 1.0);//紫
    glVertex2f(1, -1);
    glVertex2f(100, -50);
    glColor3f(0.0, 0.0, 0.0);//黑
    glVertex2f(1, -1);
    glVertex2f(50, -100);
    glVertex2f(0, 0);
    glVertex2f(100, 0);
    glVertex2f(0, 0);
    glVertex2f(0, 100);

    glEnd();
    glFlush();

    
}

int main(int argc, char** argv)
{

    glutInit(&argc, argv);                         // Initialize GLUT.
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   // Set display mode.
    glutInitWindowPosition(50, 100);   // Set top-left display-window position.
    glutInitWindowSize(600, 600);      // Set display-window width and height.
    glutCreateWindow("DDA画线算法"); // Create display window.
    init();                           // Execute initialization procedure.
    glutDisplayFunc(DDALine);       // Send graphics to display window.
    glutMainLoop();// Send graphics to display window.                  // Display everything and wait.
    

    return 0;
}
// 多边形填充算法
#define GL_SILENCE_DEPRECATION

#include <iostream>
using namespace std;
#include <GLUT/glut.h> // windows改成<GL/glut.h>
#include "myclass.h"

void drawFrame();
void scanFill();

void myReshape(GLsizei w, GLsizei h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w / 2, w / 2, -h / 2, h / 2, -10, 10);
}

void myDisplay() {
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0, 0.0, 0.0);
    //glRectf(100, 100, 20, 20);
    drawFrame();
    scanFill();
    glFlush();
}

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(600, 600);
    glutCreateWindow("多边形填充");

    glutDisplayFunc(myDisplay);
    glutReshapeFunc(myReshape);
    glutMainLoop();
    
    return 0;
}

void drawFrame(){
    Point2D point_1(0,0);
    Point2D point_2(-100,100);
    Point2D point_3(100,100);
    Point2D point_4(0,200);
    
    glBegin(GL_LINE_LOOP);
    glVertex2i(point_1.GetX(),point_1.GetY());
    glVertex2i(point_2.GetX(),point_2.GetY());
    glVertex2i(point_3.GetX(),point_3.GetY());
    glVertex2i(point_4.GetX(),point_4.GetY());
    glEnd();
}


void scanFill(){
    NewEdgeTable NET;
    ActiveEdgeTable AET;
    ActiveEdge point1(0, -1, 100);
    NET.InsertNewEdge(&point1, 0);
    ActiveEdge point2(0, 1, 100);
    point1.SetNext(&point2);
    ActiveEdge point3(-100, 1, 200);
    NET.InsertNewEdge(&point3, 100);
    ActiveEdge point4(100, -1, 200);
    point3.SetNext(&point4);

    int i=0;
    //遍历新边表
    for (ActiveEdge* point : NET.rowTable){
        ActiveEdge * ptr = AET.head->GetNextedge();
        //遍历活性边表 删去非必要的边
        while (ptr != NULL) {
            if (ptr->GetMax()==i){
                ActiveEdge* ptr2 = ptr;
                ptr = ptr->GetNextedge();
                AET.DeleteActiveEdge(ptr2);
            }else{
                float x = ptr->GetCurrentX()+ptr->GetDX();
                ptr->SetCurrentX(x);
                ptr = ptr->GetNextedge();
            }
        }
        
        //放入活性边表
        while (point != NULL) {
            ActiveEdge* point2 = point;
            point = point->GetNextedge();
            AET.InsertActiveEdge(point2);
        }
        AET.sort();
        ptr = AET.head->GetNextedge();
        glBegin(GL_LINES);
        glColor3f(0.0, 0.0, 0.0);
        
        //遍历新的活性边表 填充
        while (ptr!=NULL){
            int x = ptr->GetCurrentX();
            glVertex2i(x, i);
            ptr = ptr->GetNextedge();
            x = ptr->GetCurrentX();
            glVertex2i(x, i);
            ptr = ptr->GetNextedge();
        }
        glEnd();
        i++;
        
    }
    
}

六、附录

  1. 设想:可以考虑用每一步都定格一小段时间看真实的扫描过程,但因能力不足未实现。
  2. 资料:
    1. 多边形的扫描转换算法——扫描线算法(计算机图形学)_八爪鱼的博客-CSDN博客
    2. 【区域填充】中的扫描线填充算法,活性边表AET,新边表NET_ZY_cat的博客-CSDN博客_活性边表
    3. 计算机图形学实验三:多边形填充算法之活性边表方法实现_孜迹的博客-CSDN博客_活性边表算法
    4. UniTHI/PolygonRasterer.java at 1669f5ede92db042919dad65c09fda71b0bd1fac · MobysDikk/UniTHI · GitHub
    5. 百度搜索、百度文库、课本等。
  3. 思考题:
    1. Q:对比DDA画线算法,Bresenham中点画线算法有哪些优点?A:D DA算法中的yk都必须用浮点数表示,并且每一步运算都要对y进行舍入取整,这不利于硬件实现。中点画线法只包含整数变量,并且不含乘除法,速度更快效率更高。
    2. Q:举例说明种子填充算法适合什么应用场景? A:如果要填充的区域是以图像元数据方式给出的,通常使用种子填充算法进行区域填充。种子填充算法需要给出图像数据的区域,以及区域内的一个点,这种算法比较适合人机交互方式进行的图像填充操作,不适合计算机自动处理和判断填色。​​​​​​​

// 大家随便看看,当初做实验真的是被整麻了……心态一整个没有hhh。

// 要是有错误欢迎指出,用到了麻烦点个赞点个关注~

猜你喜欢

转载自blog.csdn.net/Kqp12_27/article/details/121498410
今日推荐