RosettaCodeData/Task/Animate-a-pendulum/Haskell/animate-a-pendulum-2.hs

52 lines
2.2 KiB
Haskell

import Graphics.Gloss
-- Initial conditions
g_ = (-9.8) :: Float --Gravity acceleration
v_0 = 0 :: Float --Initial tangential speed
a_0 = 0 / 180 * pi :: Float --Initial angle
dt = 0.01 :: Float --Time step
t_f = 15 :: Float --Final time for data logging
l_ = 200 :: Float --Rod length
-- Define a type to represent the pendulum:
type Pendulum = (Float, Float, Float) -- (rod length, tangential speed, angle)
-- Pendulum's initial state
initialstate :: Pendulum
initialstate = (l_, v_0, a_0)
-- Step funtion: update pendulum to new position
movePendulum :: Float -> Pendulum -> Pendulum
movePendulum dt (l,v,a) = ( l , v_2 , a + v_2 / l * dt*10 )
where v_2 = v + g_ * (cos a) * dt
-- Convert from Pendulum to [Picture] for display
renderPendulum :: Pendulum -> [Picture]
renderPendulum (l,v,a) = map (uncurry Translate newOrigin)
[ Line [ ( 0 , 0 ) , ( l * (cos a), l * (sin a) ) ]
, polygon [ ( 0 , 0 ) , ( -5 , 8.66 ) , ( 5 , 8.66 ) ]
, Translate ( l * (cos a)) (l * (sin a)) (circleSolid (0.04*l_))
, Translate (-1.1*l) (-1.3*l) (Scale 0.1 0.1 (Text currSpeed))
, Translate (-1.1*l) (-1.3*l + 20) (Scale 0.1 0.1 (Text currAngle))
]
where currSpeed = "Speed (pixels/s) = " ++ (show v)
currAngle = "Angle (deg) = " ++ (show ( 90 + a / pi * 180 ) )
-- New origin to beter display the animation
newOrigin = (0, l_ / 2)
-- Calcule a proper window size (for angles between 0 and -pi)
windowSize :: (Int, Int)
windowSize = ( 300 + 2 * round (snd newOrigin)
, 200 + 2 * round (snd newOrigin) )
-- Run simulation
main :: IO ()
main = do --plotOnGNU
simulate window background fps initialstate render update
where window = InWindow "Animate a pendulum" windowSize (40, 40)
background = white
fps = round (1/dt)
render xs = pictures $ renderPendulum xs
update _ = movePendulum