引文1

URL:http://zhuxianzhong.blog.51cto.com/user_index.php?action=addblog_new


一阶贝赛尔曲线上的由两个点确定 P0 和P1,当t在0--->1区间上递增时,根据式(1)

会得到多个点的坐标,其实这些的点就是一条直线上的点。

B(t) = (1-t)P0 + tP1--------------------------------------(1)

即:

B(t).x = (1-t)P0.x + tP1.x

B(t).y = (1-t)P0.y + tP1.y

二阶贝赛尔曲线由3个点确定,它可以理解成是这样的一阶贝赛尔曲线:确定该一阶贝赛尔曲线的两个点是变化的。

这两个点(设分别为Pm,Pn)是怎样变化的呢,这两个点又分别是(P0,P1)确定的一阶贝赛尔曲线和(P1,P2)确定的一阶贝赛尔

曲线上的点。

于是有了2阶贝赛尔曲线的公式

Pm(t) = (1-t)P0 + tP1

Pn(t) = (1-t)P1 + tP2

B(t) = (1-t)Pm(t) + tPn(t) = (1-t)^2 P0 + 2(1-t)tP1+ t^2P2

以此类推可以得到3阶贝赛尔曲线,是不是很简单?



引文2

URL:http://www.cnblogs.com/jay-dong/archive/2012/09/26/2704188.html

Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线。曲线定义:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名,称为贝塞尔曲线。

以下公式中:B(t)为t时间下点的坐标;

P0为起点,Pn为终点,Pi为控制点

一阶贝塞尔曲线(线段):

意义:由 P0 至 P1 的连续点, 描述的一条线段

二阶贝塞尔曲线(抛物线):

原理:由 P0 至 P1 的连续点 Q0,描述一条线段。
由 P1 至 P2 的连续点 Q1,描述一条线段。
由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。

经验:P1-P0为曲线在P0处的切线。

三阶贝塞尔曲线:

通用公式:

高阶贝塞尔曲线:

4阶曲线:

5阶曲线:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html

Following the construction of a Bézier curve, the next important task is to find the pointC(u) on the curve for a particularu. A simple way is to pluguinto every basis function, compute the product of each basis function and its corresponding control point, and finally add them together. While this works fine, it is not numerically stable (i.e., could introduce numerical errors during the course of evaluating the Bernstein polynomials).

In what follows, we shall only write down the control point numbers. That is, the control points are00forP0,01forP1, ...,0iforPi, ...,0nforPn. The0s in these numbers indicate the initial or the 0-thiteration. Later on, it will be replaced with1,2,3and so on.

The fundamental concept of de Casteljau's algorithm is to choose a pointCin line segmentABsuch thatCdivides the line segmentABin a ratio ofu:1-u(i.e., the ratio of the distance betweenAandCand the distance betweenAandBisu). Let us find a way to determine the pointC.

The vector fromAtoBisB - A. Sinceuis a ratio in the range of 0 and 1, pointCis located atu(B - A). Taking the position ofAinto consideration, pointCisA+u(B - A) = (1 -u)A+uB. Therefore, given au, (1 -u)A+uBis the pointCbetweenAandBthat dividesABin a ratio ofu:1-u.

The idea of de Casteljau's algorithm goes as follows. Suppose we want to findC(u), whereuis in [0,1]. Starting with the first polyline,00-01-02-03...-0n, use the above formula to find a point1ion the leg (i.e.line segment) from0ito0(i+1)that divides the line segment0iand0(i+1)in a ratio ofu:1-u. In this way, we will obtainnpoints10,11,12, ....,1(n-1). They define a new polyline ofn- 1 legs.

In the figure above,uis 0.4.10is in the leg of00and01,11is in the leg of01and02, ..., and14is in the leg of04and05. All of these new points are in blue.

The new points are numbered as1i's. Apply the procedure to this new polyline and we shall get a second polyline ofn- 1 points20,21, ...,2(n-2)andn- 2 legs. Starting with this polyline, we can construct a third one ofn- 2 points30,31, ...,3(n-3)andn- 3 legs. Repeating this processntimes yields a single pointn0. De Casteljau proved that this is the pointC(u) on the curve that corresponds tou.

Let us continue with the above figure. Let20be the point in the leg of10and11that divides the line segment10and11in a ratio ofu:1-u. Similarly, choose21on the leg of11and12,22on the leg of12and13, and23on the leg of13and14. This gives a third polyline defined by20,21,22and23. This third polyline has 4 points and 3 legs. Keep doing this and we shall obtain a new polyline of three points30,31and32. From this fourth polyline, we have the fifth one of two points40and41. Do it once more, and we have50, the pointC(0.4) on the curve.

This is the geometric interpretation of de Casteljau's algorithm, one of the most elegant result in curve design.

Actual Computation

Given the above geometric interpretation of de Casteljau's algorithm, we shall present a computation method, which is shown in the following figure.

First, all given control points are arranged into a column, which is the left-most one in the figure. For each pair of adjacent control points, draw a south-east bound arrow and a north-east bound arrow, and write down a new point at the intersection of the two adjacent arrows. For example, if the two adjacent points areijandi(j+1), the new point is(i+1)j. The south-east (resp., north-east) bound arrow means multiplying 1 -u(resp.,u) to the point at its tail,ij(resp.,i(j+1)), and the new point is the sum.

Thus, from the initial column, column0, we compute column1; from column1we obtain column2and so on. Eventually, afternapplications we shall arrive at a single pointn0and this is the point on the curve. The following algorithm summarizes what we have discussed. It takes an arrayPofn+1 points and auin the range of 0 and 1, and returns a point on the Bézier curveC(u).

