opengl学习之 DDA画直线算法 Bresenham画直线算法

// 计算机图形学_实验5_20181017.cpp : 定义应用程序的入口点。
//

#include "计算机图形学_实验5_20181017.h"
#include <graphics.h>
#include <conio.h>

// circle algorithm.cpp : Defines the entry point for the console application.
//

//This program was updated by Ms Huang Jing in Beijing Normal Unbersity Zhuhai Campus
//  in Oct 20 in 2012,Contact email: [email protected]

#include "stdafx.h"

#include <glut.h>
//#include <stdio.h>
//#include <stdlib.h>
#include <math.h>


#define N 1000       //maximum line numbers

int cx = 150, cy = 150, radius = 80, ri = 50, ro = 80, n = 3, samples = 1, flag = 1;
int ww, hh;     // for display window width and height
int line[N][4], k = 0;  //for line's endpoint coordinates and line number

void Myinit(void);
void plotC(int x, int y, int xc, int yc);
void Bresenham_Circle_Algorithm(int cx, int cy, int radius);
void DrawOneLine(int x1, int y1, int x2, int y2);
void NSidedPolygon(int n, int cx, int cy, int radius);
void SampleCircle(int inner, int outer, int samples, int cx, int cy);
void Keyboard(unsigned char key, int x, int y);
void Display(void);
void Reshape(int w, int h);
void Drawlines();
void myMouse(int button, int state, int x, int y);
void myMotion(int x, int y);
void  DDA_Drawlines();
void CirPot(int x0, int y0, int x, int y, int color);
void drawCircle();
void MidPoint_Circle(int x0, int y0, double radius, int color);
void Bresenham_line(int xa, int ya, int xb, int yb);
void Bresenham_line2(int xa, int ya, int xb, int yb);
void  Bresenham_Drawlines();

int APIENTRY _tWinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPTSTR    lpCmdLine,
    int       nCmdShow)
{

    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    char *argv[] = { "hello ", " " };
    int argc = 2; // must/should match the number of strings in argv

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutCreateWindow("Basic_Primitive_Algorithm");
    Myinit();  //初始设置
    glutDisplayFunc(Display);  //注册绘制响应回调函数
    glutKeyboardFunc(Keyboard);  //注册键盘响应回调函数
    glutReshapeFunc(Reshape);    //注册窗口改变回调函数
    glutMouseFunc(myMouse);    //注册鼠标按钮回调函数
    glutMotionFunc(myMotion);  //注册鼠标移动回调函数
    glutMainLoop();
    return 0;
}


void Myinit(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);  //背景色
    glLineWidth(4.0);  //线宽
}

void Display(void)
{

    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型变换模式,表示在世界坐标系下
    glLoadIdentity();   //将当前矩阵设置为单位矩阵

    if (flag == 1)  //画圆
        Bresenham_Circle_Algorithm(cx, cy, radius);
    if (flag == 2)  //画多边形
        NSidedPolygon(n, cx, cy, radius);
    if (flag == 3)  //画胖圆
        SampleCircle(ri, radius, samples, cx, cy);
    if (flag == 4)  //鼠标划线
        Drawlines();
    if (flag == 5)
        DDA_Drawlines();//DDA画直线
    if (flag == 6)
    {
        drawCircle();//bresenham中心画圆法
    }
    if (flag == 7)
    {
        Bresenham_Drawlines();//bresenham画直线
    }
    glutSwapBuffers();
}


void Keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {

    case 'r':
        if ((flag == 1) && (radius>1))  radius--; //画单个圆时半径变小
        if ((flag == 3) && (radius>ri)) radius--;  //画胖圆时外径变小
        break;
    case 'R':
        if ((radius<ww / 2) && (radius<hh / 2))
            radius++;  //半径增加
        break;
    case 'n':
        if ((flag == 2) && (n>3)) n--;  //多边形边数递减
        break;
    case 'N':
        if (flag == 2) n++;  //多边形边数递增
        break;
    case 'i':
        if ((flag == 3) && (ri>1)) ri--;  //画胖圆时内径变小
        break;
    case 'I':
        if ((flag == 3) && (ri<radius)) ri++;  //画胖圆时内径变大
        break;
    case 's':
        if (samples>1) samples--; //采样数减少
        break;
    case 'S':
        samples++;   //采样数增加
        break;
    case 'a':
        //cancel antialias
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
        glDisable(GL_POINT_SMOOTH);
        glDisable(GL_POLYGON_SMOOTH);
        break;
    case 'A':
        //enable antialias
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
        glEnable(GL_POINT_SMOOTH);
        glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
        glEnable(GL_LINE_SMOOTH);
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
        glEnable(GL_POLYGON_SMOOTH);
        break;
    case '1':
        flag = 1;  //画圆
        break;
    case '2':
        flag = 2;  //画多边形
        break;
    case '3':
        flag = 3;   //画胖圆
                    //cancel antialias
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
        glDisable(GL_POINT_SMOOTH);
        glDisable(GL_POLYGON_SMOOTH);
        break;
    case '4':
        flag = 4;  //鼠标划线
        for (int i = 0; i <= k; i++)
        {
            line[i][0] = 0;
            line[i][1] = 0;
            line[i][2] = 0;
            line[i][3] = 0;
        }
        k = 0;
        break;
    case '5':
        flag = 5;
        for (int i = 0; i <= k; i++)
        {
            line[i][0] = 0;
            line[i][1] = 0;
            line[i][2] = 0;
            line[i][3] = 0;
        }
        k = 0;
        break;
    case '6':
        flag = 6;
        for (int i = 0; i <= k; i++)
        {
            line[i][0] = 0;
            line[i][1] = 0;
            line[i][2] = 0;
            line[i][3] = 0;
        }
        k = 0;
        break;
    case '7':
        flag = 7;
        for (int i = 0; i <= k; i++)
        {
            line[i][0] = 0;
            line[i][1] = 0;
            line[i][2] = 0;
            line[i][3] = 0;
        }
        k = 0;
        break;
    case 27:
        exit(0);
        //  default:
        //     return;
    }

    glutPostRedisplay();
}


void Reshape(int w, int h)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glViewport(0, 0, w, h);
    gluOrtho2D(0, w, 0, h);
    ww = w;
    hh = h;
    cx = w / 2;
    cy = h / 2;
}

void Bresenham_Circle_Algorithm(int cx, int cy, int radius)
{
    /* YOUR CODE HERE ,
    Update the followling codes with Bresenham_Circle_Algorithm  */

    glColor3f(1, 1, 1);
    glTranslatef(cx, cy, 0);
    glutWireSphere(radius, 40, 40);

}


void NSidedPolygon(int n, int cx, int cy, int radius)
{

    int x[100], y[100];
    double angle;

    angle = 2 * 3.1415926 / n;

    glColor3f(1, 1, 1);

    for (int i = 0; i <= n; i++)
    {
        x[i] = (int)(cx + radius*cos(i*angle));
        y[i] = (int)(cy + radius*sin(i*angle));
    }

    for (int i = 0; i <= (n - 1); i++)
    {
        DrawOneLine(x[i], y[i], x[i + 1], y[i + 1]);
    }

}


void DrawOneLine(int xa, int ya, int xb, int yb)
{

    /* YOUR CODE HERE */
    //update the following codes with DDA line algorithm

    glColor3f(1, 1, 1);
    glBegin(GL_LINES);
    glVertex2f(xa, ya);
    glVertex2f(xb, yb);
    glEnd();


}


void  Drawlines()
{


    for (int i = 0; i <= k; i++) //********
    {
        DrawOneLine(line[i][0], line[i][1], line[i][2], line[i][3]);

    }
}


