设置 :
我使用的无功香蕉用OpenGL一起,我有我想要旋转的齿轮。 我有以下信号:
bTime :: Behavior t Int -- the time in ms from start of rendering
bAngularVelosity :: Behavior t Double -- the angular velocity
-- which can be increase or
-- decreased by the user
eDisplay :: Event t () -- need to redraw the screen
eKey :: Event t KeyState -- user input
最后,我需要计算bAngle
,然后将其过去的绘图功能:
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
的角度很容易计算: a = ∫v(t) dt
问题 :
我想我想要做的是在接近这个整体作为a = ∑ v Δt
每个eDisplay事件(或更多的时候,如果我需要)。 这是去了解这个正确的方法是什么? 如果是这样,我怎么Δt
从bTime
?
另请参见 :我怀疑答案使用mapAccum
功能。 如果是这样,请另见我的其他问题也是如此。
编辑:要回答这个问题,是的,你说得对使用您正在使用的逼近,这是解决一阶微分方程的欧拉法,是你的目的不够准确,特别是因为用户不具有对于角速度躺在身边判断你对绝对值。 减少你的时间间隔将使其更加准确,但是这并不重要。
您可以在更少的,更大的步骤(见下文)做到这一点,但这种方式似乎清楚的给我,我希望这是你。
为什么这个再解决烦恼呢? 这样,即使eDisplay
发生在不规则的时间间隔,因为它计算eDeltaT
。
让我们给自己一个时间事件:
eTime :: Event t Int
eTime = bTime <@ eDisplay
为了得到DeltaT的,我们需要保持的时间间隔传递的轨迹:
type TimeInterval = (Int,Int) -- (previous time, current time)
所以我们可以将它们转换成三角洲:
delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0
我们应该如何更新的时间间隔,当我们得到一个新的t2
?
tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)
因此,让我们部分应用,为的时候,给我们的时间间隔更新:
eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime
然后我们可以accumE
-accumulate上的初始时间间隔功能:
eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker
由于ETIME是因为呈现的开始时测量,初始(0,0)
是适当的。
最后,我们可以有我们的DeltaT事件,只把它运用( fmap
平) delta
上的时间间隔。
eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval
现在,我们需要更新的角度,用类似的想法。
我会让角度更新,只需转动的bAngularVelocity
成倍数:
bAngleMultiplier :: Behaviour t (Double->Double)
bAngleMultiplier = (*) <$> bAngularVelocity
那么我们就可以用它来使eDeltaAngle
:(编辑:更改为(+)
并转换为Double
)
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> (bAngleMultiplier <@> ((fromInteger.toInteger) <$> eDeltaT)
和积累得到的角度:
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
如果你喜欢的俏皮话,你可以写
eDeltaT = delta <$> (accumE (0,0) $ tick <$> (bTime <@ eDisplay)) where
delta (t0,t1) = t1 - t0
tick t2 (t0,t1) = (t1,t2)
eAngle = accumE 0.0 $ (+) <$> ((*) <$> bAngularVelocity <@> eDeltaT) =
但我不认为这非常具有启发性,说实话,我不知道我有我的固定性的权利,因为我没有在ghci中测试这一点。
当然,因为我做了eAngle
代替bAngle
,你需要
reactimate $ (draw gears) <$> eAngle
而不是你原来的
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
一个简单的方法是假设eDisplay
发生在固定的时间间隔,并考虑bAngularVelocity
是一个相对的而不是绝对的措施,界河会给你下面真的相当短的解决方案。 [注意,这是没有好,如果eDisplay
是失控的,或者如果它触发不定期明显,或规律性变化的,因为它会导致你的装备以不同的速度为您的间隔旋转eDisplay
变化。 你需要我的其他(长)的办法,如果是这样的话。]
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> bAngularVelocity <@ eDisplay
即转bAngularVelocity
到加法器事件触发时你eDisplay
,所以后来
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
最后
reactimate $ (draw gears) <$> eAngle
是的,近似的积分作为总和是合适的,我在这里进一步作出有关的步幅可能有些不太准确assumtions接近,但很明显,并为您应该只要顺利eDisplay
是更多或更少的常规。