1. 程式人生 > >【轉】貝塞爾曲線介紹

【轉】貝塞爾曲線介紹

con 系列 ani 線段 課本 start http wpa --

原文鏈接:

http://blog.csdn.net/sangxiaonian/article/details/51984013

http://blog.csdn.net/sangxiaonian/article/details/51984584

http://blog.csdn.net/sangxiaonian/article/details/51985405

其他參考鏈接:

https://www.jianshu.com/p/55c721887568

作為一個有只誌向的碼農,除了知道一些基本的知識夠自己努力搬磚以外,還應該get一些更炫酷的技能,用更優雅的姿勢進行搬磚;想要實現一些十分炫酷的效果,貝塞爾曲線就必須進行一些研究了;
最近一段時間,我對貝塞爾曲線進行了部分的研究,因此就打算寫貝塞爾曲線系列的文章來記錄自己的研究;

規矩我都懂 !

??我明白,必須先上圖,要不然大家都沒興趣看下去

先看比較簡單的,貝塞爾曲線的一階和二階的應用

技術分享圖片

??看到二階的貝塞爾曲線有沒有感覺很眼熟,沒錯,360的下火箭彈射時候的小彈弓,還有滑動控件的陰影提示;以前的時候很多小夥伴跟我說這要計算多少數據啊,完全沒辦法實現啊,現在有了貝塞爾曲線,可以很簡單的實現這一個功能;
??不過完全不能這樣滿足啊,接下來還有更復雜一些的曲線

技術分享圖片

??沒錯,這個就是三階的使用,有沒有感覺路線更加復雜,不過還好,使用貝塞爾去玩完全可以輕松實現;對了,還有一個心在沿著曲線移動,看到這裏,小夥伴們肯定會想到滿屏幕的心在飛的場景,放心,這個我也實現了,在接下來的文章裏,我會一一進行講解;

技術分享圖片

圖片看完了,現在簡單了解貝塞爾曲線

Bézier curve(貝塞爾曲線)是應用於二維圖形應用程序的數學曲線。 曲線定義:起始點、終止點(也稱錨點)、控制點。通過調整控制點,貝塞爾曲線的形狀會發生變化。 1962年,法國數學家Pierre Bézier第一個研究了這種矢量繪制曲線的方法,並給出了詳細的計算公式,因此按照這樣的公式繪制出來的曲線就用他的姓氏來命名,稱為貝塞爾曲線。

以下公式中:B(t)為t時間下 點的坐標;

P0為起點,Pn為終點,Pi為控制點

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

技術分享圖片

意義:由 P0 至 P1 的連續點, 描述的一條線段

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

技術分享圖片

原理:由 P0 至 P1 的連續點 Q0,描述一條線段。
由 P1 至 P2 的連續點 Q1,描述一條線段。
由 Q0 至 Q1 的連續點 B(t),描述一條二次貝塞爾曲線。

經驗:P1-P0為曲線在P0處的切線。

三階貝塞爾曲線:

技術分享圖片

通用公式:

技術分享圖片

利用貝塞爾曲線的這些特性,我們可以畫出很多炫酷的曲線,所以貝塞爾曲線還是值得我們去研究學習的;

但是這些完全記不住啊!!!

沒關系,可以很負責的說,我也是!!!!!

上面的曲線完全是來自http://blog.csdn.net/tianhai110/article/details/2203572

所以,如果你的數學和我一樣是體育老師教的,就忘記這些吧,跟我一起看看android中是實現一條貝塞爾曲線的,android已經幫我們實現好了,剩下的就需要我們進行簡單使用,具體的使用,就看下一篇中講解

最後附上源碼:https://github.com/sangxiaonian/BezierIntroduce.git

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

上一篇中我簡單的介(粘)紹(貼)了一下貝塞爾曲線(Bezier)曲線的原理和公式,但是作為數學界排的上名號的渣渣,我只能默默的溜過;
?? 不過還好,android幫我們實現好了這個貝塞爾曲線的使用;

Path

??這個類中封裝了要使用貝塞爾曲線(Bezier)的簡單方法;使用起來也很簡單,總的來說也只有三步

  • 初始化Path
 mPath = new Path();

  

  • path移動到起點
  mPath.moveTo(startX, startY / 3);

  

  • 確定直線的終點
 mPath.lineTo(endX, endY / 3);
  • 調用canvas繪制貝塞爾曲線
 canvas.drawPath(mPath, mPaint);

  

??好了,到這裏一階的一條直線就完成了;
??但是這個完全沒任何卵用啊,就一條直線有木有!!

??但是,我們可以一直畫下去,就像這樣:

      path.moveTo(touchX + getWidth() / 20, touchY - getHeight() / 10);
        path.lineTo(touchX + getWidth() / 20, touchY);
        path.lineTo(touchX - getWidth() / 20, touchY);
        path.lineTo(touchX - getWidth() / 20, touchY - getHeight() / 10);
        path.lineTo(touchX, touchY - getHeight() / 7);
        path.lineTo(touchX + getWidth() / 20, touchY - getHeight() / 10 + 2);

  這段代碼繪制完成之後就是一個隨著手指一動的小火箭了

技術分享圖片
??醜爆了有木有,不過還好,如果是大神的話應該可以繪制成一個比較好一些的了吧,主要還是原理,相對於自己直接畫直線,已經大大簡化了;

