二次貝塞爾曲線
貝塞爾曲線簡介
貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用于二維圖形應用程序的數(shù)學曲線。一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段與節(jié)點組成,節(jié)點是可拖動的支點,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種矢量曲線的。貝塞爾曲線是計算機圖形學中相當重要的參數(shù)曲線,在一些比較成熟的位圖軟件中也有貝塞爾曲線工具,如PhotoShop等。在Flash4中還沒有完整的曲線工具,而在Flash5里面已經(jīng)提供出貝塞爾曲線工具。
貝塞爾曲線于1962,由法國工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發(fā)表,他運用貝塞爾曲線來為汽車的主體進行設計。貝塞爾曲線最初由Paul de Casteljau于1959年運用de Casteljau演算法開發(fā),以穩(wěn)定數(shù)值的方法求出貝茲曲線。
以上內容從采取自百度百科
貝塞爾曲線目前被廣泛應用于計算機制圖中,可以說貝塞爾曲線奠定了計算機制圖的基礎。
Android中繪制Path的API
Android中繪制Path常用方法:
| 作用 | 相關方法 | 備注 |
|---|---|---|
| 移動起點 | moveTo | 移動下一次操作的起點位置 |
| 設置終點 | setLastPoint | 重置當前path中最后一個點位置,如果在繪制之前調用,效果和moveTo相同 |
| 連接直線 | lineTo | 添加上一個點到當前點之間的直線到Path |
| 閉合路徑 | close | 連接第一個點連接到最后一個點,形成一個閉合區(qū)域 |
| 添加內容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圓角矩形, 橢圓, 圓, 路徑, 圓弧) 到當前Path (注意addArc和arcTo的區(qū)別) |
| 是否為空 | isEmpty | 判斷Path是否為空 |
| 是否為矩形 | isRect | 判斷path是否是一個矩形 |
| 替換路徑 | set | 用新的路徑替換到當前路徑所有內容 |
| 偏移路徑 | offset | 對當前路徑之前的操作進行偏移(不會影響之后的操作) |
| 貝塞爾曲線 | quadTo, cubicTo | 分別為二次和三次貝塞爾曲線的方法 |
| rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | 不帶r的方法是基于原點的坐標系(偏移量), rXxx方法是基于當前點坐標系(偏移量) |
| 填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 設置,獲取,判斷和切換填充模式 |
| 提示方法 | incReserve | 提示Path還有多少個點等待加入(這個方法貌似會讓Path優(yōu)化存儲結構) |
| 布爾操作(API19) | op | 對兩個Path進行布爾運算(即取交集、并集等操作) |
| 計算邊界 | computeBounds | 計算Path的邊界 |
| 重置路徑 | reset, rewind | 清除Path中的內容 |
reset不保留內部數(shù)據(jù)結構,但會保留FillType.
rewind會保留內部的數(shù)據(jù)結構,但不保留FillType |
| 矩陣操作 | transform | 矩陣變換 |
貝塞爾曲線應用簡單場景:
- QQ小紅點拖拽效果
- 平滑的折線圖的制作
- 閱讀軟件的翻書效果
繪制貝塞爾曲線
一階貝塞爾曲線
一階貝塞爾曲線的原理就是一條直線,其實就是直接畫了一個Path出來,在這里不做過多的介紹,本文主要介紹的是二階的貝塞爾曲線。
二階貝塞爾曲線
二階貝塞爾曲線效果圖:

實現(xiàn)原理
二階曲線由兩個數(shù)據(jù)點(A 和 C),一個控制點(B)來描述曲線狀態(tài),大致如下:

上圖中紅色曲線部分就是傳說中的二階貝塞爾曲線,那么這條紅色曲線是如何生成的呢?接下來我們就以其中的一個狀態(tài)分析一下:

連接AB BC,并在AB上取點D,BC上取點E,使其滿足條件:


連接DE,取點F,使得:
AD/AB = BE/BC = DF/DE
這樣獲取到的點F就是貝塞爾曲線上的一個點,動態(tài)過程如下:

實現(xiàn)代碼
public class Bezier2 extends View {
private Paint mPaint;
private int centerX, centerY;
private PointF start, end, control;
public Bezier2(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(8);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTextSize(60);
start = new PointF(0,0);
end = new PointF(0,0);
control = new PointF(0,0);
}
public Bezier2(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(8);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTextSize(60);
start = new PointF(0,0);
end = new PointF(0,0);
control = new PointF(0,0);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX = w/2;
centerY = h/2;
// 初始化數(shù)據(jù)點和控制點的位置
start.x = centerX-200;
start.y = centerY;
end.x = centerX+200;
end.y = centerY;
control.x = centerX;
control.y = centerY-100;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 根據(jù)觸摸位置更新控制點,并提示重繪
control.x = event.getX();
control.y = event.getY();
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 繪制數(shù)據(jù)點和控制點
mPaint.setColor(Color.GRAY);
mPaint.setStrokeWidth(20);
canvas.drawPoint(start.x,start.y,mPaint);
canvas.drawPoint(end.x,end.y,mPaint);
canvas.drawPoint(control.x,control.y,mPaint);
// 繪制輔助線
mPaint.setStrokeWidth(4);
canvas.drawLine(start.x,start.y,control.x,control.y,mPaint);
canvas.drawLine(end.x,end.y,control.x,control.y,mPaint);
// 繪制貝塞爾曲線
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(8);
Path path = new Path();
path.moveTo(start.x,start.y);
path.quadTo(control.x,control.y,end.x,end.y);
canvas.drawPath(path, mPaint);
}
}