天天看点

自定义View时,使用 Matlab 模拟运动曲线

版权声明:本文章原创于 RamboPan ,未经允许,请勿转载。

自定义View时,使用 Matlab 模拟运动曲线

    • 事件起因
    • 数据推测
    • 数据拟合求曲线
    • 数据插值求曲线

事件起因

自定义View时,使用 Matlab 模拟运动曲线

最近自己在做一个 自定View,有一个功能,就是用手指拖动图片时是实时移动图片,如果抬起时移动有一定速度,那么那个图片还会再滑行一段时间,这个功能也很常见,网上也有很多参考,我想试试按自己的想法去试试,虽然没做过,但第一感觉是这个功能应该不复杂吧(吃了自信的亏,找资料花太久了 …(:з」∠)_ )。

我知道的思路有通过移动 View (View上的图片不移动),给人的感觉是图片在动,但是 View 没有动。那我想的是直接移动 View 中图片的位置,View 上的图片是通过原图片使用 Matrix 进行缩放和位移的,那么我只需要在一小段时间内计算好接下来滑动的 Matrix 值,就可以达到这种滑动的效果,简单的说:

找一个运动曲线函数,然后把对应时间传入,得出移动多少距离。

数据大概心里知道要怎么样的,可以到时候试下,但是寻找运动曲线,没有头绪。问了一个大学时的学霸,然后又跟着他提示摸索了段时间,算是有点思路,决定记录下这个坑,如果你也碰到了需要自定义运动曲线或者有段数据,自己想求出曲线函数,但又不是专业弄数据的,就可以参考下这篇文章。

数据推测

确定了可行性之后,就可以考虑下我们需要计算什么,已知的是可以通过 VelocityTracker 计算抬起时的速度,毕竟我们也需要速度是否足够大来判断满足滑动条件。因为通过速度来计算每个间隔时间运动多少,感觉有点麻烦,所以我打算通过总路程,再按一定的比例分到每段时间需要移动多少。

假设我们抬起手指时速度为 x ,还继续这个速度的 3 倍距离,就是 3x ,举个例子,比如抬起时 1000 的速度,那我们还让这个图片滑动 3000 的距离,至于多少倍可以后面调试看多少效果最好。那既然知道了滑动的总距离,那就要计算多少次滑动结束,为了方便计算,这里取 10 。

那么我们现在需要来计算每份时间移动多少距离,虽然说不上每份具体取多少,但肯定不会是平均,因为平均的话,就是匀速运动了,这样不太符合逻辑。按我们物理的常识,你加速肯定是有力作用并且力还要增大,如果没有力作用速度需要慢慢变小。所以这里假设是先加速运动一半后减速运动,在总运动距离中各占一半。

通过 Excel 先把大致的曲线模拟出来,得到对应的 x 与 y 的一些对应关系,才能拿去求对应的函数关系。这里先贴出来模拟的数据再进行说明。

自定义View时,使用 Matlab 模拟运动曲线

x 为运动的时间,0 为开始 1 为结束;

y 为运动的距离,0 为开始 1 为结束,

紫色表格部分为 x 的坐标点,代表时间;

蓝色表格部分为 y 的坐标点,代表移动的距离比值。

因为这里实际上想算的是一个比值,所以用的 0 - 1 的区间,如果你想用其他区间,也可以修改对应的值,我们最后肯定会拿这个比值和移动总距离 (3000) 相乘,所以就用 0 - 1 的范围。

当准备好一组 x,y 对应关系的数据后,就可以插入表格,使用带平滑曲线的散点图,把 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
   
           
自定义View时,使用 Matlab 模拟运动曲线

可以看到这里的蓝色曲线就是算出来的曲线,绿色的点是之前我们标记的参考点,可以看到蓝色曲线是大致符合,但是如果你需要精确的话,可能不太适合,比如我们查看对应 0 与 0.1 的 y 值,可以发现 0.1 比 0 的 y 值还低,如果要作为运动轨迹反映,那就是 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 ,那么就是四次方,加上常数项为五个。所以这里 y 为 5 个值,可以看到第一项实际上没有,如果 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
	   
           
自定义View时,使用 Matlab 模拟运动曲线

可以看到 p3 这次只有 4 项,得到参数与上面相同,并且图中红色曲线覆盖蓝色线。当然你尝试时可以多使用几个次方数来确定是否哪条会更好,比如我再次用蓝色线表示,采用 10 次方的多项式来拟合数据。

自定义View时,使用 Matlab 模拟运动曲线

过了给的所有数据点,圆滑度相比 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');

           
自定义View时,使用 Matlab 模拟运动曲线

可以看到曲线是过了所有的点的,不算特别圆滑,但也还行,需要求出这个表达式。我暂时没有找到好点的方式,使用 spline 对 x 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 中的一个小方面,摸索简单,如果不妥指出欢迎指出。