OpenGL绘制Bezier曲线的方法

 更新时间:2020年04月20日 14:37:19   作者:process-z.com  
这篇文章主要为大家详细介绍了OpenGL绘制Bezier曲线的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了OpenGL绘制Bezier曲线的具体代码,供大家参考,具体内容如下

项目要求:

– 使用鼠标在屏幕中任意设置控制点,并生成曲线

– 使用鼠标和键盘的交互操作实现对曲线的修改。

项目总体介绍

本项目利用Bezier曲线生成算法生成可由用户自定义的曲线。可实现核心功能如下:

1、用户用鼠标左击屏幕任意处产生记录点。

2、鼠标右击屏幕任意处由先前的任意个数记录点和其先后关系生成Bezier曲线。

另有辅助输入功能:

1、按键盘‘C'键可清除所有记录点。

2、按键盘‘R'键可清除上一个记录点。

3、按键盘‘Q'键可推出程序。

项目设计思路

1、Bezier曲线介绍:

贝塞尔曲线就是这样的一条曲线,它是依据四个位置任意的点坐标绘制出的一条光滑曲线。在历史上,研究贝塞尔曲线的人最初是按照已知曲线参数方程来确定四个点的思路设计出这种矢量曲线绘制法。1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名是为贝塞尔曲线。

2、生成公式:

(1)线性公式(只有两个点情况)

给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:

且其等同于线性插值。

(2)二次方公式(三个点组成)

二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:

TrueType字型就运用了以贝兹样条组成的二次贝兹曲线。

(3)三次方公式(四个点)

P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。

曲线的参数形式为:

现代的成象系统,如PostScript、Asymptote和Metafont,运用了以贝兹样条组成的三次贝兹曲线,用来描绘曲线轮廓。

(4)一般参数公式(n个点)

阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:

N阶的贝兹曲线,即N-1阶贝兹曲线之间的插值。

#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<GL/glut.h>
//定义控制点数目的最大值
#define MAX_CPTX 25 
int ncpts=0;//实际控制点个数
static int width=600,height=600;//窗口大小
typedef struct
{
 GLfloat x,y;
} POINT;
POINT cpts[MAX_CPTX];//存储控制点坐标
//求n!
int JieCheng(int n)
{
 if(n==1||n==0)
 {
 return 1;
 }
 else
 {
 return n*JieCheng(n-1);
 }
}
//求组合排列
double C(int n,int i)
{
 return ((double)JieCheng(n))/((double)(JieCheng(i)*JieCheng(n-i)));
}
//求一个数u的num次方
double N(double u,int n)
{
 double sum=1.0;
 if (n==0)
 {
 return 1;
 }
 for(int i=0;i<n;i++)
 {
 sum*=u;
 }
 return sum;
}
 
//绘制bezier曲线
void drawBezier(POINT *p)
{ 
 void display();
 if(ncpts<=0) return; 
 
 POINT *p1;
 p1=new POINT[1000];
 GLfloat u=0,x,y;
 int i,num=1;
 p1[0]=p[0];
 for(u=0;u<=1;u=u+0.001)
 { 
 x=0;
 y=0;
 for(i=0;i<ncpts;i++)
 { 
  x+=C(ncpts-1,i)*N(u,i)*N((1-u),(ncpts-1-i))*p[i].x;
  y+=C(ncpts-1,i)*N(u,i)*N((1-u),(ncpts-1-i))*p[i].y;
 }
 p1[num].x=x;
 p1[num].y=y;
 num++;
 } 
 
  glPointSize(4.0);
  glColor3f(0.0,0.0,0.0);
  glBegin(GL_LINE_STRIP);
  for(int k=0;k<1000;k++)
 glVertex2f(p1[k].x,p1[k].y);
  glEnd();
  glFlush();
 return;
}
 
 
 
