欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

android中貝塞爾曲線的應(yīng)用示例

 更新時(shí)間:2017年03月15日 10:51:18   作者:許方鎮(zhèn)  
本篇文章主要介紹了android中貝塞爾曲線的應(yīng)用示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

前言:

貝塞爾曲線又稱貝茲曲線,它的主要意義在于無(wú)論是直線或曲線都能在數(shù)學(xué)上予以描述。最初由保羅·德卡斯特里奧(Paul de Casteljau)于1959年運(yùn)用德卡斯特里奧演算法開(kāi)發(fā)(de Casteljau Algorithm),在1962,由法國(guó)工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發(fā)表。目前廣泛應(yīng)用于圖形繪制領(lǐng)域來(lái)模擬光滑曲線,為計(jì)算機(jī)矢量圖形學(xué)奠定了基礎(chǔ)。在一些圖形處理軟件中都能見(jiàn)到貝塞爾曲線,比如CorelDraw中翻譯成“貝賽爾工具”;而在Fireworks中叫“畫(huà)筆”;Photoshop中叫“鋼筆工具”。下圖為Photoshop中用鋼筆繪制的貝塞爾曲線,共繪制了三條貝塞爾曲線:


數(shù)學(xué)表達(dá)

術(shù)語(yǔ):數(shù)據(jù)點(diǎn)、控制線、控制點(diǎn)、德卡斯特里奧算法、一階,二階,三階,n階……

  1. 數(shù)據(jù)點(diǎn):一條貝塞爾曲線的起始點(diǎn)和終結(jié)點(diǎn)都叫數(shù)據(jù)點(diǎn)。
  2. 控制線:在圖中可以看到那條中心點(diǎn)為數(shù)據(jù)點(diǎn)的線段,每個(gè)數(shù)據(jù)點(diǎn)對(duì)應(yīng)一條控制線
  3. 控制點(diǎn):就是控制線的端點(diǎn),通過(guò)控制線隨著控制點(diǎn)的變化而變化;數(shù)據(jù)點(diǎn)和控制點(diǎn)決定一條貝塞爾曲線。
  4. 一階貝塞爾曲線:其實(shí)是一條直線段,沒(méi)有控制點(diǎn)。

一階貝塞爾曲線示意圖


一階貝塞爾曲線公式

二階貝塞爾曲線:圖中第二段為二階貝塞爾曲線,只有一個(gè)控制點(diǎn),即只有一個(gè)控制點(diǎn)和兩個(gè)數(shù)據(jù)點(diǎn)來(lái)決定曲線形狀。

二階貝塞爾曲線公式

二階公式推導(dǎo):


二階貝塞爾曲線t=0.6示意圖.gif
根據(jù)控制點(diǎn)和數(shù)據(jù)點(diǎn),對(duì)貝塞爾曲線進(jìn)行約束,滿足的條件為


問(wèn)題變?yōu)椋阂阎狿0(x0,y0), P1(x1,y1), P2(x2,y2),根據(jù)上式求P點(diǎn)坐標(biāo)?

先求出A、B點(diǎn)坐標(biāo),其坐標(biāo)

PA=P0+(P1-P0)·t

PB=P1+(P2-P1)·t

之后求P點(diǎn)坐標(biāo),其坐標(biāo)

P=PA+(PB-PA)·t

P=(1-t)2P0+2t(1-t)P1+t2P2, t∈[0,1]

三階貝塞爾曲線:圖中第三段為三階貝塞爾曲線,有兩個(gè)控制點(diǎn)和兩個(gè)數(shù)據(jù)點(diǎn)決定的曲線,同樣滿足等比條件:

三階貝塞爾曲線

三階貝塞爾曲線公式

