亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

線性貝塞爾曲線的簡單說明(一)

2019-11-07 23:12:06
字體:
來源:轉載
供稿:網友

因為公司開發SDK的原因,公司開發需要做各種動畫UI特效,也算是對動畫有一定的了解,所以準備寫個博客鞏固下。本篇就對貝塞爾曲線加上屬性動畫來說一下。 1、線性別塞爾曲線的知識說明 線性貝塞爾曲線的公式如下: B(t) = P0 + (P1 - P0)t 其中t的范圍是[0,1](這個范圍很是關鍵). 說白了就是兩點Point0,Point1之間構成的一條直線(線段),其作用可以看做是從P0點到P1點的位移路徑,假設A從P0走到P1,那么就是隨著t的變換,A逐漸走P1點的一個過程。如下圖(盜圖): 這里寫圖片描述 我們知道一個點在平面中是有X,Y兩個坐標點組成(特么的廢話),假設Point0的坐標是(X0,Y0),Point1的坐標位(X1,Y1)那么A移動的過程中也即是隨著t的漸變,A的橫坐標點從X0逐漸移動到X1,縱坐標Y0逐漸移動到Y1的過程,用點來表示的話就是A經過一些列的點:(X0,Y0)–>(Xa,Ya)–>(Xb,Yb)–>…–>(X1,Y1)或者Point0–>PointA–>PointB–>…–>Point1才到Point1(此時t=1)。 我們在初中的時候學過直線方程y = kx +b是x跟y的關系,而貝塞爾曲線在應用中其實是x與t構成的直線函數以及y與t構成的直線函數關系: B(tx) = (X1-X0)t+X0 B(ty) = (Y1-Y0)t + Y0 這里寫圖片描述 所以如果在android中想要讓一個View從一位置移動到另外一個位置,如果用線性貝塞爾曲線的話,就是根據上面的兩個函數根據變量t不斷修改View的x和y的位置即可;當然因為(x,y)構成一個點,所以就是讓View隨著t的改變,從一個點移動到新的點的過程直到Point1。那么核心算法就是根據當前t的值(t->[0,1])根據上面的兩個函數獲取當前的newX和newY構成的坐標點(newX,newY)更新view的位置坐標點。 (感覺上面有點啰里啰嗦,表達能力欠缺)。 那么基本算法偽代碼可以如下:

Point point0 = new Point(x0,y0);Point point1 = new Point(x1,y1);int k0 = x1- x0;//x與t直線函數的斜率int k1 = y1 - y0;//y與t直線函數的斜率float t = 0f;while(t<=0){ //最新的x和y的位置 int newX = k0*t + x0; int newY = k1*t + y0; //更新view的位置方式1 LayoutParams params = view.getLayoutParams(); params.leftMargin = newX; params.rightMargin = newY; view.setLayoutParams(params); //t以某種規則遞增,比如每次增加0.1 t+=0.1 }

2、自己寫一個小小的測試例子 根據是上面的說明以及偽代碼例子程序如下: 代碼也很簡單,首先第一一個Point類,包換了x和y:

