1 简介
贝塞尔曲线就是这样的一条曲线,它是依据N个位置任意的点坐标绘制出的一条光滑曲线。那么,我们可以直观地认为,为了得到一条贝塞尔曲线,我们只要输入起点、终点及控制点既可。变化参数t都是位于[0,1]。看到这里还不理解,没关系,文章会介绍怎么使用。
如下图输入4个点[P0, P1, P2, P3],可以获得一条光滑的三阶贝塞尔曲线,通常我们叫P0为起点,P3为终点,P1和P2为控制点。
强烈推荐在线工具https://cubic-bezier.com,这个工具的使用方法会在文章里介绍。
另外一个在线工具http://wx.karlew.com/canvas/bezier/
2 贝塞尔曲线公式
引用百度百科的贝塞尔曲线公式先介绍一下公式
线性公式
给定点P0、P1,线性贝塞尔曲线只是一条两点之间的直线。这条线由下式给出:
且其等同于线性插值。
二次方公式
二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
三次方公式
P0、P1、P2、P3四个点在平面或在三维空间中定义了三阶贝塞尔曲线。
一般参数公式
阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:
如上公式可如下递归表达: 用表示由点P0、P1、…、Pn所决定的贝兹曲线。
用平常话来说,阶的贝兹曲线,即双阶贝兹曲线之间的插值。
3 使用公式(以三阶贝塞尔曲线为例)
对于上图,实际是使用使用了贝塞尔三次方公式,输入的控制点为[P0(97,279), P1(280, 305), P2(233,125), P3(442,219)], t由0–>1均匀变化得到的点B(t), 由B(t)画出的曲线。可以认为在0到1归一化的时间内,在t时刻,B(t)对应的点(x, y)由以下公式计算得到:
代入4个点的x值
总结下,要使用贝塞尔曲线,首先确定使用的N阶的贝塞尔曲线(即确定要套用的公式,公式是固定的),再输入对应的N+1个点(包含终点,起点,N-2个控制点),就可以通过t由0–>1递增输入,如[0, 0.01, 0.02, … ,0.99, 1],然后通过t的递增变化计算得到对应的点(x, y)即B(t) 。下面使用Android三阶Bezier曲线API(红色粗线)和上面的公式(蓝色细线)来画图比较,及黑色的4个点。
可以看到画出图形,与上图一样,并且Android三阶Bezier曲线API与我们用公式直接算是一样。
@Override
protected void dispatchDraw(Canvas canvas) {
Point P0,P1,P2,P3;
P0 = new Point(97, 279);
P1 = new Point(280,305);
P2 = new Point(233,125);
P3 = new Point(442,219);
mPath.moveTo(P0.x,P0.y);
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(10);
//Android 三阶Bezier曲线API
mPath.cubicTo(P1.x,P1.y,P2.x,P2.y,P3.x,P3.y);
canvas.drawPath(mPath,mPaint);
//套公式算的
mPaint.setColor(Color.BLUE);
mPaint.setStrokeWidth(2);
float t;
mPath.moveTo(P0.x,P0.y);
for(int i= 0;i<1000;i++){
t = i*0.001f;
int x = (int)cubicCurves(t,P0.x,P1.x,P2.x,P3.x);
int y = (int)cubicCurves(t,P0.y,P1.y,P2.y,P3.y);
mPath.lineTo(x,y);
}
canvas.drawPath(mPath,mPaint);
//画出P0, P1, P2, P3点
mPaint.setColor(Color.BLACK);
canvas.drawPoint(P0.x,P0.y,mPaint);
canvas.drawPoint(P1.x,P1.y,mPaint);
canvas.drawPoint(P2.x,P2.y,mPaint);
canvas.drawPoint(P3.x,P3.y,mPaint);
}
/**
* 求三次贝塞尔曲线(四个控制点)一个点某个维度的值.<br>
* 套用公式即可
* x = x0*((1-t)^3)+3*x1*t*((1-t)^2)+3*x2*(t^2)*(1-t)+x3*(t^3)
* y = y0*((1-t)^3)+3*y1*t*((1-t)^2)+3*y2*(t^2)*(1-t)+y3*(t^3)
* @return d
*/
public static double cubicCurves(double t, double p0v, double p1v, double p2v, double p3v) {
return p0v*Math.pow(1-t,3)+3*p1v*t*Math.pow(1-t,2)+3*p2v*Math.pow(t,2)*(1-t)+p3v*Math.pow(t,3);
}
4 总结
使用贝塞尔曲线关键是确定控制点,然后用这些点套对应阶数的公式。N阶贝塞尔曲线,需要N+1个点。