OpenGL實現Hermite演算法繪製三次曲線

離殤灬孤狼發表於2017-10-13

首先是推導:節省功夫我就直接貼照片了。
程式加了滑鼠的監聽器,可以移動控制點和型值點。


Hermite演算法推導
注意:圖片中矩陣第二行第二列應該為3,當時筆誤


程式效果:
這裡寫圖片描述

程式碼如下:

#include<gl/glut.h>
#include<math.h>
#include<windows.h>
#include<algorithm>
using namespace std;
struct Vertex
{
    int x, y;
    Vertex(int tx, int ty)
    {
        x = tx;
        y = ty;
    }
};

Vertex p0(100, 250);        //型值點
Vertex p1(400, 250);
Vertex c0(150, 200);        //控制點
Vertex c1(350, 300);        

bool mouseLeftIsDown = false;
bool mouseRightIsDown = false;

int caculateSquareDistance(Vertex a, Vertex b)
{
    return (a.x - b.x)*(a.x - b.x) + (a.y - b.y);
}
void Hermite(int n)     //精度
{
    //求出相對於控制點的向量(切線)
    //這裡把切點的長度人為擴大4倍,劃線的效果更為明顯(實際上不符合計算出的公式)
    Vertex tempC0((c0.x - p0.x)<<2, (c0.y - p0.y)<<2);
    Vertex tempC1((c1.x - p1.x)<<2, (c1.y - p1.y)<<2);

    double delTa = 1.0 / n;
    glBegin(GL_LINE_STRIP);
    for (int i = 0; i < n; i++)
    {
        double t = i * delTa;

        double t1 = 2 * pow(t, 3) - 3 * pow(t, 2) + 1;
        double t2 = -2 * pow(t, 3) + 3 * pow(t, 2);
        double t3 = pow(t, 3) - 2 * pow(t, 2) + t;
        double t4 = pow(t, 3) - pow(t, 2);

        glVertex2d(p0.x*t1 + p1.x*t2 + tempC0.x*t3 + tempC1.x*t4, p0.y*t1 + p1.y*t2 + tempC0.y*t3 + tempC1.y*t4);
    }
    glEnd();
}
void myDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT);       //清除。GL_COLOR_BUFFER_BIT表示清除顏色

    glPointSize(10.0f);
    glColor3f(0, 0, 1);
    //畫出型值點和控制點(藍色)
    glBegin(GL_POINTS);
    glVertex2d(p0.x, p0.y);
    glVertex2d(p1.x, p1.y);
    glVertex2d(c0.x, c0.y);
    glVertex2d(c1.x, c1.y);
    glEnd();

    //畫出控制點與型值點的連線(紅色)
    glColor3f(1, 0, 0);
    glLineWidth(3);
    glBegin(GL_LINES);
    glVertex2d(p0.x, p0.y);    glVertex2d(c0.x, c0.y);
    glVertex2d(p1.x, p1.y);    glVertex2d(c1.x, c1.y);
    glEnd();

    Hermite(200);

    glFlush();
    glutSwapBuffers();
}
void mouse(int button,int state,int x, int y)       //監聽滑鼠動作
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        mouseLeftIsDown = true;
    }
    if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
    {
        mouseLeftIsDown = false;
    }
    if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    {
        mouseRightIsDown = true;
    }
    if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
    {
        mouseRightIsDown = false;
    }
}
void motion(int x, int y)       //移動點
{
    if (mouseLeftIsDown)        //左鍵移動控制點
    {
        if (caculateSquareDistance(Vertex(x, y), c0) < 400)     //防止滑鼠移動過快點位無法及時讀取,經測試,400為一個較適合的值
        {
            c0.x = x;
            c0.y = y;
        }
        else if (caculateSquareDistance(Vertex(x, y), c1) < 400)
        {
            c1.x = x;
            c1.y = y;
        }
    }
    else if (mouseRightIsDown)      //右鍵移動型值點
    {
        if (caculateSquareDistance(Vertex(x, y), p0) < 400)
        {
            p0.x = x;
            p0.y = y;
        }
        else if (caculateSquareDistance(Vertex(x, y), p1) < 400)
        {
            p1.x = x;
            p1.y = y;
        }
    }
    glutPostRedisplay();        //重新構圖
}
void Reshape(int w, int h)      //兩個引數:視窗被移動後大小
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, w, h, 0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void initWindow(int &argc, char *argv[], int width, int height, char *title)    //初始化並顯示到螢幕中央
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - width) >> 1, (GetSystemMetrics(SM_CYSCREEN) - height) >> 1);       //指定視窗位置
    glutInitWindowSize(width, height);       //指定視窗大小
    glutCreateWindow(title);

    glClearColor(1, 1, 1, 0.0);
    glShadeModel(GL_FLAT);
}

int main(int argc, char *argv[])
{
    initWindow(argc, argv, 500, 500, "Hermite");

    puts("\n\t使用Hermite演算法,用兩頂點兩控制點繪製三次曲線。");
    puts("\t左鍵移動控制點,右鍵移動型值點");

    glutDisplayFunc(myDisplay);
    glutReshapeFunc(Reshape);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);

    glutMainLoop();

    return 0;
}

相關文章