//输入新的控制点
static void mouse(int button, int state,int x,int y)
{
void display();
float wx,wy;
//鼠标未按下左键,不做响应
if(state!=GLUT_DOWN)
 return;
else 
 {if(button==GLUT_LEFT_BUTTON)
 {
//转换坐标
wx=(2.0*x)/(float)(width-1)-1.0;
wy=(2.0*(height-1-y))/(float)(height-1)-1.0;
//判断控制点数目是否超过最大值
if(ncpts==MAX_CPTX)
 return;
//存储控制点
cpts[ncpts].x=wx;
cpts[ncpts].y=wy;
ncpts++;
//绘制控制点
glColor3f(0.0,0.0,0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2f(wx,wy);
glEnd();
glFlush();
}
if(button==GLUT_RIGHT_BUTTON)
{
display();
drawBezier(cpts);
}
}
}
void display(void)
{
 int i;
 glClear(GL_COLOR_BUFFER_BIT);
 glColor3f(0.0,0.0,0.0);
 glPointSize(5.0);
 glBegin(GL_POINTS);
 for (i = 0; i < ncpts; i++)
  glVertex2f(cpts[i].x,cpts[i].y);
 glEnd();
 glFlush();
 
}
//键盘回调函数
void keyboard(unsigned char key,int x,int y)
{
 switch (key)
 {
  case 'q': case 'Q':
   exit(0);
   break;
  case 'c': case 'C':
 ncpts = 0;
 glutPostRedisplay();
   break;
 case 'r': case 'R':
 ncpts--;
 glutPostRedisplay();
 break;
 }
}
 
//重绘函数
void reshape(int w,int h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,w,h);//调整视口
width=w;
height=h;
}
int main(int argc, char **argv)
{
//初始化
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(width,height);
glutCreateWindow("zjc2012211763");
//注册回调函数
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(0.0,0.0,0.0);
glutMainLoop();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C++实现LeetCode(159.最多有两个不同字符的最长子串)

    C++实现LeetCode(159.最多有两个不同字符的最长子串)

    这篇文章主要介绍了C++实现LeetCode(159.最多有两个不同字符的最长子串),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++的程序流程结构你了解多少

    C++的程序流程结构你了解多少

    这篇文章主要为大家详细介绍了C++的程序流程结构,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • C++中构造函数详解

    C++中构造函数详解

    大家好,本篇文章主要讲的是C++中构造函数详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-02-02
  • C++ AVL树插入新节点后的四种调整情况梳理介绍

    C++ AVL树插入新节点后的四种调整情况梳理介绍

    AVL树是高度平衡的而二叉树,它的特点是AVL树中任何节点的两个子树的高度最大差别为1,本文主要给大家介绍了C++如何实现AVL树,需要的朋友可以参考下
    2022-08-08
  • 解决Qt设置QTextEdit行高的问题

    解决Qt设置QTextEdit行高的问题

    这篇文章介绍了Qt设置QTextEdit行高的方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • C语言 递归实现排雷游戏

    C语言 递归实现排雷游戏

    扫雷是电脑上很经典很经典的传统老游戏,从小编第一次摸到计算机开始就玩过扫雷,虽然当时并不理解玩法原理,但终是第一次玩电脑游戏,下面来从扫雷的前世今生讲起
    2021-11-11
  • C++构造函数的初始化列表详解

    C++构造函数的初始化列表详解

    这篇文章主要为大家介绍了C++构造函数的初始化列表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • 快来领取!你想要的C++/C语言优秀书籍

    快来领取!你想要的C++/C语言优秀书籍

    如何选择合适的C++/C语言书籍,是不是已经眼花缭乱,不知道该选择哪本好了呢?今天我来为大家分享两本不可错过的优秀书籍
    2017-09-09
  • C语言图书借阅系统源码

    C语言图书借阅系统源码

    这篇文章主要为大家分享了C语言图书借阅系统源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 浅谈Qt中使用CEF的几个要点(Windows下)

    浅谈Qt中使用CEF的几个要点(Windows下)

    下面小编就为大家带来一篇浅谈Qt中使用CEF的几个要点(Windows下)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07

最新评论