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 << "多边形边条数:\t" << 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 << "\t最大扫描线:" << ymax << "\t扫描线数量: " << 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!\n";
    }
    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 << "\t最大扫描线: " << 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\n";
        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\n", 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;
}

 

posted @ 2018-05-31 19:21  kimsimple  阅读(1216)  评论(0编辑  收藏  举报