QiPi
Input:arrayP[0:n] ofn+1 points and real numberuin [0,1]
Output:point on curve,C(u)
Working:point arrayQ[0:n]

fori:= 0tondo
fork:= 1tondo
returnQ[0];

[

] := (1 -

)

[

] +

+ 1];

[

]; // save input

QiuQiuQifori:= 0ton - kdo

[

] :=

[

A Recurrence Relation

The above computation can be expressed recursively. Initially, letP0,jbePjforj= 0, 1, ...,n. That is,P0,jis thej-th entry on column 0. The computation of entryjon columniis the following:

More precisely, entryPi,jis the sum of (1-u)Pi-1,j(upper-left corner) anduPi-1,j+1(lower-left corner). The final result (i.e., the point on the curve) isPn,0. Based on this idea, one may immediately come up with the following recursive procedure:

functiondeCasteljau(i,j)
begin
end

(1-

)*

(

-1,

) +

*

(

returnP0,j
returnudeCasteljauijudeCasteljauijifi= 0then
else

+1)

-1,

This procedure looks simple and short; however, it is extremely inefficient. Here is why. We start with a call todeCasteljau(n,0) for computingPn,0. Theelsepart splits this call into two more calls,deCasteljau(n-1,0) for computingPn-1,0anddeCasteljau(n-1,1) for computingPn-1,1.

Consider the call todeCasteljau(n-1,0). It splits into two more calls,deCasteljau(n-2,0) for computingPn-2,0anddeCasteljau(n-2,1) for computingPn-2,1. The call todeCasteljau(n-1,1) splits into two calls,deCasteljau(n-2,1) for computingPn-2,1anddeCasteljau(n-2,2) for computingPn-2,2. Thus,deCasteljau(n-2,1) is called twice. If we keep expanding these function calls, we should discover that almost all function calls for computingPi,jare repeated, not once but many times. How bad is this? In fact, the above computation scheme is identical to the following way of computing then-th Fibonacci number:

functionFibonacci(n)
beginend

1

(

-1) +

return
returnFibonaccinFibonaccinifn= 0orn= 1then
else

-2)

(

This program takes an exponential number of function calls (an exercise) to computeFibonacci(n). Therefore, the above recursive version of de Casteljau's algorithm isnotsuitable for direct implementation, although it looks simple and elegant!

An Interesting Observation

The triangular computation scheme of de Casteljau's algorithm offers an interesting observation. Take a look at the following computation on a Bézier curve of degree 7 defined by 8 control points00,01, ...,07. Let us consider a set of consecutive points on the same column as the control points of a Bézier curve. Then, given auin [0,1], how do we compute the corresponding point on this Bézier curve? If de Casteljau's algorithm is applied to these control points, the point on the curve is the opposite vertex of the equilateral's base formed by the selected points!

For example, if the selected points are02,03,04and05, the point on the curve defined by these four control points that corresponds touis32. See the blue triangle. If the selected points are11,12and13, the point on the curve is31. See the yellow triangle. If the selected points are30,31,32,33and34, the point on the curve is70.

By the same reason,70is the point on the Bézier curve defined by control points60and61. It is also the point on the curve defined by50,51and52, and on the curve defined by40,41,42and43. In general, if we select a point and draw an equilateral as shown above, the base of this equilateral consists of the control points from which the selected point is computed.


可能性应用分析

  好了,有了前面的足够多的理论指导,我们在cococs2d-x开发中如何使用呢?思路有多种,方法也有多种。我当前的应用需求是,要绘制一条从A点到B点的一条粒子流路径。其中这两个点是UI编辑器确定的屏幕上的固定点,而且绘制路径不要是直线式,否则太板了--难看!当然,要求也不是非常高,过此两点大致画一曲线即可。于是,我可以在此两点确定的直接的某一侧适当估计一个点,然后通过这三个点画一个二阶Bezier曲线,这个应该是好办的。这样大致的曲线正是我实现粒子系统的流动路径所需要的!


  先分析一下我使用上述大致指导思路实现的一只蝴蝶沿着一个封闭曲线飞动的动画相应代码:

ccBezierConfigbezier1,bezier2;bezier1.controlPoint_1=ccp(0,0);bezier1.controlPoint_2=ccp(-VisibleRect::right().x*2/3,VisibleRect::top().y*2/3);bezier1.endPosition=ccp(-VisibleRect::right().x*2/3-130,236);CCActionInterval*bezierForward1=CCBezierBy::create(10,bezier1);//belowroutinebezier2.controlPoint_1=ccp(0,0);bezier2.controlPoint_2=ccp(-130,-236);bezier2.endPosition=ccp(VisibleRect::right().x*2/3+130,-236);CCActionInterval*bezierForward2=CCBezierBy::create(10,bezier2);CCActionInterval*seq=CCSequence::create(bezierForward1,bezierForward2,NULL);CCRepeatForever*repeat_01=CCRepeatForever::create(seq);arm_butterfly_01->runAction(repeat_01);

  上述代码思路是:把两个BEZIER曲线连接起来,形成一个封闭曲线,从而形成动画路径。使用这种思路,你可以实现几乎任意曲线方案。对于粒子流动路径的应用自然也十分类似。


补充:

  当起点与终点是一条水平线或者竖线时,确定线外的那个控制点相当EASY。若是AB点的连接线是一个倾斜直线时大致不估略微麻烦些。我有时使用UI编辑器中旋转的一个1X1像素点作为PLACEHOLDER,然后为后台代码所取出使用。当然,直接在后台代码中分析确定这样的点也OK。