關於貝塞爾曲線的故事

概述

  • 在開始本故事的以前,先來介紹下故事的背景。話說幾百年前,從天而降一座神山,遠遠看去像一天光滑的絲帶,它的名字叫作:「貝塞爾曲線"。有大法師預言登上這座神山能夠發現天地大祕可是前途艱險。

定義

  • 摘自百度百科android

    貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用於二維圖形應用程序的數學曲線。通常的矢量圖形軟件經過它來精確畫出曲線,貝茲曲線由線段與節點組成,節點是可拖動的支點,線段像可伸縮的皮筋,咱們在繪圖工具上看到的鋼筆工具就是來作這種矢量曲線的。
    「貝賽爾曲線」是由法國數學家Pierre Bézier所發明,由此爲計算機矢量圖形學奠基了基礎。它的主要意義在於不管是直線或曲線都能在數學上予以描述。canvas

公式

  • 因爲應用用到主要以二階貝塞爾曲線爲主,貼下二階的公式:api

    二次方公式
    二次方貝茲曲線的路徑由給定點P0、P一、P2的函數B(t):
    ide

如何應用?

  • 爲了前往"貝塞爾曲線山",向那些從前登上神山的老前輩請教;

所需的Android知識

  • 畫筆(paint),路徑(path),畫布(canvas)類的api要熟悉函數

  • View繪製的生命週期工具

    簡單來看:測量-measure 擺放-layout 繪製-draw測試

  • Android觸摸事件code

    這裏須要瞭解onTouchEvent方法能夠捕捉到觸屏的事件blog

用手勢畫光滑的曲線

  • 路途艱險,在這裏我碰到了大白虎,史前巨獸猛獁象,海天鯤鵬,經歷了生死考驗終於登上神山,恍然大悟,天地大祕原來在此。生命週期

  • 讓咱們想想畫東西須要什麼?答案:一塊白板,一隻筆。
  • 這裏的關鍵是手勢與光滑,處理手勢的話就是前面講的重寫Android觸摸事件,聰明的你必定想到了經過二階貝塞爾曲線去作到光滑。
  • 畫一條二階貝塞爾曲線須要3個點,兩個數據點一個控制點,那麼手勢落下的點--起始點(x1,y1)與不斷移動的手的觸點是數據點,控制點須要本身創造,那線段的中點是最好計算的,假設第一個手滑動到的點(x2,y2),那麼中點就是((x1+x2)/2,(y1+y2)/2)。
  • 重寫Android觸摸事件須要捕捉MOVE類型與DOWN類型的事件,DOWN類型的事件中須要記錄起始點的位置,而MOVE類型事件須要緩衝上一次移動的位置。

  • 1.聲明控制點,曲線,起始點,以及斷定滑動的距離
private  Paint controlPaint;

    private Path mCurrentPath;

    private float startPointX;
    private float startPointY;
    //畫貝塞爾曲線的標識--能夠自定義值
    private float offset = ViewConfiguration.get(getContext()).getScaledTouchSlop();
  • 2.初始化畫筆與路徑
public PaintBeSaiErView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //創建路徑
        mCurrentPath = new Path();
        //繪製時抗鋸齒
        controlPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //設置畫筆樣式
        controlPaint.setStyle(Paint.Style.STROKE);
        //設置畫筆的粗細
        controlPaint.setStrokeWidth(8);
        //設置畫筆顏色
        controlPaint.setColor(Color.RED);

    }
  • 3.重寫onTouchEvent,記錄手勢起始點與移動位置並繪製貝塞爾曲線,經過invalidate方法更新UI視圖
@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                //爲了方便測試,每次下落以前清空路徑
                mCurrentPath.reset();
                float x = event.getX();
                float y = event.getY();
                startPointX = x;
                startPointY = y;
                //移動到起始點
                mCurrentPath.moveTo(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                float curX= event.getX();
                float curY= event.getY();
                float preX= startPointX;
                float preY= startPointY;
                if(Math.abs(preX-curX)>=offset||Math.abs(preX-curY)>=offset) {
                    mCurrentPath.quadTo((curX + preX) / 2, (curY + preY) / 2, curX, curY);
                    startPointX = curX;
                    startPointY = curY;
                }
                invalidate();
                break;
        }
        return  true;
    }
  • 4.下面對比使用線段畫lineTo(curX, curY)與貝塞爾曲線畫quadTo(avgX,avgY)的效果

    左圖爲線段畫的,右圖爲貝塞爾曲線畫的,看起來更圓潤!why?其實,用線段畫基本上看是一個折線圖,而貝塞爾函數畫是一段段曲線

  • 固然,貝塞爾曲線的應用十分普遍,上面是簡單的例子,後面將講如何應用模擬翻頁。

總結

  • 總覺得登上神山纔是最大的收穫,原來一路走來更有收穫。
  • 去了解一個事物的時候,要善於思考,記憶中愈來愈深入的,每每思考的越透徹。
相關文章
相關標籤/搜索