自定義View時,使用 Matlab 模擬運動曲線

版權聲明:本文章原創於 RamboPan ,未經允許,請勿轉載。

自定義View時,使用 Matlab 模擬運動曲線

事件起因

最近自己在做一個 自定View,有一個功能,就是用手指拖動圖片時是實時移動圖片,如果擡起時移動有一定速度,那麼那個圖片還會再滑行一段時間,這個功能也很常見,網上也有很多參考,我想試試按自己的想法去試試,雖然沒做過,但第一感覺是這個功能應該不復雜吧(吃了自信的虧,找資料花太久了 …(:з」∠)_ )。

我知道的思路有通過移動 ViewView上的圖片不移動),給人的感覺是圖片在動,但是 View 沒有動。那我想的是直接移動 View 中圖片的位置,View 上的圖片是通過原圖片使用 Matrix 進行縮放和位移的,那麼我只需要在一小段時間內計算好接下來滑動的 Matrix 值,就可以達到這種滑動的效果,簡單的說:

找一個運動曲線函數,然後把對應時間傳入,得出移動多少距離。

數據大概心裏知道要怎麼樣的,可以到時候試下,但是尋找運動曲線,沒有頭緒。問了一個大學時的學霸,然後又跟着他提示摸索了段時間,算是有點思路,決定記錄下這個坑,如果你也碰到了需要自定義運動曲線或者有段數據,自己想求出曲線函數,但又不是專業弄數據的,就可以參考下這篇文章。


數據推測

確定了可行性之後,就可以考慮下我們需要計算什麼,已知的是可以通過 VelocityTracker 計算擡起時的速度,畢竟我們也需要速度是否足夠大來判斷滿足滑動條件。因爲通過速度來計算每個間隔時間運動多少,感覺有點麻煩,所以我打算通過總路程,再按一定的比例分到每段時間需要移動多少。

假設我們擡起手指時速度爲 x ,還繼續這個速度的 3 倍距離,就是 3x ,舉個例子,比如擡起時 1000 的速度,那我們還讓這個圖片滑動 3000 的距離,至於多少倍可以後面調試看多少效果最好。那既然知道了滑動的總距離,那就要計算多少次滑動結束,爲了方便計算,這裏取 10

那麼我們現在需要來計算每份時間移動多少距離,雖然說不上每份具體取多少,但肯定不會是平均,因爲平均的話,就是勻速運動了,這樣不太符合邏輯。按我們物理的常識,你加速肯定是有力作用並且力還要增大,如果沒有力作用速度需要慢慢變小。所以這裏假設是先加速運動一半後減速運動,在總運動距離中各佔一半。

通過 Excel 先把大致的曲線模擬出來,得到對應的 xy 的一些對應關係,才能拿去求對應的函數關係。這裏先貼出來模擬的數據再進行說明。

模擬數據

x 爲運動的時間,0 爲開始 1 爲結束;
y 爲運動的距離,0 爲開始 1 爲結束,
紫色表格部分爲 x 的座標點,代表時間;
藍色表格部分爲 y 的座標點,代表移動的距離比值。

因爲這裏實際上想算的是一個比值,所以用的 0 - 1 的區間,如果你想用其他區間,也可以修改對應的值,我們最後肯定會拿這個比值和移動總距離 (3000) 相乘,所以就用 0 - 1 的範圍。

當準備好一組 xy 對應關係的數據後,就可以插入表格,使用帶平滑曲線的散點圖,把 x y 對應放進去,就可以得到右圖中根據這些數據模擬出來的曲線,如果途中你有些數據不滿意,打算調一下,直接修改 Excel 中對應的數據,表格也會隨着變化。

因爲我們是表達時間與距離的關係,斜率反映的是距離的變化快慢,也側面反映了速度

前半段斜率由小變大( y 相對 x 的增加從小變大);
後半段斜率由大變小( y 相對 x 的增加從大變小)。

符合我們剛開始的要求。這裏說下,如果你想的是要一個直接運動從快到慢的曲線,就類似後半段的曲線,這裏演示採用我這條曲線。

當你確定這個曲線是你想要的,那我們就需要求這個曲線的函數表達式了。這裏需要使用 matlab 來進行操作。因爲不是專業用這個,如果有不對的地方,希望大佬提出更好的方式予以改進。

我嘗試出來得分有兩種方式去算出對應函數曲線:數據擬合求曲線數據插值求曲線


數據擬合求曲線

數據不一定完全過你給的參考點,但是大致曲線是符合的。

話不多說,上代碼和曲線圖,中間插入註釋說明。
(代碼不需要輸入 >> ,我這裏是複製的結果,所以有 >> )


	//首先是 輸入 x 與 y 的值,數組的寫法。
	>> x=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0];
	>> y=[0,0.03,0.07,0.15,0.28,0.5,0.72,0.85,0.93,0.97,1.0];
	//把對應數據顯示出來,g. 代表綠色的點,後面就是指定點的大小。
	>> plot(x,y,'g.','markersize',25);
	//保留繪圖
	>> hold on;
	// 這裏是採用高次方進行擬合數據。
	//p3 代表得出來的係數,你也可以取另外的變量名。
	//4 代表採用4次方的函數(多項式)來進行擬合。
	>> p3=polyfit(x,y,4);
	//這裏這種表達式代表 0 開始 ,步進爲 0.1 ,直到 1 結束。
	>> x2=0:0.1:1;
	//通過 x2 使用 p3 這個函數把(不知道怎麼稱呼)算出對應 y2 的值。
	>> y2=polyval(p3,x2);
	//把x2 y2 數據顯示出來,這裏 b 代表藍色。
	>> plot(x2,y2,'b');
	//得到 p3 的多項式參數
	>> p3

	p3 =
	//後面來解釋用法
   -0.0000   -3.2673    4.9009   -0.6707    0.0185
   