二階曲線

??二階曲線在安卓中的定義也是很簡單的,就是調用quadTo方法,

        mPath.moveTo(startX, startY);
        mPath.quadTo(touchX, touchY, endX, endY);
        canvas.drawPath(mPath, mPaint);

  

技術分享圖片
 

不管是幾階的,都是要先moveTo到起點;

三階曲線 ##

技術分享圖片

         mPath.moveTo(pointFStart.x, pointFStart.y);
        mPath.cubicTo(pointFFirst.x, pointFFirst.y, pointFSecond.x, pointFSecond.y, pointFEnd.x, pointFEnd.y);
        canvas.drawPath(mPath, mPaint);

  途中從下倒上,四個點依次是pointFStart,pointFFirst,pointFSecond,pointFSecond;根本沒什麽難度,非常簡單,可以直接使用,上篇提到的”心”的移動就是按照這個軌跡進行移動,所以看起來十分順滑,效果也不錯;

貝塞爾曲線的繪制本身並沒有什麽難度,這些都是很基礎的一些東西,但是卻能實現一些很炫酷的效果,比如qq上的粘性控件的效果等,這些都可以實現;

好了,簡單的使用就介紹到這裏了,下一篇我會利用貝塞爾曲線實現一些炫酷的效果

最後附上源碼:https://github.com/sangxiaonian/BezierIntroduce.git

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

這一篇文章會完整的介紹如何通過貝塞爾曲線實現愛心點贊的效果,如果實在看不懂,可以看第一篇貝塞爾曲線的簡介,還有第二篇安卓中的簡單使用;

好了,終於到了放大招的時候了,真實憋了很久了
技術分享圖片
先做一些準備工作,繪制各種顏色的紅心:

  private Bitmap creatHeart(int color) {

   int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        canvas.drawBitmap(bitmap, 0, 0, criPaint);
        canvas.drawColor(color, PorterDuff.Mode.SRC_ATOP);
        canvas.setBitmap(null);
        return newBitmap;
}

  

這裏面比較關鍵的代碼只有是 canvas.drawColor(color, PorterDuff.Mode.SRC_ATOP),關於PorterDuff,還是可以去學習了解一下的,很多時候還是很有用的,在這裏簡單的介紹一下;
技術分享圖片

這樣就比較清晰明了了吧,這裏使用的就是SRC_ATOP,去心的圖形和顏色重疊部分,就是心了;
這樣只要準備一個心形圖片,就能實現格式各樣的心了;

接下來就是進行根據軌跡進行繪制了,看過第一篇文章的,就應該根據幾個點,就能繪制出來一條軌跡;這裏使用屬性動畫,來獲取相對應的軌跡;

首先

 /**
     * 繪制一個增值器
     */
    class TypeE implements TypeEvaluator<PointF> {

        private PointF pointFFirst,pointFSecond;

        public TypeE(PointF start,PointF end){
            this.pointFFirst =start;
            this.pointFSecond = end;
        }

        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            PointF result = new PointF();
            float left = 1 - fraction;
            result.x = (float) (startValue.x*Math.pow(left,3)+3*pointFFirst.x*Math.pow(left,2)*fraction+3*pointFSecond.x*Math.pow(fraction, 2)*left+endValue.x*Math.pow(fraction,3));
            result.y= (float) (startValue.y*Math.pow(left,3)+3*pointFFirst.y*Math.pow(left,2)*fraction+3*pointFSecond.y*Math.pow(fraction, 2)*left+endValue.y*Math.pow(fraction,3));
            return result;
        }
    }

  

 

這個很簡單,就是單純的使用公式了,所以說想要繪制復雜的軌跡,我還是要重新拾起來被扔進糞坑的小學數學課本重新看看,當真是熏得淚流滿面啊!!
接下來就很簡單了,只要不停使用屬性動畫,不斷變換位置就好了;

private void moveHeart(final ImageView view){
        PointF pointFFirst = this.pointFFirst;
        PointF pointFSecond = this.pointFSecond;
        PointF pointFStart = this.pointFStart;
        PointF pointFEnd = this.pointFEnd;


        ValueAnimator animator = ValueAnimator.ofObject(new TypeE(pointFFirst, pointFSecond), pointFStart, pointFEnd);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF value = (PointF) animation.getAnimatedValue();
                view.setX(value.x);
                view.setY(value.y);
            }
        });

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                AdvancePathView.this.removeView(view);
            }
        });

        ObjectAnimator af = ObjectAnimator.ofFloat(view, "alpha", 1f, 0);
        af.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                AdvancePathView.this.removeView(view);
            }
        });

       AnimatorSet set = new AnimatorSet();
        set.setDuration(3000);
        set.play(animator).with(af);
        set.start();

    }

  

就是這麽簡單,完全沒有難度啊有木有!!!
總的來說還是三步:
第一

  1. :繪制各種顏色的心
  2. 繪制一個增值器,獲取軌跡
  3. 使用屬性動畫,根據軌跡移動位置

好了,到這裏我這一系列的文章就結束了,兩天水時間搞的,感覺稍微有點水,但是就這樣啦,畢竟本身不是很難的東西,有什麽問題可以問我,有時間一定會耐心解答的;

最後附上源碼:https://github.com/sangxiaonian/BezierIntroduce.git

【轉】貝塞爾曲線介紹