Android-貝塞爾曲線的應用

什麼是貝塞爾曲線

貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用於二維圖形應用程序的數學曲線。一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段節點組成,節點是可拖動的支點,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種矢量曲線的。主要結構:起始點、終止點(也稱錨點)、控制點。通過調整控制點,貝塞爾曲線的形狀會發生變化。

展示:一階貝塞爾曲線(線段)

1.gif

展示:二階貝塞爾曲線(拋物線)

2.gif

展示:三階貝塞爾曲線

3.gif

提供兩個網站幫助我們瞭解貝塞爾曲線:

http://www.html-js.com/article/1628
http://bezier.method.ac/#

Android提供的貝塞爾曲線代碼實現:


/**
 * Add a quadratic bezier from the last point, approaching control point
 * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
 * this contour, the first point is automatically set to (0,0).
 *
 * @param x1 The x-coordinate of the control point on a quadratic curve
 * @param y1 The y-coordinate of the control point on a quadratic curve
 * @param x2 The x-coordinate of the end point on a quadratic curve
 * @param y2 The y-coordinate of the end point on a quadratic curve
 */
public void quadTo(float x1, float y1, float x2, float y2) {
    isSimplePath = false;
    native_quadTo(mNativePath, x1, y1, x2, y2);
}
/**
 * Add a cubic bezier from the last point, approaching control points
 * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
 * made for this contour, the first point is automatically set to (0,0).
 *
 * @param x1 The x-coordinate of the 1st control point on a cubic curve
 * @param y1 The y-coordinate of the 1st control point on a cubic curve
 * @param x2 The x-coordinate of the 2nd control point on a cubic curve
 * @param y2 The y-coordinate of the 2nd control point on a cubic curve
 * @param x3 The x-coordinate of the end point on a cubic curve
 * @param y3 The y-coordinate of the end point on a cubic curve
 */
public void cubicTo(float x1, float y1, float x2, float y2,
                    float x3, float y3) {
    isSimplePath = false;
    native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
}

quadTo()方法從上一個點爲起點開始繪製貝塞爾曲線,其中(x1,y1)爲輔助控制點,(x2,y2)爲終點。

cubicTo()方法從上一個點爲起點開始繪製三階貝塞爾曲線,其中(x1,y1),( x2, y2 )爲輔助控制點,(x3,y3)爲終點。

舉個例子:

Path mPath = new Path();
mPath.moveTo(x0,y0);
mPath.quadTo(x1,y1,x2,y2);

如調用以上代碼,即繪製起點(x0,y0),終點(x2,y2),輔助控制點(x1,y1)的貝塞爾曲線。因此,通過不斷改變這三個點的位置,我們可以繪製出各種各樣的曲線。

貼一份二階貝塞爾曲線的測試代碼,幫助理解(將以下自定義View在佈局中引用即可看到效果):

基本思路:
  • 1.先準備一支畫筆。
  • 2.分別指定起點、終點、以及控制點的值。
  • 3.爲了幫助理解,繪製上面3個點以及輔助線的位置。
  • 4.繪製貝塞爾曲線。
  • 5.簡單重寫滑動事件,讓手指可以改變控制點的位置,使貝塞爾曲線進行重繪,讓我們可以看到改變後的貝塞爾曲線。
package chao.base.view.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 二階曲線
 */
public class Bezier extends View {

    private Paint mPaint;
    private int centerX, centerY;

    private PointF start, end, control;

    public Bezier(Context context, 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);


    }

    public Bezier(Context context) {
        this(context, null);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w / 2;
        centerY = h / 2;

        // 初始化數據點和控制點的位置
        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) {
        // 根據觸摸位置更新控制點,並提示重繪
        control.x = event.getX();
        control.y = event.getY();
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 繪製數據點和控制點
        mPaint.setColor(Color.GRAY);
        mPaint.setStrokeWidth(20);
        canvas.drawPoint(start.x, start.y, mPaint);
        canvas.drawPoint(end.x, end.y, mPaint);
        mPaint.setColor(Color.BLUE);
        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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章