德卡斯特里奧算法的思想:給定數(shù)據(jù)點(diǎn)和控制點(diǎn)P0、P1…Pn,首先將數(shù)據(jù)點(diǎn)和控制點(diǎn)連接形成一條折線,計(jì)算出每條折線上面的一點(diǎn),使得初始數(shù)據(jù)點(diǎn)(初始控制點(diǎn))到該點(diǎn)的距離與初始數(shù)據(jù)點(diǎn)(初始控制點(diǎn))到終止數(shù)據(jù)點(diǎn)(終止控制點(diǎn))的距離之比為t:1。將這些點(diǎn)連接起來(lái)形成新的折線(折線少了一段),用遞歸的算法繼續(xù)計(jì)算,指導(dǎo)只有兩個(gè)點(diǎn),在這兩個(gè)點(diǎn)形成的線段上去一點(diǎn),滿足以上的比例關(guān)系。隨著t的從0到1的變化,該點(diǎn)的集合形成了貝塞爾曲線。

n階貝塞爾曲線公式如下。


Android中的應(yīng)用

對(duì)android中如何獲取貝塞爾曲線上的點(diǎn),如何繪制貝塞爾曲線,以及結(jié)合貝塞爾曲線的知識(shí)做出的效果進(jìn)行分析。

1. 獲取貝塞爾曲線上點(diǎn)的坐標(biāo)

在android中并沒(méi)有直接獲取的方法,因此需要利用上面的公式進(jìn)行計(jì)算,以二階貝塞爾曲線為例,獲取51個(gè)點(diǎn),主要是t從0開(kāi)始到1間取51項(xiàng)的等差數(shù)列:

public class MainActivity extends AppCompatActivity {

  private static final float mPointNum = 50f;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    init();
  }

  private void init() {
    PointF mStartPoint = new PointF(0, 0);
    PointF mEndPoint = new PointF(0, 1200);
    PointF mControlPoint = new PointF(500, 600);

    List<PointF> mPointList = new ArrayList<>();
    for (int i = 0; i <= mPointNum; i++) {
      mPointList.add(getBezierPoint(mStartPoint, mEndPoint, mControlPoint, i / mPointNum));
      Log.d("Bezier", "X:" + mPointList.get(i).x + " Y:" + mPointList.get(i).y);
    }
  }

  private PointF getBezierPoint(PointF start, PointF end, PointF control, float t) {
    PointF bezierPoint = new PointF();
    bezierPoint.x = (1 - t) * (1 - t) * start.x + 2 * t * (1 - t) * control.x + t * t * end.x;
    bezierPoint.y = (1 - t) * (1 - t) * start.y + 2 * t * (1 - t) * control.y + t * t * end.y;
    return bezierPoint;
  }
}

如果需要更高階,可以使用遞歸函數(shù)來(lái)運(yùn)算

//用遞歸獲取貝塞爾曲線點(diǎn)的x軸坐標(biāo)
private float getBezierPointX(int n, int position, float t) {
    if (n == 1) {
      return (1 - t) * mPointList.get(position).x + t * mPointList.get(position + 1).x;
    }
    return (1 - t) * getBezierPointX(n - 1, position, t) + t * getBezierPointX(n - 1, position + 1, t);
  }
//用遞歸獲取貝塞爾曲線點(diǎn)的x軸坐標(biāo)
private float getBezierPointX(int n, int position, float t) {
    if (n == 1) {
      return (1 - t) * mPointList.get(position).x + t * mPointList.get(position + 1).x;
    }
    return (1 - t) * getBezierPointX(n - 1, position, t) + t * getBezierPointX(n - 1, position + 1, t);
  }
private ArrayList<PointF> buildBezierPoints() {
    ArrayList<PointF> points = new ArrayList<>();
    int order = mPointList.size() - 1;
    float delta = 1.0f / POINT_NUM;
    for (float t = 0; t <= 1; t += delta) {
      // Bezier點(diǎn)集
      points.add(new PointF(getBezierPointX(order, 0, t), getBezierPointY(order, 0, t)));
    }
    return points;
  }

2. 繪制貝塞爾曲線

Android 中的Path類可以直接繪制一階到三階的貝塞爾曲線,在onDraw(Canvas canvas) 方法中使用:

