zoukankan      html  css  js  c++  java
  • openGL笔记-画基本图形

     

    #include "iostream"
    #include <GL/glut.h>  
    #include<cmath>
    #include<vector>
    #include<algorithm>
    #include<fstream>
    #include "MatrixV.h"
    
    #define PI acos(-1)
    using namespace std;
    #pragma comment(lib, "legacy_stdio_definitions.lib")
    
    // ---------------------------------------------------------------------------------------------------结构
    struct MPOINT {
        GLdouble x, y;
        MPOINT() {
    
        }
        MPOINT(double x, double y) {
            this->x = x;
            this->y = y;
        }
        bool operator == (struct MPOINT& a) {
            return (abs(this->x - a.x<=2)) && (abs(this->y - a.y)<=2);
        }
        friend ostream& operator<<(ostream &out,struct MPOINT& a) {
            cout << a.x << " " << a.y << endl;
            return out;
        }
    };
    struct lineEquation {
        double k, b;
        int x1, x2, y1, y2;
        bool fk;//true 代表k不存在
    };
    
    struct Color {
        GLdouble r, g, b;
        struct Color(GLdouble r, GLdouble g, GLdouble b)
        {
            this->r = r;
            this->g = g;
            this->b = b;
        }
    };
    
    vector<struct lineEquation> lineEV;
    typedef struct LineAE    /*有效边描述结构*/
    {
        GLfloat x;          /*当前扫描线与边的交点 */
        GLfloat dx;         /*斜率的倒数*/
        GLint ymax;          /*边所在的最大扫描线值*/
        struct LineAE *next;  /*指向下一条有效边*/
        LineAE() {
            next = NULL;
        }
    }ActiveEdge;
    
    vector<ActiveEdge> activeEdge;
    struct MPOINT *oldPoint, *curPoint;
    GLdouble longAxes, shortAxes,ovalAngle;//输入为角度,计算时转化为弧度
    int flag = 0,choice ;
    vector<struct MPOINT> vertexSet;
    void Line_sin()
    {
        glClear(GL_COLOR_BUFFER_BIT);
        //glColor3f(1.0f, 0.0f, 0.0f);
        glBegin(GL_LINES);
        {
            glVertex2f(-1.0f, 0.0f);
            glVertex2f(1.0f, 0.0f);         // 以上两个点可以画x轴
            glVertex2f(0.0f, -1.0f);
            glVertex2f(0.0f, 1.0f);         // 以上两个点可以画y轴
        }
        glEnd();
        glBegin(GL_LINE_STRIP);
        {
            for (int i = 0; i < 1000; i++) {
                glVertex2f(i, 100*sin(i*1.0));
            }
        }
        glEnd();
        glFlush();
    }
    
    
    void Show()
    {
        const GLfloat factor = 0.1f;
        GLfloat x;
        glClear(GL_COLOR_BUFFER_BIT);
        //glColor3f(1.0f, 1.0f, 1.0f);
        glBegin(GL_LINES);
        {
            glVertex2f(-1.0f, 0.0f);
            glVertex2f(1.0f, 0.0f);         // 以上两个点可以画x轴
            glVertex2f(0.0f, -1.0f);
            glVertex2f(0.0f, 1.0f);         // 以上两个点可以画y轴
        }
        glEnd();
        glBegin(GL_POINTS);
        {
            for (x = -1.0f / factor; x < 1.0f / factor; x += 0.01f)
            {
                glVertex2f(x*factor, sin(x)*factor);
            }
        }
        glEnd();
        glFlush();
    }
    
    
    /* 函数用来画图 */
    void display(void)
    {
        
    }
    
    //-------------------------------------------------------------------------------------------------------直线
    //1.DDA
    void Line_DDA(struct MPOINT* p1, struct MPOINT* p2)
    {
        //glClear(GL_COLOR_BUFFER_BIT);
        //glColor3f(1.0f, 0.0f, 0.0f);
        //glPointSize(5);//设置点大小为5像素
    
        GLdouble Xa = p1->x, Ya = p1->y, Xb = p2->x, Yb = p2->y;
        GLint dx = Xb - Xa, dy = Yb - Ya, steps, k;
        GLdouble xIncrement, yIncrement, x = Xa, y = Ya;
        if (abs(dx) > abs(dy))
            steps = abs(dx);
        else
            steps = abs(dy);
        xIncrement = dx / (GLdouble)steps;
        yIncrement = dy / (GLdouble)steps;
        glBegin(GL_POINTS);
        {
            glVertex2d((GLdouble)round(x), (GLdouble)round(y));
            for (k = 0; k < steps; k++)
            {
                x += xIncrement;
                y += yIncrement;
                glVertex2d((GLdouble)round(x), (GLdouble)round(y));
            }
        }
        glEnd();
        glFlush();
    }
    
    
    //中点Bresenham算法(改进版)
    void Line_Bresenham(struct MPOINT* p1, struct MPOINT* p2)
    {
        GLint dx = p2->x - p1->x, dy = p2->y - p1->y,x = p1->x, y= p1->y,e=0;
        GLdouble k = (dy) / (GLdouble)dx;
        glBegin(GL_POINTS);
        {
            glVertex2i(round(x), round(y));
            if (k >= 0) {
                if (p1->x > p2->x || ((p1->x == p2->x) &&(p1->y > p2->y))) {
                    GLint tmp = p1->x;
                    x = p2->x;
                    p2->x = tmp;
                    tmp = p1->y;
                    y  = p2->y;
                    p2->y = tmp;
                    dx *= -1;
                    dy *= -1;
                }
                if (k <= 1)
                {
                    e = -dx;
                    while (x != p2->x && y != p2->y) {
                        e += 2 * dy;
                        if (e > 0) {
                            if (x < p2->x || y< p2->y) {
                                x++;
                                y++;
                            }
                            else if (x > p2->x || y > p2->y)
                            {
                                x--;
                                y--;
                            }
                            e -= 2 * dx;
                        }
                        else {
                            if (x < p2->x) {
                                x++;
                            }
                            else if(x > p2->x)
                            {
                                x--;
                            }
                        }
                        glVertex2i(round(x), round(y));
                    }
                }
                else if (k > 1) {
                    e = -dy;
                    while (x != p2->x && y != p2->y) {
                        e += 2 * dx;
                        if (e > 0) {
                            if (x < p2->x || y< p2->y) {
                                x++;
                                y++;
                            }
                            else if (x > p2->x || y > p2->y)
                            {
                                x--;
                                y--;
                            }
                            e -= 2 * dy;
                        }
                        else {
                            if (y < p2->y) {
                                y++;
                            }
                            else if (y > p2->y)
                            {
                                y--;
                            }
                        }
                        glVertex2i(round(x), round(y));
                    }
                }
            }
            else {
                if (k >= -1)
                {
                    e = -dx;
                    while (x != p2->x && y != p2->y) {
                        e += abs(dy)*2;
                        if (e > 0) {
                            if (x > p2->x || y< p2->y) {
                                x--;
                                y++;
                            }
                            else if (x < p2->x || y > p2->y)
                            {
                                x++;
                                y--;
                            }
                            e -= abs(dx)*2;
                        }
                        else {
                            if (x < p2->x) {
                                x++;
                            }
                            else if (x > p2->x)
                            {
                                x--;
                            }
                        }
                        glVertex2i(round(x), round(y));
                    }
    
                }
                else 
                {
                    e = -dy;
                    while (x != p2->x && y != p2->y) {
                        e += 2 * abs(dx);
                        if (e > 0) {
                            if (x > p2->x || y< p2->y) {
                                x--;
                                y++;
                            }
                            else if (x < p2->x || y > p2->y)
                            {
                                x++;
                                y--;
                            }
                            e -= 2 * abs(dy);
                        }
                        else {
                            if (y < p2->y) {
                                y++;
                            }
                            else if (y > p2->y)
                            {
                                y--;
                            }
                        }
                        glVertex2i(round(x), round(y));
                    }
                }
            }
        }
        glEnd();
        glFlush();
    }
    
    //-------------------------------------------------------------------------------------------------------圆形
    //极坐标法 for Ciecle
    void Circle_Polar(struct MPOINT *c, GLdouble R)
    { 
        GLint n = 100;
        GLdouble x=c->x, y=c->y;
        glBegin(GL_POINTS);
        {
            for (int i = 0; i < n; i++)
            {
                x =c->x + R * cos(2 * PI *i/ n);
                y =c->y + R * sin(2 * PI *i/ n);
                glVertex2f(x,y);
            }
        }
        glEnd();
        glFlush();
    }
    //中点Bresenham for Circle
    //画点(x,y)和他的7个对称点
    void Draw8(struct MPOINT *c,GLdouble x, GLdouble y)
    {
        GLdouble X = c->x, Y = c->y;
        glBegin(GL_POINTS);
        {
            glVertex2d(x +X,y + Y);
            glVertex2d(-x +X, y + Y);
            glVertex2d(x + X, -y + Y);
            glVertex2d(-x + X, -y + Y);
    
            glVertex2d(y + X, x + Y);
            glVertex2d(-y + X, x + Y);
            glVertex2d(y + X, -x + Y);
            glVertex2d(-y + X, -x + Y);
        }
        glEnd();
        glFlush();
    }
    void Circle_Bresenham(struct MPOINT *c,GLdouble R)
    {
        GLdouble d = 1 - R, x = 0, y = R;
        while (x <= y)
        {
            Draw8(c, x ,y);
            if (d <= 0)
            {
                d += 2 * x + 3;
                x++;
            }
            else
            {
                d += 2 * (x-y) + 5;
                x++;
                y--;
            }
        }
    }
    
    //DDA for Circle
    void Circle_DDA(struct MPOINT *c, GLdouble R)
    {
        GLdouble xc = c->x, yc = c->y, x = xc + R, y = yc, theta = 0, e = 1 / R;
        glBegin(GL_POINTS);
        {
            while (theta < 2 * PI) {
                glVertex2f(x, y);
                x = x - (y - yc)*e;
                y = y + (x - xc)*e;
                theta += e;
            }
        }
        glEnd();
        glFlush();
    }
    
    //-------------------------------------------------------------------------------------------------------椭圆
    //某点绕某点旋转后的新坐标
    void getNewPoint(struct MPOINT* c,GLdouble X, GLdouble Y,GLdouble& x,GLdouble& y)
    {
        x = (X - c->x)*cos(ovalAngle*PI / 180) - (Y - c->y)*sin(ovalAngle*PI / 180) + c->x;
        y = (X - c->x)*sin(ovalAngle*PI / 180) + (Y - c->y)*cos(ovalAngle*PI / 180) + c->y;
    }
    
    //画点(x,y)和它的3个对称点
    void Draw4(struct MPOINT* c,GLdouble x, GLdouble y,double pointSize, struct Color color)
    {
        GLdouble X = c->x, Y = c->y,xn,yn;
        glColor3f(color.r, color.g, color.b);
        glPointSize(pointSize);
        glBegin(GL_POINTS);
        {
            /*
            glVertex2f(x+X,y+Y);
            glVertex2f(-x+X, y+Y);
            glVertex2f(x+X, -y+Y);
            glVertex2f(-x+X, -y+Y);
            */
            getNewPoint(c,x + X, y + Y, xn, yn);
            glVertex2f(xn, yn);
            getNewPoint(c, -x + X, y + Y, xn, yn);
            glVertex2f(xn, yn);
            getNewPoint(c, x + X, -y + Y, xn, yn);
            glVertex2f(xn, yn);
            getNewPoint(c, -x + X, -y + Y, xn, yn);
            glVertex2f(xn, yn);
        }
        glEnd();
        glFlush();
    }
    //中点Bresenham算法 for Oval
    void Oval_Bresenham(struct MPOINT* c,double pointSize, struct Color color)
    {
        if (longAxes <= 0 || shortAxes <= 0) {
            longAxes = 50, shortAxes = 10;
        }
        GLdouble d = shortAxes * shortAxes + longAxes * longAxes*(0.25 - shortAxes), x = 0, y = shortAxes;
        while (shortAxes*shortAxes*(x + 1) < longAxes * longAxes * (y - 0.5))
        {
            Draw4(c,x, y, pointSize,color);
            if (d <= 0)
            {
                d += shortAxes * shortAxes *(2 * x + 3);
                x++;
            }
            else
            {
                d += shortAxes * shortAxes *(2 * x + 3) + longAxes * longAxes *(-2 * y + 2);
                x++;
                y--;
            }
        }
    
        d = shortAxes * shortAxes*(x + 0.5)*(x + 0.5) + longAxes * longAxes *(y - 1)*(y - 1) - longAxes * longAxes * shortAxes * shortAxes;
        while (y >= 0)
        {
            Draw4(c,x,y, pointSize,color);
            if (d <= 0)
            {
                d += shortAxes * shortAxes *(2*x + 2) + longAxes * longAxes *(-2*y + 3);
                x++;
                y--;
            }
            else
            {
                d += longAxes * longAxes *(-2*y + 3),
                y--;
            }
        }
    }
    
    
    //======================================================= 多边形的扫描转换和区域填充 ===============
    
    
    // 点集按序连线
    void buildPloy(vector<struct MPOINT> vertexSet,double &ymin,double& ymax)
    {
        
        int len = vertexSet.size();
        cout << "多边形边条数:	" << len << endl;
        /*
        //划线1
        glBegin(GL_LINES);
        {
            for (int i = 1; i < len; i++) {
                cout << vertexSet[i].x << "  " << vertexSet[i].y << endl;
                glVertex2i(vertexSet[i - 1].x, vertexSet[i - 1].y);
                glVertex2i(vertexSet[i].x, vertexSet[i].y);
            }
            glVertex2i(vertexSet[0].x,vertexSet[0].y);
            glVertex2i(vertexSet[len-1].x, vertexSet[len - 1].y);
        }
        glEnd();
        glFlush();
        */
        struct lineEquation tmpE;
        ymin = vertexSet[0].y;
        ymax = ymin;
        //划线二
        for (int i = 1; i < len; i++) {
            //划线
            Line_DDA(&vertexSet[i - 1], &vertexSet[i]);
            // k不存在时 x = x1 = x2
            if (abs((vertexSet[i - 1].x - vertexSet[i].x)) <1e-10 ) {
                tmpE.fk = true;
            }
            else { // y = k*x +b
                tmpE.fk = false;
                tmpE.k = (double)(vertexSet[i - 1].y - vertexSet[i].y) / (double)(vertexSet[i - 1].x - vertexSet[i].x);
                tmpE.b = vertexSet[i - 1].y - tmpE.k * vertexSet[i - 1].x;
                // k == 0 时 y = b
            }
            // 求直线所占范围 xmin xmax ymin ymax
            if (vertexSet[i - 1].x <= vertexSet[i].x) {
                tmpE.x1 = vertexSet[i - 1].x;
                tmpE.x2 = vertexSet[i].x;
            }
            else {
                tmpE.x1 = vertexSet[i].x;
                tmpE.x2 = vertexSet[i - 1].x;
            }
            if (vertexSet[i - 1].y <= vertexSet[i].y) {
                tmpE.y1 = vertexSet[i - 1].y;
                tmpE.y2 = vertexSet[i].y;
            }
            else {
                tmpE.y1 = vertexSet[i].y;
                tmpE.y2 = vertexSet[i - 1].y;
            }
            lineEV.push_back(tmpE);
            // 更新扫描线
            if (ymin > vertexSet[i].y) {
                ymin = vertexSet[i].y;
            }
            if (ymax < vertexSet[i].y) {
                ymax = vertexSet[i].y;
            }
        }
        // 划线
        Line_DDA(&vertexSet[0], &vertexSet[len-1]);
        // k不存在时 x = x1 = x2
        if (abs((vertexSet[0].x - vertexSet[len -1].x)) < 1e-10) {
            tmpE.fk = true;
        }
        else {
            tmpE.fk = false;
            tmpE.k = (double)(vertexSet[0].y - vertexSet[len - 1].y) / (double)(vertexSet[0].x - vertexSet[len - 1].x);
            tmpE.b = vertexSet[0].y - tmpE.k * vertexSet[0].x;
        }
        if (vertexSet[0].x <= vertexSet[len - 1].x) {
            tmpE.x1 = vertexSet[0].x;
            tmpE.x2 = vertexSet[len - 1].x;
        }
        else {
            tmpE.x1 = vertexSet[len - 1].x;
            tmpE.x2 = vertexSet[0].x;
        }
        if (vertexSet[0].y >= vertexSet[len -1].y) {
            tmpE.y1 = vertexSet[len - 1].y;
            tmpE.y2 = vertexSet[0].y;
        }
        else {
            tmpE.y1 = vertexSet[0].y;
            tmpE.y2 = vertexSet[len - 1].y;
        }
        lineEV.push_back(tmpE);
    }
    
    // 画点
    void drawPoint(struct MPOINT& a,GLdouble pointSize,struct Color color) {
        glColor3f(color.r, color.g, color.b);
        glPointSize(pointSize);
        glBegin(GL_POINTS);
        {
            glVertex2f(a.x,a.y);
        }
        glEnd();
        glFlush();
    }
    
    
    bool cmp(struct LineAE& a,struct LineAE& b)
    {
        if (a.x != b.x) {
            return a.x < b.x;
        }
        else {
            return a.dx < b.dx;
        }
    }
    //改进的有效边表算法(Y连贯性算法)
    //求交点,排序(生成AE表)  匹配  填色
    void buildAE(double ymin,double ymax)
    {
        int numLE = lineEV.size();
        double x;
        vector<ActiveEdge> lineAE;
        ActiveEdge *tmpAE,*preAE;
        activeEdge.clear();
    
        //cout << "最小扫描线: "<<ymin << "	最大扫描线:" << ymax << "	扫描线数量: " << ymax - ymin << endl;
        // 每条y
        for (int i = ymin; i <= ymax; i++) {
            lineAE.clear();
            int t = 0; vector<struct lineEquation> le;
            // 多边形的每条边
            for (int j = 0; j < numLE; j++) {
                // 求交点,将相交的直线暂存 x y(max) 1/k next
                //该直线斜率不存在时,直线上的x都相等
                if (lineEV[j].fk) {
                    x = lineEV[j].x1;
                    if (i - lineEV[j].y1 >= 0 && i - lineEV[j].y2 <= 0) {
                        tmpAE = new ActiveEdge();
                        tmpAE->x = x;
                        tmpAE->ymax = lineEV[j].y2;
                        lineAE.push_back(*tmpAE);
                    }
                    continue;
                }
                if (lineEV[j].k == 0) {
                    continue;
                }
                else {//斜率存在,求得交点
                    if (lineEV[j].y1 == i) {
                        if (lineEV[j].k > 0) {
                            x = lineEV[j].x1;
                        }
                        else {
                            x = lineEV[j].x2;
                        }
                    }
                    else if (lineEV[j].y2 == i) {
                        if (lineEV[j].k > 0) {
                            x = lineEV[j].x2;
                        }
                        else {
                            x = lineEV[j].x1;
                        }
                    }
                    else {
                        x = ((i - lineEV[j].b) / lineEV[j].k);
                    }
                }
                if (x - lineEV[j].x1 >=0 && x - lineEV[j].x2<=0) {
                    tmpAE = new ActiveEdge();
                    tmpAE->x = x;
                    tmpAE->ymax = lineEV[j].y2;
                    if(!lineEV[j].fk)
                        tmpAE->dx = 1 / lineEV[j].k;
                    lineAE.push_back(*tmpAE);
                }
            }
            
            // 有效线段排序
            sort(lineAE.begin(), lineAE.end(), cmp);
            int  aeNum = lineAE.size();
            if (aeNum > 0) {
                // 转化为AE表
                ActiveEdge *preAe = new ActiveEdge(), *head = new ActiveEdge();
                preAe->x = lineAE[0].x;
                preAe->ymax = lineAE[0].ymax;
                preAe->dx = lineAE[0].dx;
                preAe->next = NULL;
                head = preAe;
                for (int k = 1; k < aeNum; k++) {
                    ActiveEdge *aeTmp = new ActiveEdge();
                    aeTmp->x = lineAE[k].x;
                    aeTmp->ymax = lineAE[k].ymax;
                    aeTmp->dx = lineAE[k].dx;
                    aeTmp->next = NULL;
                    preAe->next = aeTmp;
                    preAe = aeTmp;
                }
                activeEdge.push_back(*head);
            }
        }
    
    
        int numAE = activeEdge.size();
        // 使用AE表
        // 对每个桶的每条有效边交点进行必配
        struct MPOINT *a = NULL;// (tmpAE->x, ymin + i);
        struct MPOINT *b = NULL;// (tmpAE->next->x, ymin + i);
        tmpAE = new ActiveEdge();
        preAE = new LineAE();
        vector<double> po(1,0);
        for (int i = 0; i < numAE; i++) {
            int y = ymin + i;
            bool f = true;// 单复数标志 匹配时使用
    
            // 有效边链表 配对
            *tmpAE = activeEdge[i];
            *preAE = activeEdge[i];
            a = NULL;
            b = NULL;
            po.clear();
            while (tmpAE != NULL) {
                po.push_back(tmpAE->x);
                if (tmpAE->next !=NULL) {
                    if (tmpAE->x == tmpAE->next->x) {
                        if ((tmpAE->ymax > y && tmpAE->next->ymax > y)) {
                            po.push_back(tmpAE->x);
                        }
                        else if ((tmpAE->ymax < y && tmpAE->next->ymax < y)) {
                            po.pop_back();
                        }
                        else if ((tmpAE->ymax == y && tmpAE->next->ymax == y)) {
                            po.pop_back();
                        }
                        else {
    
                        }
                        if (tmpAE->next->next == NULL) {
                            break;
                        }
                        else {
                            tmpAE = tmpAE->next->next;
                        }
                    }
                    else {
                        tmpAE = tmpAE->next;
                    }
                }
                else {
                    break;
                }
            }
            int con = po.size();
            for (int k = 1; k < con; k+=2) {
                a = new struct MPOINT(po[k-1], y);
                b = new struct MPOINT(po[k], y);
                Line_DDA(a, b);
            }
        }
    }
    
    // 获得福字矩阵
    Matrix getFuMatrix(string filePath)
    {
        vector<struct MPOINT> pointV;
        struct MPOINT a;
        ifstream fin(filePath);
        if (!fin.is_open()) {
            std::cerr << "file read wrong!
    ";
        }
        while (!fin.eof())
        {
            fin >> a.x >> a.y;
            a.x *= 300;
            a.y *= 300;
            a.y = 350 - a.y;
            pointV.push_back(a);
        }
        int numPoint = pointV.size();
        //生成点集矩阵
        Matrix matrix(numPoint, 3);
        for (int i = 0; i < numPoint; i++) {
            matrix[i][0] = pointV[i].x;
            matrix[i][1] = pointV[i].y;
            matrix[i][2] = 1;
        }
        return matrix;
    }
    
    // 计算一阶矩二阶矩
    //参数: 点云矩阵,质心,长半轴,短半轴,倾角(单位为角度不是弧度)
    void computeSecondMoment(Matrix& matrix, struct MPOINT& center,GLdouble& w,GLdouble& l,GLdouble& theta)
    {
        int pointNum = matrix.rows();
        center.x = 0.0;
        center.y = 0.0;
        for (int i = 0; i < pointNum; i++) {
            center.x += matrix[i][0];
            center.y += matrix[i][1];
        }
        // 质心
        center.x /= pointNum;
        center.y /= pointNum;
    
        // 二阶矩矩阵 -- 半长轴 半短轴 角度(弧度)
        double u20 = 0.0, u11 = 0.0, u02 = 0.0;
        for (int i = 0; i < pointNum; i++) {
            u20 += pow(matrix[i][0] - center.x, 2);
            u11 += (matrix[i][0] - center.x) * (matrix[i][1] - center.y);
            u02 += pow(matrix[i][1] - center.y, 2);
        }
        double lam1 = 0.5*((u20 + u02) + sqrt(pow(u20 - u02, 2) + 4 * u11*u11));
        double lam2 = 0.5*((u20 + u02) - sqrt(pow(u20 - u02, 2) + 4 * u11*u11));
        w = sqrt(lam1 / pointNum);//半长轴
        l = sqrt(lam2 / pointNum);//半短轴
        theta = 0.5*atan(2 * u11 / (u20 - u02)) * 180 / PI; // 椭圆倾角 这里化弧度为角度
    }
    
    //画福字 指定颜色,点的大小
    void drawFu(Matrix& matrix,GLdouble pointSize,struct Color color)
    {
        struct MPOINT tmpP(0,0);
        int r = matrix.rows();
        for (int i = 0; i < r; i++) {
            tmpP.x = matrix[i][0];
            tmpP.y = matrix[i][1];
            drawPoint(tmpP, pointSize, color);
        }
    }
    
    //画福字的椭圆; 传入theta为弧度
    void drawFuOval(struct Color color,struct MPOINT& center, double& w, double& l, double& theta)
    {
        longAxes = w;
        shortAxes = l;
        ovalAngle = theta;
        // 画椭圆
        Oval_Bresenham(&center, 1, color);
    
        // 长轴、短轴线
        struct MPOINT tmp(0, 0), tmp1(0, 0);
        double cha1 = 100, cha2 = 50;
        double k = tan(theta*PI / 180);
        tmp.x = center.x + cha1;
        tmp.y = center.y + cha1 * k;
        tmp1.x = center.x - cha1;
        tmp1.y = center.y - cha1 * k;
        Line_DDA(&tmp, &tmp1);
    
        k = tan((theta + 90)*PI / 180); // 化为角度计算
        tmp.x = center.x + cha2;
        tmp.y = center.y + cha2 * k;
        tmp1.x = center.x - cha2;
        tmp1.y = center.y - cha2 * k;
        Line_DDA(&tmp, &tmp1);
    
    }
    
    
    // 平移矩阵
    void matrixTransolation(Matrix& matrixT,GLdouble x, GLdouble y)
    {
        matrixT[0][0] = 1;
        matrixT[0][1] = 0;
        matrixT[0][2] = 0;
        matrixT[1][0] = 0;
        matrixT[1][1] = 1;
        matrixT[1][2] = 0;
        matrixT[2][0] = x;
        matrixT[2][1] = y;
        matrixT[2][2] = 1;
    }
    // 旋转矩阵
    void matrixRotate(Matrix& matrixT, GLdouble x1, GLdouble x2,GLdouble y1,GLdouble y2)
    {
        matrixT[0][0] = x1;
        matrixT[0][1] = x2;
        matrixT[0][2] = 0;
        matrixT[1][0] = y1;
        matrixT[1][1] = y2;
        matrixT[1][2] = 0;
        matrixT[2][0] = 0;
        matrixT[2][1] = 0;
        matrixT[2][2] = 1;
    }
    
    void clear()
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glutSwapBuffers();
    }
    
    // 福字变换
    void fuTransformation()
    {
        double wX, lX, thetaX, wY, lY, thetaY;
        struct MPOINT centerX, centerY;
        struct Color color1(0, 0, 1);
        Matrix matrixX = getFuMatrix("./X.txt"); // 待变换福
        computeSecondMoment(matrixX, centerX, wX, lX, thetaX);
        GLdouble w = wX, l = lX;
    
        drawPoint(centerX, 5, color1);
        drawFu(matrixX, 2, color1);
        drawFuOval(color1, centerX, wX, lX, thetaX);
        
    
        struct Color color(1, 0, 0);
        Matrix matrixY = getFuMatrix("./Y.txt"); // 标准福
        computeSecondMoment(matrixY, centerY, wY, lY, thetaY);
        drawPoint(centerY, 5, color);
        drawFu(matrixY, 2, color);
        drawFuOval(color, centerY, wY, lY, thetaY);
        
        
        Sleep(500);//-----------------------------------移位
        clear();
    
        drawPoint(centerY, 5, color);
        drawFu(matrixY, 2, color);
        drawFuOval(color, centerY, wY, lY, thetaY);
        //移位,质心一致
        Matrix matrixT(3, 3);
        matrixTransolation(matrixT, centerY.x - centerX.x, centerY.y - centerX.y);
        matrixX = matrixX * matrixT;
        computeSecondMoment(matrixX, centerX, wX, lX, thetaX);
        drawPoint(centerX, 5, color1);
        drawFu(matrixX, 2, color1);
        drawFuOval(color1, centerX, wX, lX, thetaX);
    
        
        Sleep(500);//-----------------------------------缩放
        clear();
    
        drawPoint(centerY, 5, color);
        drawFu(matrixY, 2, color);
        drawFuOval(color, centerY, wY, lY, thetaY);
        //缩放
        //移至原点
        matrixTransolation(matrixT, -centerX.x, -centerX.y);
        matrixX = matrixX * matrixT;
        //缩放
        matrixRotate(matrixT, wY / wX, 0, 0, lY / lX);
        matrixX = matrixX * matrixT;
        //移回
        matrixTransolation(matrixT, centerX.x, centerX.y);
        matrixX = matrixX * matrixT;
        computeSecondMoment(matrixX, centerX, wX, lX, thetaX);
    
        drawPoint(centerX, 5, color1);
        drawFu(matrixX, 2, color1);
        drawFuOval(color1, centerX, wX, lX, thetaX);
    
        
        Sleep(500);//-----------------------------------旋转
        clear();
    
        drawPoint(centerY, 5, color);
        drawFu(matrixY, 2, color);
        drawFuOval(color, centerY, wY, lY, thetaY);
    
    
        GLdouble thetaXDegree = (thetaY - thetaX) * PI / 180;
        //旋转 
        //移至原点
        matrixTransolation(matrixT, -centerX.x, -centerX.y);
        matrixX = matrixX * matrixT;
        //旋转
        matrixRotate(matrixT, cos(thetaXDegree), sin(thetaXDegree), -sin(thetaXDegree), cos(thetaXDegree));
        matrixX = matrixX * matrixT;
        //移回
        matrixTransolation(matrixT, centerX.x, centerX.y);
        matrixX = matrixX * matrixT;
        computeSecondMoment(matrixX, centerX, wX, lX, thetaX);
    
        
        drawPoint(centerX, 5, color1);
        drawFu(matrixX, 2, color1);
        drawFuOval(color1, centerX, wX, lX, thetaX);
    
    }
    
    // ---------------------------------------------------------------------------------------------------Bezier 曲线
    GLdouble* Coefficient(int n)
    {
        GLdouble* res = new GLdouble[n + 1],tmp1,tmp2;
        int con = 0,tmpI,mid = n/2;
        res[0] = 1;
        res[n] = 1;
        for (int i = 1; i <= mid; i++) {
            tmp1 = n;
            tmpI = n;
            con = i - 1;
            while (con > 0) {
                tmpI--;
                tmp1 *= tmpI;
                con--;
            }
            con = i - 1;
            tmp2 = i;
            while (con > 1) {
                tmp2 *= con;
                con--;
            }
            cout << tmp1 << " ********* " << tmp2 << endl;
            res[i] = tmp1 / tmp2;
            res[n - i] = res[i];
        }
        return res;
    }
    void bezier()
    {
        clear();
        int pointNum = vertexSet.size();
        struct  Color color(1,0,0);
        drawPoint(vertexSet[0], 1.0, color);
        for (int i = 1; i < pointNum; i++) {
            drawPoint(vertexSet[i],1.0,color);
            Line_DDA(&vertexSet[i-1], &vertexSet[i]);
        }
        struct  Color color1(0, 0, 1);
        GLdouble deltaT = 0.01;
        struct MPOINT *pointTmp = new MPOINT(),*perPoint = NULL;
        if (pointNum == 2) {
            for (GLdouble t = 0; t <= 1.0; t += deltaT) {
                pointTmp->x = (1 - t) * vertexSet[0].x + t * vertexSet[1].x;
                pointTmp->y = (1 - t) * vertexSet[0].y + t * vertexSet[1].y;
                if (!perPoint) {
                    perPoint = new MPOINT();
                    *perPoint = *pointTmp;
                    drawPoint(*pointTmp, 1.0, color1);
                }
                else {
                    Line_DDA(perPoint, pointTmp);
                    *perPoint = *pointTmp;
                }
            }
        }
        else if (pointNum == 3) {
            for (GLdouble t = 0; t <= 1.0; t += deltaT) {
                pointTmp->x = (1 - t) *(1 - t)* vertexSet[0].x +2* t * (1 - t)* vertexSet[1].x + t * t * vertexSet[2].x;
                pointTmp->y = (1 - t) *(1 - t)* vertexSet[0].y +2* t * (1 - t) *vertexSet[1].y + t * t * vertexSet[2].y;
                if (!perPoint) {
                    perPoint = new MPOINT();
                    *perPoint = *pointTmp;
                    drawPoint(*pointTmp, 1.0, color1);
                }
                else {
                    Line_DDA(perPoint, pointTmp);
                    *perPoint = *pointTmp;
                }
            }
        }
        else {
    
            /*
            // 3次bezier分段
            int i = 3;
            for (; i < pointNum; i+=3) {
                for (GLdouble t = 0; t <= 1.0; t += deltaT) {
                    pointTmp.x = (1 - t) *(1 - t)* (1 - t) * vertexSet[i - 3].x + 3 * t * (1 - t)*(1 - t)* vertexSet[i - 2].x + 3 * t * t *(1 - t)* vertexSet[i - 1].x + t * t*t*vertexSet[i].x;
                    pointTmp.y = (1 - t) *(1 - t)* (1 - t) * vertexSet[i - 3].y + 3 * t * (1 - t)*(1 - t)* vertexSet[i - 2].y + 3 * t * t *(1 - t)* vertexSet[i - 1].y + t * t*t*vertexSet[i].y;
                    drawPoint(pointTmp, 1.0, color1);
                }
            }*/
            GLdouble* coefficient = Coefficient(pointNum - 1);
            for (GLdouble t = 0; t <= 1.0; t += deltaT) {
                pointTmp->x = 0;
                pointTmp->y = 0;
                for (int i = 0; i < pointNum; i++) {
                    pointTmp->x += coefficient[i] * pow(1 - t, pointNum - 1 - i)*pow(t, i)*vertexSet[i].x;
                    pointTmp->y += coefficient[i] * pow(1 - t, pointNum - 1 - i)*pow(t, i)*vertexSet[i].y;
                }
                if (!perPoint) {
                    perPoint = new MPOINT();
                    *perPoint = *pointTmp;
                    drawPoint(*pointTmp, 1.0, color1);
                }
                else {
                    Line_DDA(perPoint,pointTmp);
                    *perPoint = *pointTmp;
                }
            }
        }
    }
    
    //==========================================================================事件========
    
    
    /*鼠标点击事件 */
    void mouseClick(int btn, int state, int x, int y)
    {
        if (choice == 6 && btn == 0 && state == 0) {
            struct MPOINT* tmpPoint = new MPOINT(x,y);
            vertexSet.push_back(*tmpPoint);
            bool f = false;
            if (vertexSet.size()>1&&*tmpPoint == vertexSet[0]) {
                f = true;
                tmpPoint->x = vertexSet[0].x;
                tmpPoint->y = vertexSet[0].y;
            }
            struct Color color(1, 0, 0);
            drawPoint(*tmpPoint,1.0,color);
            if (f) {
                vertexSet.pop_back();//弹出最后一个顶点,与开始点重合
                double ymin, ymax;
                buildPloy(vertexSet,ymin,ymax);
                cout <<"最小扫描线: "<< ymin << "	最大扫描线: " << ymax << endl;
                buildAE(ymin,ymax);
            }
        }
        if (choice == 8 && btn == 0 && state == 0) {
            struct MPOINT* tmpPoint = new MPOINT(x, y);
            vertexSet.push_back(*tmpPoint);
            if (vertexSet.size() >= 2) {
                bezier();
            }
        }
        if (btn == 0 && state == 0) {
            if (oldPoint == NULL) {
                oldPoint = new MPOINT(x, y);
            }
            else {
                curPoint = new MPOINT(x, y);
            }
        }
        if (oldPoint != NULL && curPoint != NULL) {
            if (choice == 1) {
                Line_DDA(oldPoint, curPoint); // DDA for line
                //Line_Bresenham(oldPoint, curPoint);// Bresenham for Line
            }
            else if (choice == 2) {
                GLdouble R = sqrt(pow(curPoint->x - oldPoint->x, 2) + pow(curPoint->y - oldPoint->y, 2));
                //Circle_DDA(oldPoint, R); // DDA for Circle
                //Circle_Polar(oldPoint,R); // Polar for Circle
                Circle_Bresenham(oldPoint, R); // Bresenham for Circle
            }
            else if (choice == 3) {
                struct Color color(1, 0, 0);
                Oval_Bresenham(oldPoint,1,color); // Bresenham for Oval
            }
            flag = 0;
            free(oldPoint);
            free(curPoint);
            oldPoint = NULL;
            curPoint = NULL;
        }
    }
    
    //键盘事件
    void SpecialKey(GLint c, GLint x, GLint y) {
        //向上的箭头,清除窗口
        if (c == GLUT_KEY_UP) {
            glClear(GL_COLOR_BUFFER_BIT);
            glFlush();
        }
        //向下的箭头,输入椭圆参数
        if (c == GLUT_KEY_DOWN) {
            cout << "Please input the  long axis, shaort axis and the rotation angle of Oval
    ";
            cin >> longAxes >> shortAxes >> ovalAngle;
        }
        if (c == GLUT_KEY_LEFT) {
        
        }
        //ESC 退出窗口
        if (c == 27) {
            exit(0);
        }
    }
    
    /* 鼠标移动事件 */
    void mouseMove(int x, int y)
    {
        //printf("移动鼠标中,x:%d,y%d
    ", x, y);
    }
    
    // 菜单选择后
    void mymenu(int value) {
    
        if (value == 1) {
            choice = 1;
        }
        if (value == 2) {
            choice = 2;
        }
        if (value == 3) {
            choice = 3;
        }
        if (value == 6) {
            choice = 6;
            vertexSet.clear();
        }
        if (value == 7) {
            choice = 7;
            fuTransformation();
        }
        if (value == 8) {
            choice = 8;
            vertexSet.clear();
        }
        if (value == 4) {
            vertexSet.clear();
            activeEdge.clear();
            lineEV.clear();
            system("cls");
            glClear(GL_COLOR_BUFFER_BIT);
            glutSwapBuffers();
        }
        if (value == 5) {
            exit(0);
        }
        free(oldPoint);
        free(curPoint);
        oldPoint = NULL;
        curPoint = NULL;
    }
    
    // 初始化菜单项
    void initMenu()
    {
        //添加菜单项
        glutAddMenuEntry("Line", 1);
        glutAddMenuEntry("Circle", 2);
        glutAddMenuEntry("Oval", 3);
        glutAddMenuEntry("Polygonal scan conversion", 6);
        glutAddMenuEntry("FU transformation", 7);
        glutAddMenuEntry("Bezier", 8);
        glutAddMenuEntry("Clear Screen", 4);
        glutAddMenuEntry("Exit", 5);
        glutAttachMenu(GLUT_RIGHT_BUTTON);//把当前菜单注册到指定的鼠标键
        choice = 1;
    }
    
    
    
    //============================================== MAIN =============================
    int main(int argc, char *argv[])
    {
        glutInit(&argc, argv);
        /*显示模式*/
        glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
        /*创建窗口*/
        glutInitWindowPosition(100, 100);
        glutInitWindowSize(600, 600);
        glutCreateWindow("OpenGL");
        glClearColor(1.0, 1.0, 0.6, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3f(0.0f, 0.0f, 0.0f);
        /*窗口坐标设置*/
        gluOrtho2D(0, 600.0, 600.0, 0);
        /*回调函数*/
        glutDisplayFunc(display);
        /*鼠标点击事件,鼠标点击或者松开时调用 */
        glutMouseFunc(mouseClick);
        /*鼠标移动事件,鼠标按下并移动时调用 */
        glutMotionFunc(mouseMove);
        /*键盘事件,键盘按下时调用 */
        glutSpecialFunc(&SpecialKey);
        /*菜单*/
        int menu=glutCreateMenu(mymenu);//注册菜单回调函数
        //添加菜单项
        initMenu();
    
        /*主循环*/
        glutMainLoop();
        return 0;
    }
  • 相关阅读:
    [源码解析] 消息队列 Kombu 之 基本架构
    拿破仑,技术大牛晋级管理之后的困境
    Dyno-queues 分布式延迟队列 之 辅助功能
    Dyno-queues 分布式延迟队列 之 生产消费
    Dyno-queues 分布式延迟队列 之 基本功能
    DOM和BOM的区别
    Navigator对象
    expr命令
    ReactRouter的实现
    History对象
  • 原文地址:https://www.cnblogs.com/kimsimple/p/9050573.html
Copyright © 2011-2022 走看看