void SampleCircle(int inner, int outer, int samples, int cx, int cy)
{

    float r2, ro2, ri2;   //r2为子像素的半径
    int x, y, nx, ny;   //x,y 为胖圆内的一点
    float color_value;  //颜色亮度
    int count; //计数合格的子像素


               //#########  Calculate outer radius's square and inner's square

    ro2 = outer*outer;   //胖圆外径平方
    ri2 = inner*inner;   //胖圆内径平方

                         //#########  for each pixel(x,y), testing its sample

                         //1/4胖圆内的点测试
    for (x = 0; x<outer; x++)
        for (y = 0; y <= outer; y++)
        {

            //######## count available subpixels for each pixel      
            count = 0;

            //每个点切分成smaples*samples个子像素
            //判断子像素是否在胖圆内
            for (nx = 0; nx <= samples; nx++)
                for (ny = 0; ny <= samples; ny++)
                {
                    r2 = (x + (float)nx / (float)samples)*(x + (float)nx / (float)samples);
                    r2 = r2 + (y + (float)ny / (float)samples)*(y + (float)ny / (float)samples);

                    if ((r2 <= ro2) && (r2 >= ri2))  count++; //计数合格的子像素

                }


            //########## calculate color gray level for each pixel
            color_value = ((float)count) / (((float)samples + 1.0)*((float)samples + 1.0));

            //########## draw pixel by using the color calculated above
            glColor3f(color_value, color_value, color_value);

            //对称画点
            glBegin(GL_POINTS);
            glVertex2f(cx + x, cy + y);
            glVertex2f(cx + x, cy - y);
            glVertex2f(cx - x, cy + y);
            glVertex2f(cx - x, cy - y);
            glEnd();

        }
}

//鼠标按钮响应事件..
void myMouse(int button, int state, int x, int y)
{

    if (button == GLUT_LEFT_BUTTON&&state == GLUT_DOWN)
    {
        line[k][0] = x;   //线段起点x坐标
        line[k][1] = hh - y;  //线段起点y坐标
    }

    if (button == GLUT_LEFT_BUTTON&&state == GLUT_UP)
    {
        line[k][2] = x;   //线段终点x坐标
        line[k][3] = hh - y;   //线段终点y坐标
        k++;
        glutPostRedisplay();
    }

}

//鼠标移动时获得鼠标移动中的坐标-----------------------------------------------------
void myMotion(int x, int y)
{

    //get the line's motion point
    line[k][2] = x;   //动态终点的x坐标
    line[k][3] = hh - y;  //动态终点的y坐标  
    glutPostRedisplay();

}


//DDA画直线算法
void DDA_line(int xa, int ya, int xb, int yb)
{
    int dx = xb - xa;
    int dy = yb - ya;

    float xIncrement, yIncrement, steps, x = xa, y = ya;
    if (abs(dx) > abs(dy))
    {
        steps = abs(dx);
    }
    else
    {
        steps = abs(dy);
    }
    xIncrement = (float)(dx) / steps;
    yIncrement = (float)(dy) / steps;
    for (int k = 0; k < steps; k++)
    {
        glBegin(GL_POINTS);
        glVertex2i((int)(x + 0.5), (int)(y + 0.5));
        glEnd();
        x += xIncrement;
        y += yIncrement;
    }

}

void  DDA_Drawlines()
{
    glColor3f(1, 1, 1);
    for (int i = 0; i <= k; i++) //********
    {
        DDA_line(line[i][0], line[i][1], line[i][2], line[i][3]);
    }
}

void  Bresenham_Drawlines()
{
    glColor3f(1, 1, 1);
    for (int i = 0; i <= k; i++) //********
    {
        Bresenham_line2(line[i][0], line[i][1], line[i][2], line[i][3]);
    }
}

//DDA画直线算法
void Bresenham_line(int x0, int y0, int x1, int y1)
{
    if (x0 - x1 < 0 && y0 - y1 < 0)
    {
        int dx = abs(x0 - x1);
        int dy = abs(y0 - y1);
        int h = 2 * dy - dx;
        int x = x0;
        int y = y0;

        glColor3f(1, 1, 1);

        glBegin(GL_POINTS);
        glVertex2i(x, y);
        glEnd();

        while (x < x1)
        {
            if (h < 0)
            {
                h += 2 * dy;
            }
            else
            {
                h += 2 * (dy - dx);
                y++;
            }
            glBegin(GL_POINTS);
            glVertex2i(x, y);
            glEnd();
            x++;
        }
    }
    else if (x0 - x1 > 0 && y0 - y1 > 0)
    {
        int dx = abs(x0 - x1);
        int dy = abs(y0 - y1);
        int h = (2 * dy - dx);
        int x = x0;
        int y = y0;

        glColor3f(1, 1, 1);

        glBegin(GL_POINTS);
        glVertex2i(x, y);
        glEnd();

        while (x > x1)
        {
            if (h < 0)
            {
                h += 2 * dy;
            }
            else
            {
                h += 2 * (dy - dx);
                y--;
            }
            glBegin(GL_POINTS);
            glVertex2i(x, y);
            glEnd();
            x--;
        }
    }
}

