[Computer Graphics] [Experimental Report] DDA line drawing algorithm, Bresenham midpoint line drawing algorithm, polygon filling algorithm (with code)

experimental report

1. Purpose of the experiment

  1. Understand the main theory and knowledge of raster graphics.
  2. Understand the composition of the OpenGL graphics library and design OpenGL programs.
  3. Master the generation principle of basic graphics, and learn to design the generation algorithm of basic graphics. Including the principles and implementation methods of line drawing algorithm, circle drawing algorithm and polygon filling algorithm.
  4. Design a midpoint line-drawing algorithm. For a given line segment with any starting point and end point, use the midpoint line-drawing algorithm to design a line-drawing program, and ensure the correctness of the program.
  5. Master the basic principles and methods of polygon filling algorithm, master the principles of ordered edge table method and scan line seed filling algorithm. According to the given class design, implement the program of filling polygons by ordered edge list method . 

2. Experimental content and experimental procedures

Midpoint line drawing algorithm:

  1. Complete the design of the midpoint line drawing algorithm, call the OpenGL point drawing function, and use the midpoint line drawing algorithm to complete the two-dimensional line segment drawing algorithm.
  2. Completed the lineBres function and pointFun function.
    1. lineBres function: There are four parameters in total, indicating the coordinate information of the starting point and the ending point. The midpoint line algorithm is implemented in four cases, namely: 0<=m<=1, m>=1, -1<=m<=0 and m<=-1. Call the glVertex2d(x, y) function in the function to draw each coordinate point (x, y).
    2. pointFun function: Use the glColor3f(GLfloat, GLfloat, GLfloat) function to set the line color, and then call the lineBres function to draw each line.
  3. After implementation, call OpenGL's line drawing function to draw lines and compare your own experimental results.

DDA line drawing algorithm:

  1. Complete the design of the DDA line drawing algorithm, call the function of drawing points of OpenGL, and use the DDA line drawing algorithm to complete the drawing algorithm of the two-dimensional line segment.
  2. Call the lineDDA function given in the file and create a DDALine function that has the same function as the pointFun function.
    1. lineDDA function: There are four parameters in total, indicating the coordinate information of the starting point and the ending point.
    2. DDALine function: Use the glColor3f(GLfloat, GLfloat, GLfloat) function to set the line color, and then call the lineDDA function to draw each line.

Polygon filling algorithm:       

  1. According to the given class design, implement the program of filling polygons by ordered edge list method .
  2. Create the drawFrame() function to draw the outline of the filled graphics.
  3. Import the myclass.h and myclass.cpp files in the reference file, call the classes and functions in them, and create a new function scanFill() function in the main.cpp file to realize polygon filling.
  4. Call the drawFrame() function and scanFill() function in the main() function to realize stroke and fill.

3. Experimental environment

  1. Operating system: macOS Big Sur Version 11.6
  2. Debugging software: Xcode Version 13.0
  3. Boarding location: xxx
  4. Machine number: xxx

4. Experimental process and analysis

Midpoint line drawing algorithm:

lineBres function:

 flow chart

 problem in debugging

  •  Environment configuration error

      Modify: Build Settings --> Linking --> Other Linker Flags add "-framework OpenGL"

  • Error defining function

​​​​​​​ 

Modification: Rename the function to ro (guess that round has the same name as other functions)

 coordinate information

Origin position: center of viewport

X positive direction: the right direction in the viewport

Y positive direction: the upward direction in the viewport

Viewport size: 600*600


DDA line drawing algorithm:

lineDDA function:

 flow chart

 problem in debugging

  • The loop code given in the initial file is: while  (x <= x2) , and the running result is:

The case where the slope is negative is missing.

Modification: Modify the loop judgment part to for  ( int  i= 1 ; i<=epsl; i++) to draw the correct pattern.

coordinate information

 Coordinate origin position: the center of the viewport

X positive direction: the right direction in the viewport

Y positive direction: the upward direction in the viewport

Viewport size: 600*600


Polygon filling algorithm:

scanFill function:

 flow chart

 problem in debugging

  •  Problem: The input data type does not match the definition

       Modification: Change point to reference type.

 

  •   Problem: Pointers should be called in -> style 

       Modification: Change head.GetNextedge to head->GetNextedge

  •  Problem: No graph after running the function.

       Modification: Add glFlush() function call at the end of myDisplay() function.

 coordinate information

 Coordinate origin position: the center of the viewport

X positive direction: the right direction in the viewport

Y positive direction: the upward direction in the viewport

Viewport size: 600*600


5. Summary of Experimental Results

Midpoint line drawing algorithm:

DDA line drawing algorithm:

Polygon filling algorithm:

code:

// 画线算法

#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++;
        
    }
    
}

6. Appendix

  1. Idea: It can be considered to freeze each step for a short period of time to see the real scanning process, but it has not been realized due to lack of ability.
  2. material:
    1. Polygon scan conversion algorithm - scan line algorithm (computer graphics) - Octopus Blog - CSDN Blog
    2. Scanline filling algorithm in [area filling], active edge table AET, new edge table NET_ZY_cat's blog-CSDN blog_active edge table
    3. Computer Graphics Experiment 3: Realization of the Active Edge Table Method of the Polygon Filling Algorithm_Ziji's Blog-CSDN Blog_Active Edge Table Algorithm
    4. UniTHI/PolygonRasterer.java at 1669f5ede92db042919dad65c09fda71b0bd1fac · MobysDikk/UniTHI · GitHub
    5. Baidu search, Baidu library, textbooks, etc.
  3. Thinking questions:
    1. Q: Compared with the DDA line drawing algorithm, what are the advantages of the Bresenham midpoint line drawing algorithm? A: Both y and k in the DDA algorithm must be represented by floating-point numbers , and y must be rounded and rounded at each step of operation , which is not conducive to hardware implementation. The midpoint line method only contains integer variables, and does not contain multiplication and division, which is faster and more efficient.
    2. Q: Give an example of what application scenarios the seed filling algorithm is suitable for? A: If the area to be filled is given in the form of image metadata, the seed filling algorithm is usually used for area filling. The seed filling algorithm needs to give the area of ​​the image data and a point in the area. This algorithm is more suitable for the image filling operation in the form of human-computer interaction, but not suitable for automatic computer processing and judgment color filling. ​​​​​​​​

// Let's just take a look, I was really numb when I did the experiment at the beginning... The mentality is completely without hhh.

// If there are any mistakes, please point them out. If you use them, please give me a thumbs up and a follow~

Guess you like

Origin blog.csdn.net/Kqp12_27/article/details/121498410