擬合插值結果
可以看到這裏的藍色曲線就是算出來的曲線,綠色的點是之前我們標記的參考點,可以看到藍色曲線是大致符合,但是如果你需要精確的話,可能不太適合,比如我們查看對應 00.1y 值,可以發現 0.10y 值還低,如果要作爲運動軌跡反映,那就是 0.1 的時候還比 0 的時候倒回一點距離,這就不合理的吧。

但如果你對曲線要求不這麼高的話,這裏就可以拿到曲線了,這裏對應解釋下 p3 的值需要怎麼用。p3 是顯示的 5 個值,那麼對應的函數爲。

y = - 0.0000 * x4 - 3.2673 * x3 + 4.9009 * x2 - 0.6707 * x1 + 0.0185

y 就是代表每項式對應的常數,因爲之前 p3=polyfit(x,y,4) 這裏傳入的是 4 ,那麼就是四次方,加上常數項爲五個。所以這裏 y5 個值,可以看到第一項實際上沒有,如果 p3=polyfit(x,y,3) 應該也是一樣的效果,繼續輸入嘗試一下。


	>> x3=0:0.1:1;
	>> p3=polyfit(x,y,3);
	>> y3=polyval(p3,x3);
	//這裏用的紅色線
	>> plot(x3,y3,'r');
	>> p3
	
	p3 =
	
	   -3.2673    4.9009   -0.6707    0.0185
	   

採用3次方多項式
可以看到 p3 這次只有 4 項,得到參數與上面相同,並且圖中紅色曲線覆蓋藍色線。當然你嘗試時可以多使用幾個次方數來確定是否哪條會更好,比如我再次用藍色線表示,採用 10 次方的多項式來擬合數據。

過了給的所有數據點,圓滑度相比 4 次方時也好一點,接下來就要介紹另一種方式了。


數據插值求曲線

數據完全過給的數據點,曲線相對來說也會圓滑些。


	>> x=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0];
	>> y=[0,0.03,0.07,0.15,0.28,0.5,0.72,0.85,0.93,0.97,1.0];
	>> x1=0:0.1:1;
	//這裏是 1 ,不是 l .
	//第四個參數有 4 個選項,不過看效果還是這個最好,所以就不介紹其他的了。
	//有興趣可以瞭解 nearest(臨近點) linear(線性) spline(三次採樣) cubic(立方) 
	>> y1=interp1(x,y,x1,'spline');
	>> plot(x,y,'g.','markersize',25);
	>> hold on;
	>> plot(x1,y1,'r');


可以看到曲線是過了所有的點的,不算特別圓滑,但也還行,需要求出這個表達式。我暫時沒有找到好點的方式,使用 splinex y 進行求參數操作,再使用 p 以及 p.coefs 查看所有參數(就是首先確定曲線滿足要求,再調用這個方法去尋找對應的多項式參數,而不是在 interp1 那步就能拿到對應參數進行輸出了,繞了一點)


	>> p=spline(x,y)
	//查看p.
	>> p

	p = 
	
	      form: 'pp'
	      //這裏的斷點代表 0 每個區間兩側的值。
	    breaks: [0 0.1000 0.2000 0.3000 0.4000 0.5000 0.6000 0.7000 0.8000 0.9000 1]
	    //一共有10個區間,加上上面的 11 個斷點。
	    //就是類似 0 - 0.1 ; 0.1 - 0.2 …… 0.9 - 1.0;
	 	//就是一個分段函數,一共 10 段,每段是 3次方的多項式,所以是 4個參數。
	     coefs: [10x4 double]
	    pieces: 10
	     order: 4
	       dim: 1
	       
	//輸入 對應參數.coefs 這個可以查看每項對應的參數值。
	//每行代表每個分段函數,第一行就是 0 - 0.1 的分段函數。
	//每列就是代表一個3次方的多項式.
	>> p.coefs
	
	ans =
	
	    6.6369   -1.4911    0.3827         0
	    6.6369    0.5000    0.2836    0.0300
	   -3.1845    2.4911    0.5827    0.0700
	   16.1012    1.5357    0.9854    0.1500
	  -21.2202    6.3661    1.7756    0.2800
	  -21.2202   -0.0000    2.4122    0.5000
	   16.1012   -6.3661    1.7756    0.7200
	   -3.1845   -1.5357    0.9854    0.8500
	    6.6369   -2.4911    0.5827    0.9300
	    6.6369   -0.5000    0.2836    0.9700

其實就是算了一個 10 段的分段函數給你,然後你拿到對應的值就也可以計算出一個函數出來。這裏拿 0.1 - 0.2 來舉例。

y = 6.6369 * (x - 0.1)3 + 0.5 * (x - 0.1)2 + 0.2836 * (x - 0.1)1 + 0.03

爲什麼不拿 0 - 0.1 來舉例,就是怕忘了前面的節點值。因爲是分段函數,那麼 x 需要先減去這個區間的前閾值,再進行乘方,如果直接乘方就不對了。


兩種方式就介紹到此,所以需要採用哪種方式,可以參考自己的情況。雖然能用一個方程就能表示曲線肯定省事,但是如果是多段三次方函數來表示一個曲線,可能會更圓滑。(理論上感覺)

因爲恰好想尋找一個運動曲線,才誤入擬合數據,只是簡單用了下 Matlab 中的一個小方面,摸索簡單,如果不妥指出歡迎指出。

發佈了17 篇原創文章 · 獲贊 8 · 訪問量 8278
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章