class Point { PRotected float x;//橫坐標 protected float y;//縱坐標 public Point(float x,float y){ this.x = x; this.y = y; } }

然后定義一個線性貝塞爾曲線計算器類,這個類需要先傳入線段的起始點,然后根據t來計算對應的新的Point對象:

class BezierLine { private Point startPoint;//貝塞爾曲線起點 private Point endPoint;//貝塞爾曲線終點 public BezierLine(Point startPoint, Point endPoint) { this.startPoint = startPoint; this.endPoint = endPoint; } /** * 根據線性貝塞爾函數,獲取線性貝塞爾曲線上的某個點 * @param t 在[0,1]范圍的某一個值 * @return 根據t的不同而返回的貝塞爾曲線的點 */ public Point createBezierLine(float t){ float newX = (endPoint.x -startPoint.x)*t + startPoint.x; float newY = (endPoint.y -startPoint.y)*t + startPoint.y; return new Point(newX,newY); }}

以上可以說完事具備,只欠東風,那么怎么使用上述貝塞爾曲線來更新呢?這里提供一個簡單的思路,就是用Handler來發送不斷發送消息,簡單的代碼如下:

private float t = 0.0f; private BezierLine bezierLine; private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { t+=0.01f; if(t>1.0){ return; } //獲取當前t對應的Point位置 Point newPoint = bezierLine.createBezierLine(t); //更新View的位置 updateViewLocation(newPoint); //繼續發送消息 handler.sendEmptyMessage(0); } }; private void updateViewLocation(Point point){ moveParams.leftMargin = (int)point.x; moveParams.topMargin =(int)point.y; moveView.setLayoutParams(moveParams); }

運行的效果如圖所示: 這里寫圖片描述 當然這種簡單的運動通過scrollTo也可以簡單實現,關于滾動的詳細說明,可參考《View的滾動原理簡單解析》和《View的滾動原理簡單解析2》。

到此位置demo結束,只是簡單的實現了兩個點之間的運動估計,如果點很多的情況下怎么處理呢?比如如果View要進行如下的運動軌跡該怎么辦? 這里寫圖片描述 在回答這個問題之前需要思考或者準備如下問題(以路徑B為例): 1)從P0到P4的所需時間是多少毫秒?(答案是未知,也就是用戶可配) 2)從P0–>P1、P1–>P2、P2–>P3、P3–>P4四個線段之間移動所消耗的時間是一致的嗎?(答案是不一定,他們的耗時又長又短,這其實是一個動畫中的插值器的概念,比如讓P0–>P1的時間最短,其余的線段之間速度也設置的不一樣)當然本文為了方便說明在此定義為點從P0–>P1、P1–>P2、P2–>P3、P3–>P4四個線段之間所耗時是一樣的。也就是說假設傳入的運動時間為duration表示,點的總數用n表示,那么每個線段之間的耗時比例關系如下: 這里寫圖片描述 根據上圖很容易就得出了這些點與t得關系偽代碼:

//點總數 int n; //P0的起始時間為0 (0f,P0); //p0 ..pn各個點與t的對應點斷數 int lineSegment = n-1; for (int i = 1; i < n; ++i) { ((float)i/lineSegment, Pi); }

代碼實現如下: 1)定義一個TPoint類來表示t和P0,P1,P2,P3,P4的關系

public class TPoint { protected float t; protected Point point; public TPoint(float t,Point point){ this.t = t; this.point = point; }}

2)初始化點數P0,P1,P2,P3,P4列表,并且綁定各個點對應的t

