风也温柔

计算机科学知识库

java贝塞尔曲线算法-来绘制贝塞尔曲线吧

  在图形学中,绘制曲线是非常重要也是非常基础的课题之一,其中最容易想到可能就是贝塞尔曲线,当下许多的数学算法库或者绘图api都支持贝塞尔曲线的绘制;既然如此,这次不妨就让我们使用手动绘制一下曲线,并从中探究他的原理和性质。

  一、贝塞尔()曲线介绍

  贝塞尔曲线采用由顶点序列组成的多边形来控制曲线的几何形状。有趣的是,它的出现,一开始只是为了方便汽车的主体设计;它于1950年代法国工程师P.率先提出,后来,英国学者A.R.等改写了它的最初表达式,使得曲线的表示更为平滑和易于交互。

  贝塞尔曲线为计算机矢量图形学奠定了基础,其重要意义在于无论直线或曲线都能在数学上予以证明,也是为了纪念这位发明人,我们将这条曲线命名为。

  二、数学解释

  已知空间中两个点

  和

  ,那么空间中的直线段可以通过

  这种方式来表示,如图1所示。这种表示方式的直观几何意义是参数

  的任何一个值都与线段上的一个点相对应,例如:

  当

  时,

  ,表示线段

  的中点;

  当

  时,

  ,即端点

  ;

  当

  时java贝塞尔曲线算法

  ,即端点

  ;

  贝塞尔曲线工具_java贝塞尔曲线算法_贝塞尔曲线java代码

  贝塞尔曲线工具_贝塞尔曲线java代码_java贝塞尔曲线算法

  图1

  接下来我们进入正题,已知我们有一条

  这些点控制的曲线,那么一般的,我们说这是一条n次的曲线,这个曲线可以表示为

  ,这个公式中多项式

  为基函数,它的定义为

  ,其中

  就是大家所学的二项式系数

  。

  曲线公式与之前所说的空间中直线表达形式实际上有相同之处,只不过曲线上的控制点更多,并非仅由两个端点就可以决定,且每个控制点的参数是通过基函数得到的,换言之,基函数决定了每个控制点对于曲线上不同点的影响力。直观地看来基函数,它所造成的影响是全局的,但是,不同的控制点对某部分区域的影响力会更强一点,例如对于一个三次曲线,

  对曲线前半部分的影响力明显强于

  ,反过来也是如此。

  如图2就是一条由

  控制的三次曲线:

  java贝塞尔曲线算法_贝塞尔曲线java代码_贝塞尔曲线工具

  图2

  对于t=2的点,R(0.2)=0.512R0+0.384R1+0.096R2+0.008R3

  系数可以表示每个控制点对该点的影响力

  三、de 算法

  在计算机中java贝塞尔曲线算法-来绘制贝塞尔曲线吧,曲线常常采用递归剖分控制多边形的方法生成java贝塞尔曲线算法,这一剖分算法被称作de 算法。算法思想就是每一次都遍历一遍相邻的控制点,根据给定参数

  在两相邻控制点形成的线段上取一个新的控制点。显然,每遍历一遍当前的控制点后生成的新控制点会更加逼近曲线,且控制点的数量会减1,这样,当最后只剩一个控制点时,可以将这个控制点视为曲线上的点。如果我们取不同的

  ,就能够进行多次剖分,最终生成足够多的点去绘制一个曲线,这个曲线就近似为,单次剖分算法过程描述如下:

  贝塞尔曲线java代码_贝塞尔曲线工具_java贝塞尔曲线算法

  图3

  java贝塞尔曲线算法_贝塞尔曲线工具_贝塞尔曲线java代码

  例如,当

  时,三次曲线的剖分过程如图4所示:

  贝塞尔曲线工具_贝塞尔曲线java代码_java贝塞尔曲线算法

  图4

  四、代码展示

  这次采用c++编程,使用了glut库,同时为了更好地展示曲线的特性,实现了鼠标可拖拽控制点,具体代码如下

  <pre>#include

include

include

//控制点标记
int mask = -1;
//控制点,因为已经写了鼠标交互,所以初始点并不重要
GLfloat ctrl_points4 = {

{ -0.8f,  0.1f },
{ -0.4f,  0.6f },
{  0.2f, -0.5f },
{  0.7f,  0.2f },

};
//鼠标点击事件
void mouseClick(int button, int state, int x, int y)
{

if (button == GLUT_LEFT_BUTTON)
{
    if (state == GLUT_DOWN) {
        if (mask == -1) {
            for (int i = 0; i < 4; i++)
            {
                float mouse_x = (x - 200) / 200.0f, mouse_y = (200 - y) / 200.0f;
                float dis = sqrt((mouse_x - ctrl_points[i][0])*(mouse_x - ctrl_points[i][0]) + (mouse_y - ctrl_points[i][1])*(mouse_y - ctrl_points[i][1]));
                if (dis < 0.1f) mask = i;

<p>java贝塞尔曲线算法_贝塞尔曲线工具_贝塞尔曲线java代码

            }
        }
    }
    else if (state == GLUT_UP)
        mask = -1;
}

}
//鼠标移动事件
void mouseMove(int x, int y)
{

if (mask != -1) {
    float mouse_x = (x - 200) / 200.0f, mouse_y = (200 - y) / 200.0f;
    ctrl_points[mask][0] = mouse_x;
    ctrl_points[mask][1] = mouse_y;
    glutPostRedisplay();
}

}
//核心代码,实现了剖分过程
void de_Cateljau(int n, GLfloat list[][2])
{

float R_x[4];
float R_y[4];
int k = 0;
for (double t = 0.0; t