97 lines
2.8 KiB
Haskell
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)
|