/*
-------------------- -
作者:谛听 -
来源:CSDN
原文:https ://blog.csdn.net/u012319493/article/details/53289132
版权声明:本文为博主原创文章,转载请附上博文链接!
*/
void Bresenham_line2(int x0, int y0, int x1, int y1)
{
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int x = x0;
    int y = y0;
    int stepX = 1;
    int stepY = 1;
    if (x0 > x1)  //从右向左画
        stepX = -1;
    if (y0 > y1)
        stepY = -1;

    if (dx > dy)  //沿着最长的那个轴前进
    {
        int e = dy * 2 - dx;
        for (int i = 0; i <= dx; i++)
        {
            glColor3f(1, 1, 1);
            glBegin(GL_POINTS);
            glVertex2i(x, y);
            glEnd();
            x += stepX;
            e += 2*dy;
            if (e >= 0)
            {
                y += stepY;
                e -= 2*dx;
            }
        }
    }
    else
    {
        int e = 2 * dx - dy;
        for (int i = 0; i <= dy; i++)
        {
            glColor3f(1, 1, 1);
            glBegin(GL_POINTS);
            glVertex2i(x, y);
            glEnd();
            y += stepY;
            e += dx;
            if (e >= 0)
            {
                x += stepX;
                e -= dy;
            }
        }
    }
}

void drawCircle()
{
    //glColor3f(1, 1, 1);
    double radius;

    for(int i = 0; i <=k; i++)
    {
        radius = sqrt((double)((line[i][0] - line[i][2])*(line[i][0] - line[i][2])+ (line[i][1] - line[i][3])*(line[i][1] - line[i][3])));
        //glColor3f(1.0f, 0.0f, 0.0f);
        //glRasterPos2f(line[i][0], line[i][1]);
        //glutBitmapCharacter(GLUT_BITMAP_9_BY_15,'A');
        MidPoint_Circle(line[i][0], line[i][1], radius, 1);

    }
}


void MidPoint_Circle(int x0, int y0, double radius, int color)
{
    //参数x0,y0 表示圆心坐标, radius表示圆的半径,color表示圆的绘制颜色
    int x, y, h;
    x = 0; y = int(radius); h = 1 - int(radius);
    CirPot(x0, y0, x, y, color);
    while (x<y)
    {
        if (h<0)   h += 2 * x + 3;
        else { h += 2 * (x - y) + 5;  y--; }
        x++;
        CirPot(x0, y0, x, y, color);
    }
}
void CirPot(int x0, int y0, int x, int y, int color)
{
    
    //根据圆的对称性绘出8个对称点
    glBegin(GL_POINTS);
    glColor3f(1, 1, 1);
    glVertex2i(x0 + x, y0 + y);
    glVertex2i(x0 + x, y0 - y);
    glVertex2i(x0 - x, y0 + y);
    glVertex2i(x0 - x, y0 - y);
    glVertex2i(x0 + y, y0 + x);
    glVertex2i(x0 + y, y0 - x);
    glVertex2i(x0 - y, y0 + x);
    glVertex2i(x0 - y, y0 - x);
    glEnd();
//putpixel(x0 + x, y0 + y, color); //用color颜色在x0+x,y0+y处绘制一点
//putpixel(x0 + x, y0 - y, color);
//putpixel(x0 - x, y0 + y, color);
//putpixel(x0 - x, y0 - y, color);
//putpixel(x0 + y, y0 + x, color);
//putpixel(x0 + y, y0 - x, color);
//putpixel(x0 - y, y0 + x, color);
//putpixel(x0 - y, y0 - x, color);
}

猜你喜欢

转载自blog.csdn.net/guanshanyue96/article/details/89040377