今天应公司要求,实现一个转盘旋转算法,
网上找了很多资料,再根据实际效果构造出了一个算法,其实原理很简单,下面我就来做一下总结:希望对遇到此类问题的朋友有所帮助或启发。
首先:转盘旋转分几个阶段:加速,减速,停止到指定位置。
当然旋转当然与角度与弧度有关,弧度在这里我就不介绍了,当然是用旋转角度来转换的,公式为:角度/180 * PI
一开始我对于加速过程与减速过程想了很多办法,结果没一种接近现实效果的。但是做这么多实验当然也不是徒劳的,从这些办法中我最终选择了正切函数曲线图(tan),
我将这个旋转过程分为两部分:加速,减速,我以原点坐标来表示加速到减速这个过度点,见下草图
从图中可以得出:
当 Δx为常量时: Δy从-∞到0 减少, Δy从0到+∞ 增加。(哈哈,正是我想要的结果,并且不是线性增加的,更接近真实性)
故:我决定以y代表时间,x代表角度。
//-------------------------------------------------------------------------------------------------------------
下面我开始编程实现:
定义变量:
doublem_dCurAngle;//当前的旋转角度
doublem_dTime;//距离旋转开始的时间
doublem_dCurveMid;//过度点时间(及前一段加速总时间)
c++中及得到算法函数(反正切函数):
m_dCurAngle = atan((m_dTime - m_dCurveMid));
对,到此,雏形已经明了,现在就需要解决三个问题了:
1、对于时间控制(我们淡然不是想y轴所对应的时间间隔相对于现实时间是一一对应的,说白了就是我们希望y轴的时间区块是可缩放的)
2、对于旋转到指定的点的问题还未解决的(随机出来的终点角度当然要是可控的)
3、从上一次旋转结果开始运动,
下面我来解决这几个问题:
对于第一个问题,非常简单,我们可以给时间设置一个时间参数(当然其实术语应该叫:曲线参数)
我是将所有时间除以一个参数(如下定义):
double m_dCurveParam; //曲线参数(这里我设置为150)
以上旋转就变成了: m_dCurAngle = atan((m_dwRotateTime - m_dCurveMid) / m_dCurveParam);
对于第二个问题,解决办法很多:我这里说一个我自己实现的办法。
doublem_dRotateAngle;//旋转总角度(绝对角度)
doublem_dwRotateTime;//转盘旋转总时
doublem_dCurveScale; //曲线量表
doublem_dCurveOffset; //加速旋转总角度
我的解决办法依然是给设置个参数:
我们可以从上图中得到两段易做图旋转角度:
m_dCurveOffset = atan(- m_dCurveMid / m_dCurveParam);//前半段旋转角度负值
故能得到:
m_dCurveScale=m_dRotateAngle / (atan((m_dwRotateTime - m_dCurveMid) / m_dCurveParam) - m_dCurveOffset);
其中:atan((m_dwRotateTime - m_dCurveMid) / m_dCurveParam) 表示后半段减速所旋转角度
故得出最后旋转算法:
m_dCurAngle = m_dCurveScale * ( atan((m_dTime - m_dCurveMid) / m_dCurveParam) - m_dCurveOffset);
这样:当旋转总时间结束后,就旋转到当前要旋转的点了,
下面做逻辑:
if (m_dTime <= m_dwRotateTime)//旋转没结束
{
m_dCurAngle = m_dCurveScale * (atan((m_dTime - m_dCurveMid) / m_dCurveParam) - m_dCurveOffset);
}
else{
//结束处理
}
到此:第二个问题也被解决了:
下面来解决第三个问题:
相信第二个问题解决了后,这个问题就简单到爆了。
这个问题只需要改变两个地方:
1、改变旋转总角度(m_dRotateAngle)
如果你 m_dRotateAngle = 360.0 * Random(6)+ m_dRotateOffsetNow; (m_dRotateOffsetNow表示此次相对于原点偏移)
那么你需要改成:m_dRotateAngle = 360.0 * Random(6)+ (m_dRotateOffsetNow-m_dRotateOffsetPve);(m_dRotateOffsetPve表示上次相对于原点偏移)
2、改变当前的旋转角度(m_dRotateAngle)
之前是这样 m_dRotateAngle = m_dRotateAngle;
那么你要改成这样:m_dRotateAngle = m_dRotateAngle + m_dRotateOffsetPve;(m_dRotateOffsetPve表示上次相对于原点偏移)
到此:全部旋转都解决(当然,此旋转为顺时针旋转,逆时针同理)
你不妨试试效果。
你可以调整前半段时间m_dCurveMid,跟曲线参数m_dCurveParam来实现自定义效果!
Good luck!!!