Animate a pendulum: Difference between revisions

(+ Haskell)
Line 293:
MAIN: pendulum-main
</lang>
 
=={{header|F_Sharp|F#}}==
A nice application of F#'s support for units of measure.
<lang fsharp>open System
open System.Drawing
open System.Windows.Forms
 
// define units of measurement
[<Measure>] type m; // metres
[<Measure>] type s; // seconds
[<Measure>] type ms; // milliseconds
 
// a pendulum is represented as a record of physical quantities
type Pendulum =
{ length : float<m>
gravity : float<m/s^2>
velocity : float<m/s>
angle : float
}
 
// calculate the next state of a pendulum
let next pendulum deltaT : Pendulum =
let k = -pendulum.gravity / pendulum.length
let acceleration = k * Math.Sin pendulum.angle * 1.0<m>
let newVelocity = pendulum.velocity + acceleration * deltaT
let newAngle = pendulum.angle + newVelocity * deltaT / 1.0<m>
{ pendulum with velocity = newVelocity; angle = newAngle }
 
// paint a pendulum (using hard-coded screen coordinates)
let paint pendulum (gr: System.Drawing.Graphics) =
let homeX = 160
let homeY = 50
let length = 140.0
// draw plate
gr.DrawLine( new Pen(Brushes.Gray, width=2.0f), 0, homeY, 320, homeY )
// draw pivot
gr.FillEllipse( Brushes.Gray, homeX-5, homeY-5, 10, 10 )
gr.DrawEllipse( new Pen(Brushes.Black), homeX-5, homeY-5, 10, 10 )
// draw the pendulum itself
let x = homeX + int( length * Math.Sin pendulum.angle )
let y = homeY + int( length * Math.Cos pendulum.angle )
// draw rod
gr.DrawLine( new Pen(Brushes.Black, width=3.0f), homeX, homeY, x, y )
// draw bob
gr.FillEllipse( Brushes.Yellow, x-15, y-15, 30, 30 )
gr.DrawEllipse( new Pen(Brushes.Black), x-15, y-15, 30, 30 )
 
// defines an operator "-?" that calculates the time from t2 to t1
// where t2 is optional
let (-?) (t1: DateTime) (t2: DateTime option) : float<s> =
match t2 with
| None -> 0.0<s> // only one timepoint given -> difference is 0
| Some t -> (t1 - t).TotalSeconds * 1.0<s>
 
// our main window is double-buffered form that reacts to paint events
type PendulumForm() as self =
inherit Form(Width=325, Height=240, Text="Pendulum")
let mutable pendulum = { length = 1.0<m>;
gravity = 9.81<m/s^2>
velocity = 0.0<m/s>
angle = Math.PI / 2.0
}
let mutable lastPaintedAt = None
let updateFreq = 10<ms>
 
do self.DoubleBuffered <- true
self.Paint.Add( fun args ->
let now = DateTime.Now
let deltaT = now -? lastPaintedAt |> min 0.01<s>
lastPaintedAt <- Some now
 
pendulum <- next pendulum deltaT
 
let gr = args.Graphics
gr.Clear( Color.LightGray )
paint pendulum gr
 
// initiate a new paint event after a while (non-blocking)
async { do! Async.Sleep( updateFreq / 1<ms> )
self.Invalidate()
}
|> Async.Start
)
 
[<STAThread>]
Application.Run( new PendulumForm( Visible=true ) )</lang>
 
=={{header|Haskell}}==
Anonymous user