繪制一階貝塞爾曲線:

canvas.drawLine(start.x,start.y,end.x,end.y);

繪制二階貝塞爾曲線:

mPath.moveTo(startPoint.x, startPoint.y);//起點(diǎn)
mPath.quadTo(controlPoint1.x, controlPoint1.y, endPoint.x, endPoint.y);
canvas.drawPath(mPath, mPaint);

繪制三階貝塞爾曲線:

mPath.moveTo(startPoint.x, startPoint.y);//起點(diǎn)
mPath.cubicTo(controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
canvas.drawPath(mPath, mPaint);

繪制n階貝塞爾曲線

n階貝塞爾曲線繪制,需要結(jié)合遞歸函數(shù),設(shè)定一條曲線由多少個(gè)點(diǎn)組成,通過(guò)循環(huán)獲取每個(gè)點(diǎn)的坐標(biāo)進(jìn)行繪制。

7階貝塞爾曲線

8階貝塞爾曲線

3.Demo

貝塞爾曲線在android中最常用的是做出一些動(dòng)畫(huà)特效,如QQ消息數(shù)拖拽形變效果,一些炫酷的下拉刷新控件,閱讀軟件的翻書(shū)效果,一些平滑的折線圖的制作,某圖片的運(yùn)動(dòng)軌跡等……

3.1 形狀變形

只需要知道變形前和變形后圖形的數(shù)據(jù)點(diǎn)和控制點(diǎn)即可,通過(guò)改變數(shù)據(jù)點(diǎn)和控制點(diǎn)使得形狀發(fā)生改變。


初始化

  private float[] mData = new float[8];        // 順時(shí)針記錄繪制圓形的四個(gè)數(shù)據(jù)點(diǎn)
  private float[] mCtrl = new float[16];       // 順時(shí)針記錄繪制圓形的八個(gè)控制點(diǎn)

  private float mDuration = 1000;           // 變化總時(shí)長(zhǎng)
  private float mCurrent = 0;             // 當(dāng)前已進(jìn)行時(shí)長(zhǎng)
  private float mCount = 100;             // 將時(shí)長(zhǎng)總共劃分多少份
  private float mPiece = mDuration / mCount;      // 每一份的時(shí)長(zhǎng)

在onDraw(Canvas canvas)方法中繪制

    path.reset();
    path.moveTo(mData[0], mData[1]);

    path.cubicTo(mCtrl[0], mCtrl[1], mCtrl[2], mCtrl[3], mData[2], mData[3]);
    path.cubicTo(mCtrl[4], mCtrl[5], mCtrl[6], mCtrl[7], mData[4], mData[5]);
    path.cubicTo(mCtrl[8], mCtrl[9], mCtrl[10], mCtrl[11], mData[6], mData[7]);
    path.cubicTo(mCtrl[12], mCtrl[13], mCtrl[14], mCtrl[15], mData[0], mData[1]);

    canvas.drawPath(path, mPaint);

    mCurrent += mPiece;
    if (mCurrent < mDuration) {

      mData[1] -= 120 / mCount;
      mCtrl[7] += 80 / mCount;
      mCtrl[9] += 80 / mCount;

      mCtrl[4] -= 20 / mCount;
      mCtrl[10] += 20 / mCount;

      postInvalidateDelayed((long) mPiece);
    }

3.2 漂浮的愛(ài)心

愛(ài)心的漂浮軌跡就是一條三階貝塞爾曲線,結(jié)合屬性動(dòng)畫(huà)中的估值器進(jìn)行設(shè)置。


首先定義一個(gè)屬性動(dòng)畫(huà)的估值器

public class BezierEvaluator implements TypeEvaluator<PointF> {

 private PointF mControlP1;
 private PointF mControlP2;

 public BezierEvaluator(PointF controlP1, PointF controlP2) {
   this.mControlP1 = controlP1;
   this.mControlP2 = controlP2;
 }

 @Override
 public PointF evaluate(float time, PointF start, PointF end) {

   float timeLeft = 1.0f - time;
   PointF point = new PointF();

   point.x = timeLeft * timeLeft * timeLeft * (start.x) + 3 * timeLeft * timeLeft * time *
       (mControlP1.x) + 3 * timeLeft * time *
       time * (mControlP2.x) + time * time * time * (end.x);

   point.y = timeLeft * timeLeft * timeLeft * (start.y) + 3 * timeLeft * timeLeft * time *
       (mControlP1.y) + 3 * timeLeft * time *
       time * (mControlP2.y) + time * time * time * (end.y);
   return point;
 }
}

之后自定義一個(gè)view可以生成愛(ài)心,添加透明度,縮放等動(dòng)畫(huà)和根據(jù)貝塞爾曲線改變其位置的屬性動(dòng)畫(huà)。

初始化愛(ài)心圖片和多個(gè)插值器等,到時(shí)隨即選取

 private void init() {

    // 初始化顯示的圖片
    drawables = new Drawable[3];
    drawables[0] = getResources().getDrawable(R.drawable.red);
    drawables[1] = getResources().getDrawable(R.drawable.yellow);
    drawables[2] = getResources().getDrawable(R.drawable.green);

    // 初始化插補(bǔ)器
    mInterpolators = new Interpolator[4];
    mInterpolators[0] = new LinearInterpolator();// 線性
    mInterpolators[1] = new AccelerateInterpolator();// 加速
    mInterpolators[2] = new DecelerateInterpolator();// 減速
    mInterpolators[3] = new AccelerateDecelerateInterpolator();// 先加速后減速

    // 底部 并且 水平居中
    dWidth = drawables[0].getIntrinsicWidth();
    dHeight = drawables[0].getIntrinsicHeight();
    lp = new LayoutParams(dWidth, dHeight);
    lp.addRule(CENTER_HORIZONTAL, TRUE);// 這里的TRUE 要注意 不是true
    lp.addRule(ALIGN_PARENT_BOTTOM, TRUE);

  }

入場(chǎng)動(dòng)畫(huà)

private AnimatorSet getEnterAnimator(final View target) {
    ObjectAnimator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, 0.2f, 1f);
    ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, 0.2f, 1f);
    ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, 0.2f, 1f);
    AnimatorSet enter = new AnimatorSet();
    enter.setTarget(target);
    enter.setInterpolator(new LinearInterpolator());
    enter.setDuration(500).playTogether(alpha, scaleX, scaleY);
    return enter;
  }

