前言
貝塞爾曲線是一個強大而又神秘的東西锥惋。今天有時間徹底梳理了一下淆两,神秘的面紗被揭下來了,剩下了只有強大膀跌。下面就一步一步來了解一下貝塞爾曲線奠涌。
貝塞爾曲線是什么
貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟(jì)埃曲線降狠,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線对竣。一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段與節(jié)點組成榜配,節(jié)點是可拖動的支點否纬,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種矢量曲線的蛋褥。貝塞爾曲線是計算機(jī)圖形學(xué)中相當(dāng)重要的參數(shù)曲線临燃,在一些比較成熟的位圖軟件中也有貝塞爾曲線工具,如PhotoShop等烙心。在Flash4中還沒有完整的曲線工具膜廊,而在Flash5里面已經(jīng)提供出貝塞爾曲線工具。
上面是網(wǎng)上找的定義淫茵,算了還是看圖體會吧爪瓜。
看了這圖后對貝塞爾曲線差不多就有點數(shù)了。
Android中實現(xiàn)貝塞爾曲線的API
了解自定義View的小伙伴匙瘪,肯定知道 canvas.drawPath()铆铆,這個方法。該方法接受的第一個對象是Path丹喻,這個Path薄货,提供了兩個方法:quadTo()、cubicTo()驻啤,分別實現(xiàn)二階貝塞爾曲線菲驴、三階貝塞爾曲線。接下來我們就寫代碼來看看效果骑冗。
quadTo()的使用
代碼:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path path = new Path();
path.moveTo(50, 200);
path.quadTo(150, 50, 400, 200);
canvas.drawPath(path, paint);
}
效果:
標(biāo)注有點簡陋赊瞬,聰明的你先煎,應(yīng)該看得懂的哈。
cubicTo()的使用
代碼:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path path = new Path();
path.moveTo(50, 200);
path.cubicTo(100, 50, 350, 50, 500, 200);
canvas.drawPath(path, paint);
}
效果:
以上就是用Android API實現(xiàn)二階貝塞爾曲線和三階貝塞爾取消巧涧,是不是很簡單呢薯蝎。
作為一名有夢想的程序員,你一定不會滿足的谤绳。接下來就研究一下貝塞爾曲線的原理占锯。
貝塞爾曲線公式。
1.貝塞爾曲線的通用公式
在網(wǎng)上查資料得到這個公式缩筛,這個公式是貝塞爾曲線的通用公式消略,通過這個公式可以得到一階、二階瞎抛、三階艺演。。桐臊。胎撤。N階貝塞爾曲線。
第一眼看到這個公式断凶,說實話我是一臉懵逼伤提,心想這好像是微積分吧,當(dāng)年的高數(shù)都是睡過來的认烁。于是求助了在上研究生的同學(xué)肿男。
于是得到了下面的圖片:
好吧,還是有點懵逼砚著,主要是字太丑次伶。
不管推導(dǎo)過程了,直接把結(jié)果拿來用吧稽穆。
一階貝塞爾公式
給定p0冠王、p1兩個點。得到如下公式
二階貝塞爾公式
二階貝塞爾曲線可以理解為兩個一階貝塞爾曲線的連線上舌镶,動態(tài)的劃出一階貝塞爾曲線柱彻。
三階貝塞爾曲線
按照二階的推導(dǎo)原理,以此類推餐胀,由四個控制點定義的三階貝塞爾曲線P03可被定義為分別由(P0哟楷,P1,P2)和(P1否灾,P2卖擅,P3)確定的兩條二階貝塞爾曲線的線性組合:P03 = (1-t)P02 + tP12
可遞歸代入得出三階貝塞爾曲線公式:
貝塞爾曲線原理部分借鑒于:http://mp.weixin.qq.com/s/l0ABkX3IzBk_s8-nWkUJig
在此對大神表示感謝。
計算貝塞爾曲線的路徑
通過上面的學(xué)習(xí),我們可以很輕松的畫出二階惩阶、三階貝塞爾曲線挎狸。那么,我們想畫出高階的貝塞爾曲線呢断楷?我們只是需要貝塞爾曲線的路徑而不只是畫出細(xì)線呢?
那么我們就需要得到貝塞爾曲線的繪制過程锨匆,也就是說要得到貝塞爾曲線上的每一個點。
這里不多將直接上代碼來冬筒,看效果好了恐锣。
核心代碼,計算貝塞爾曲線上的點集:
借鑒于https://github.com/venshine/BezierMaker
這是真大神舞痰,給跪了土榴。
/**
* 創(chuàng)建Bezier點集
*
* @return
*/
private ArrayList<PointF> buildBezierPoints() {
ArrayList<PointF> points = new ArrayList<>();
int order = mControlPoints.size() - 1;
float delta = 1.0f / FRAME;
for (float t = 0; t <= 1; t += delta) {
// Bezier點集
points.add(new PointF(deCasteljauX(order, 0, t), deCasteljauY(order, 0, t)));
}
return points;
}
/**
* deCasteljau算法
*
* @param i 階數(shù)
* @param j 點
* @param t 時間
* @return
*/
private float deCasteljauX(int i, int j, float t) {
if (i == 1) {
return (1 - t) * mControlPoints.get(j).x + t * mControlPoints.get(j + 1).x;
}
return (1 - t) * deCasteljauX(i - 1, j, t) + t * deCasteljauX(i - 1, j + 1, t);
}
/**
* deCasteljau算法
*
* @param i 階數(shù)
* @param j 點
* @param t 時間
* @return
*/
private float deCasteljauY(int i, int j, float t) {
if (i == 1) {
return (1 - t) * mControlPoints.get(j).y + t * mControlPoints.get(j + 1).y;
}
return (1 - t) * deCasteljauY(i - 1, j, t) + t * deCasteljauY(i - 1, j + 1, t);
}
初始化控制點:
void init() {
mControlPoints = new ArrayList<>(MAX_COUNT + 1);
int w = getResources().getDisplayMetrics().widthPixels;
mControlPoints.add(new PointF(144, 144));
mControlPoints.add(new PointF(266, 51));
mControlPoints.add(new PointF(500, 83));
mControlPoints.add(new PointF(650, 212));
mControlPoints.add(new PointF(689, 491));
mControlPoints.add(new PointF(485, 747));
mControlPoints.add(new PointF(185, 577));
mControlPoints.add(new PointF(45, 180));
mControlPoints.add(new PointF(48, 747));
mControlPoints.add(new PointF(689, 747));
//在這里初始化控制點的集合,可以任意添加控制點响牛,從而得到N階貝塞爾曲線鞭衩。
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(getResources().getColor(R.color.colorAccent));
}
在onDraw方法中調(diào)用:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path path = new Path();
ArrayList<PointF> list = buildBezierPoints();
for (int i = 1; i < list.size(); i++) {
path.moveTo(list.get(i - 1).x, list.get(i - 1).y);
path.lineTo(list.get(i).x, list.get(i).y);
canvas.drawPath(path, paint);
}
}
好了看下效果,由于控制點是隨便添加的娃善,所以就是這樣的鬼樣子:
看到這里大家覺得沒什么了不起的。大家可以發(fā)揮想象力瑞佩。
1.坐標(biāo)規(guī)劃的夠好聚磺,就可以畫出各種各樣的圖案,畫個汽車不成問題炬丸。
2.得到貝塞爾曲線的點集后瘫寝,我們不一次性畫出來,而是延時的畫稠炬,那么就可以讓線條動起來焕阿,那么就是動畫了
3.得到貝塞爾曲線后,我們不劃線首启,而是在這個路徑上畫圖案暮屡,那么就可以實現(xiàn),圖案在這路徑上飄動毅桃。就想直播里面點贊出現(xiàn)的動畫一樣褒纲。