orbit/src/Lib.hs
2017-07-18 18:12:40 +02:00

97 lines
2.8 KiB
Haskell

module Lib (
gravity,
Body,
bodyDistance,
field,
acceleration,
update,
b1, b2, b3
) where
import Linear.Vector
import Linear.V3
import Linear.Affine
import Linear.Metric
--------------------------------------------------------------------------------
-- CONSTANTS
--------------------------------------------------------------------------------
-- Gravitational constant [m^3 kg^-1 s^-2]
gravity :: Double
gravity = 6.67408e-11
--------------------------------------------------------------------------------
-- BODY TYPE
--------------------------------------------------------------------------------
-- Body
data Body = Body {
bodyMass :: Double,
bodyPosition :: Point V3 Double,
bodySpeed :: V3 Double
} deriving (Show, Eq)
-- Distance between two bodies
bodyDistance :: Body -> Body -> Double
bodyDistance body1 body2 =
distance (bodyPosition body1) (bodyPosition body2)
--------------------------------------------------------------------------------
-- GRAVITY FORCE
--------------------------------------------------------------------------------
-- Field created by a body on a certain position
field :: Body -> Point V3 Double -> V3 Double
field body pos =
unP $ (gravity * m / r**2) *^ (normalize vec)
where m = bodyMass body
vec = (bodyPosition body) - pos
r = norm vec
-- Acceleration given to a body by its neighbours
acceleration :: Body -> [Body] -> V3 Double
acceleration body = foldr f (fromInteger 0)
where f neighbour acc =
acc + field neighbour (bodyPosition body)
--------------------------------------------------------------------------------
-- SIMULATION
--------------------------------------------------------------------------------
-- Update speed and position with using a timestep dt
update :: Double -> Body -> [Body] -> Body
update dt (Body m pos speed) neighbours =
Body m newpos newspeed
where accel = acceleration (Body m pos speed) neighbours
newspeed = speed + dt *^ accel
newpos = pos + dt *^ P newspeed
-- Update all bodies with a timestep dt
updateAll :: Double -> [Body] -> [Body]
updateAll dt bodies = aux [] [] bodies
where
-- Cycles through all bodies, updates each one and stores it in
-- res. Each body already updated is moved to prev.
aux res prev [] = res
aux res prev (b:next) =
aux (newb:res) (b:prev) next
where newb = update dt b $ prev ++ next
--------------------------------------------------------------------------------
-- EXAMPLES
--------------------------------------------------------------------------------
b1 = Body 42 (P $ V3 0 0 0) (V3 0 0 0)
b2 = Body 11 (P $ V3 1 2 3) (V3 0 0 0)
b3 = Body 5 (P $ V3 5 2 1) (V3 0 0 0)
-- Astronomical Unit
au :: Double
au = 149597870700
sun = Body 1.98855e30 (P $ V3 0 0 0) (V3 0 0 0)
earth = Body 8.97237e24 (P $ V3 au 0 0) (V3 0 29.78e3 0)