貝塞爾曲線動(dòng)畫(huà)

  private ValueAnimator getBezierValueAnimator(final View target) {
    // 初始化貝塞爾估值器
    BezierEvaluator evaluator = new BezierEvaluator(getPointF(2), getPointF(1));
    // 起點(diǎn)在底部中心位置,終點(diǎn)在底部隨機(jī)一個(gè)位置
    ValueAnimator animator = ValueAnimator.ofObject(evaluator, new PointF((mWidth - dWidth) /
        2, mHeight - dHeight), new PointF(random.nextInt(getWidth()), 0));
    animator.setTarget(target);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        // 這里獲取到貝塞爾曲線計(jì)算出來(lái)的的x y值 賦值給view 這樣就能讓愛(ài)心隨著曲線走啦
        PointF pointF = (PointF) valueAnimator.getAnimatedValue();
        target.setX(pointF.x);
        target.setY(pointF.y);
        // alpha動(dòng)畫(huà)
        target.setAlpha(1 - valueAnimator.getAnimatedFraction());
      }
    });

    animator.setDuration(3000);
    return animator;
  }

結(jié)合動(dòng)畫(huà)添加愛(ài)心

public void addHeart() {

    final ImageView imageView = new ImageView(getContext());
    // 隨機(jī)選一個(gè)愛(ài)心
    imageView.setImageDrawable(drawables[random.nextInt(3)]);
    imageView.setLayoutParams(lp);
    addView(imageView);

    AnimatorSet finalSet = new AnimatorSet();

    AnimatorSet enterAnimatorSet = getEnterAnimator(imageView);//入場(chǎng)動(dòng)畫(huà)
    ValueAnimator bezierValueAnimator = getBezierValueAnimator(imageView);//貝塞爾曲線路徑動(dòng)畫(huà)

    finalSet.playSequentially(enterAnimatorSet, bezierValueAnimator);
    finalSet.setInterpolator(mInterpolators[random.nextInt(4)]);
    finalSet.setTarget(imageView);

    finalSet.addListener(new AnimatorListenerAdapter() {
      @Override
      public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        removeView((imageView));//刪除愛(ài)心
      }
    });
    finalSet.start();

  }