public void bindTPoint(){ //pointList是一個ArrayList size = pointList.size(); tPoints = new TPoint[size]; tPoints[0] = new TPoint(0f,pointList.get(0)); //p0--p1構成的線段 int lineSegment = size -1; for(int i=1;i<size;i++){ tPoints[i] = new TPoint((float)i/lineSegment,pointList.get(i)); } }

就這樣完成了第一步的工作!

在第一個例子的時候 BezierLine方式提供了startPoint和endPoint兩個起止點就可以了,但是現在有若干個點怎么辦呢,所以在這里優先重構的的就是BezierLine這個類:

/** * 根據線性貝塞爾函數,獲取線性貝塞爾曲線上的某個點 * @param t 在[0,1]范圍的某一個值 * @param startPoint 貝塞爾曲線開始的點 * @param endPoint 貝塞爾曲線結束的點 * @return 根據t的不同而返回的貝塞爾曲線的點 */ public static Point createBezierLine(float t,Point startPoint,Point endPoint){ float newX = (endPoint.x -startPoint.x)*t + startPoint.x; float newY = (endPoint.y -startPoint.y)*t + startPoint.y; return new Point(newX,newY); }

注意此時相鄰兩個點組成的路徑的范圍t仍然為[0,1];只不過t要換一種方法來解釋,t對于相鄰點之間有點類似于求進度的算法,一個作為起點一個作為終點,其數學公式如下: 這里寫圖片描述

那么根據上面的公式,根據當前時間獲取最新位置點Point對象的代碼如下:

public Point getNewPoint(){ //當前時間 long currentTime = System.currentTimeMillis(); //當前時間進度 float currentProgress = (float) (currentTime - startTime) / DURATION ; if(currentProgress>1.0){ finish = true; } //判斷當前時間進度是在哪一個線段上 TPoint prePoint = tPoints[0]; for(int i=1;i<size;i++){ TPoint nextPoint = tPoints[i]; //運動的點在prePoint和nextPoint之間 if(currentProgress<nextPoint.t){ //當前點在當前路徑的進度 float progress = (currentProgress-prePoint.t)/(nextPoint.t-prePoint.t); return BezierLine.createBezierLine(progress, prePoint.point, nextPoint.point); } prePoint = nextPoint; }//end for //其實這一步感覺不應該返回 return tPoints[size-1].point; }

那么有了這個getNewPoint方法,直接調用第一個Demo中的updateViewLocation方法即可,同樣是用handler來發送消息,并跟新位置,詳細見文章最后代碼下載鏈接,運行效果如圖: 這里寫圖片描述 其實上面分析了這么多有點啰里啰嗦了,總結下來基本的算法思路很簡單(在各個線段耗時相等的情況下,假設view從P0出發): 1)分配View 從P0到達P1,P2,P3,P4到這幾個點的時間節點 1)根據當前時間和開始時間以及步驟1計算此時view應該位于哪一條路徑上 2)計算view在當前路徑相對當前路徑起始點的進度。比如view此時位于p(n-1)和pn這條路徑上,那么此進度當前路徑的貝塞爾曲線的t值

