OpenGL实现Hermite算法绘制三次曲线

来源:互联网 发布:ps盖印图层快捷键 mac 编辑:程序博客网 时间:2024/05/19 16:04

首先是推导:节省功夫我就直接贴照片了。
程序加了鼠标的监听器,可以移动控制点和型值点。


Hermite算法推导


程序效果:
这里写图片描述

代码如下:

#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;}
原创粉丝点击