3.3 貝塞爾曲線側(cè)邊索引條

實(shí)例地址:FancyListIndexer_jb51.rar

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android中利用xml文件布局修改Helloworld程序

    Android中利用xml文件布局修改Helloworld程序

    這篇文章主要介紹了Android中利用xml文件布局修改Helloworld程序 的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • android獲取當(dāng)前運(yùn)行Activity名字的方法

    android獲取當(dāng)前運(yùn)行Activity名字的方法

    這篇文章主要介紹了android獲取當(dāng)前運(yùn)行Activity名字的方法,對(duì)比分析了兩種實(shí)現(xiàn)方法供大家選擇,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-01-01
  • Android自定義控件實(shí)現(xiàn)九宮格解鎖

    Android自定義控件實(shí)現(xiàn)九宮格解鎖

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)九宮格解鎖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Android圖片壓縮的實(shí)例詳解

    Android圖片壓縮的實(shí)例詳解

    這篇文章主要介紹了Android圖片壓縮的實(shí)例詳解的相關(guān)資料,android圖片壓縮主要有兩種方式:壓縮圖片分辨率與壓縮圖片質(zhì)量,需要的朋友可以參考下
    2017-08-08
  • Flutter項(xiàng)目手勢(shì)運(yùn)用及單獨(dú)指針消歧問(wèn)題解決方案

    Flutter項(xiàng)目手勢(shì)運(yùn)用及單獨(dú)指針消歧問(wèn)題解決方案

    這篇文章主要為大家介紹了Flutter項(xiàng)目手勢(shì)運(yùn)用及單獨(dú)指針消歧問(wèn)題解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Flutter 路由插件fluro的使用

    Flutter 路由插件fluro的使用

    使用原生的路由基本上能夠滿足大部分需求,但如果想要對(duì)頁(yè)面做類似瀏覽器 url 那樣的路由,或者控制頁(yè)面跳轉(zhuǎn)的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),那么原生的路由需要做不少的改造。在 pub 上,有優(yōu)秀的路由插件 fluro 解決這類問(wèn)題。本文介紹該插件的使用方法
    2021-06-06
  • Android獲取手機(jī)位置的實(shí)現(xiàn)代碼

    Android獲取手機(jī)位置的實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Android獲取手機(jī)位置的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android實(shí)現(xiàn)dialog的3D翻轉(zhuǎn)示例

    Android實(shí)現(xiàn)dialog的3D翻轉(zhuǎn)示例

    這篇文章主要介紹了Android實(shí)現(xiàn)dialog的3D翻轉(zhuǎn)示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-08-08
  • Android itemDecoration接口實(shí)現(xiàn)吸頂懸浮標(biāo)題

    Android itemDecoration接口實(shí)現(xiàn)吸頂懸浮標(biāo)題

    這篇文章主要介紹了Android中使用itemdecoration實(shí)現(xiàn)吸頂懸浮標(biāo)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • Android 滑動(dòng)定位和吸附懸停效果實(shí)現(xiàn)代碼

    Android 滑動(dòng)定位和吸附懸停效果實(shí)現(xiàn)代碼

    這篇文章主要介紹了Android 滑動(dòng)定位和吸附懸停效果實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08

最新評(píng)論