本來本篇就涉及到屬性動畫的介紹的,但是昨天因為搬家折騰了一天,一篇博客寫了兩天,這樣的話思路有點混亂了感覺,下一篇在分析屬性動畫的貝塞爾曲線實現方案吧,不過感覺應該跟本文的思路相差不大;另外本篇只討論了線性的,拋物線的運動軌跡改下createBezierLine的方程就OK了,就不多做說明。如有不當之處,歡迎批評指正,老規矩最后上代碼:下載鏈接


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品一区专区欧美日韩| www高清在线视频日韩欧美| 57pao精品| 久久精品中文字幕电影| 欧美日韩国产黄| 亚洲男人天堂2019| 亚洲字幕一区二区| 人人爽久久涩噜噜噜网站| 国产精品a久久久久久| 欧美一级淫片aaaaaaa视频| 日韩毛片中文字幕| 中日韩美女免费视频网址在线观看| 欧美日韩亚洲天堂| 91久热免费在线视频| 国产丝袜一区二区| 久久人人爽国产| 亚洲xxxx18| 欧美福利在线观看| 国产精品视频免费观看www| 亚洲国产欧美一区二区丝袜黑人| 精品动漫一区二区| 奇米成人av国产一区二区三区| 国产精品wwww| 国产日韩欧美电影在线观看| 亚洲一区二区免费| 欧美成人精品激情在线观看| 国产精品一区二区三| 欧美精品久久久久久久| 国产精品露脸av在线| 日韩日本欧美亚洲| 色综合导航网站| 亚洲精品一区二三区不卡| 国内精品久久影院| 成人激情视频在线| 日韩免费视频在线观看| 欧美猛男性生活免费| 国产精品国模在线| 青青草一区二区| 97热精品视频官网| 亚洲天堂精品在线| 亚洲开心激情网| 亚洲色图美腿丝袜| 97国产精品免费视频| 伊人久久综合97精品| 中文字幕精品—区二区| 欧美自拍视频在线观看| 国产精品视频不卡| 日韩av电影手机在线观看| 国产欧美日韩最新| 国产视频亚洲精品| 午夜精品美女自拍福到在线| 久久精品国产2020观看福利| 色阁综合伊人av| 欧美激情成人在线视频| 亚洲欧美在线一区| 粉嫩av一区二区三区免费野| 7777免费精品视频| 精品一区二区三区四区在线| 91在线国产电影| 国产精品欧美一区二区| 97在线精品视频| 成人妇女淫片aaaa视频| 91最新国产视频| 成人亚洲综合色就1024| 欧美激情精品久久久久久久变态| 精品久久久一区| 91深夜福利视频| 国产精品视频地址| 精品丝袜一区二区三区| 国产欧美日韩丝袜精品一区| 日韩av有码在线| 亚洲最大成人网色| 91在线观看免费高清完整版在线观看| 亚洲男人的天堂在线播放| 久久精品国产96久久久香蕉| 尤物yw午夜国产精品视频| 久久精品国产亚洲一区二区| 亚洲一区二区三区sesese| 亚洲国产精品热久久| 亚洲第一天堂无码专区| 最近2019中文字幕一页二页| 国产美女搞久久| 国产在线视频欧美| 91精品久久久久久久久久另类| 黄色成人在线播放| 欧美极品美女电影一区| 国产成一区二区| 欧美亚洲一区在线| 最近2019中文字幕mv免费看| 亚洲女人天堂av| 日韩中文字幕精品视频| 久久久久久久爱| 久久久久久久激情视频| 国产+成+人+亚洲欧洲| 97久久久免费福利网址| 国产精品夜间视频香蕉| 国内免费精品永久在线视频| 亚洲精品电影久久久| 久久av.com| 国产成人极品视频| 国产精品美女久久久久av超清| 日本亚洲精品在线观看| 国产精品九九九| 亚洲精品美女视频| 日韩美女视频在线观看| 成人乱色短篇合集| 懂色av影视一区二区三区| 久久久成人的性感天堂| 亚洲国产天堂久久国产91| 成人在线免费观看视视频| 68精品久久久久久欧美| 亚洲国产99精品国自产| 久久久久久69| 精品国内自产拍在线观看| 欧美日韩免费区域视频在线观看| 欧美成人精品在线视频| 国产精品一香蕉国产线看观看| 日韩电影免费观看中文字幕| 都市激情亚洲色图| 日韩欧美在线第一页| 国产成人福利视频| 成人黄色av播放免费| 亚洲国产精品人人爽夜夜爽| 美日韩丰满少妇在线观看| 色综合色综合久久综合频道88| 欧美怡春院一区二区三区| 国产一区二区在线播放| 亚洲国产中文字幕久久网| 国产精品久久久久久久app| 91精品视频一区| 亚洲日本中文字幕免费在线不卡| 成人国产精品免费视频| 日韩中文字幕在线| 亚洲精品国产免费| 97精品国产97久久久久久春色| 91视频国产一区| 91精品视频在线免费观看| 91精品国产综合久久久久久久久| 日韩成人激情影院| www.欧美视频| 原创国产精品91| 国产精品igao视频| 国产精品自产拍在线观| 欧美色播在线播放| 美日韩丰满少妇在线观看| 成人黄色av免费在线观看| 日韩电影在线观看中文字幕| 精品久久香蕉国产线看观看亚洲| 欧美激情女人20p| 国产精品第1页| 欧美裸体xxxx极品少妇| 7m第一福利500精品视频| 亚洲天堂av在线免费| 欧美另类老女人| 精品欧美一区二区三区| 91免费版网站入口| 欧美日韩成人精品| 亚洲视频欧洲视频| 国产视频精品xxxx| 日韩精品视频在线观看免费| 国产精品 欧美在线| 人人爽久久涩噜噜噜网站| 久久99视频精品| 国产欧美日韩免费看aⅴ视频|