1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
{-# LANGUAGE BangPatterns #-}
-- | Massful bodies in the simulation.
module Body
( Velocity
, Accel
, MassPoint
, Body
, unitBody
, massPointOfBody
, setMassOfBody
, setAccelOfBody
, setStartVelOfBody
, advanceBody)
where
import Util
-- Types ----------------------------------------------------------------------
-- We're using tuples instead of ADTs so we can put them in unboxed vectors.
-- | The velocity of a point.
type Velocity = (Double, Double)
-- | The acceleration of a point.
type Accel = (Double, Double)
-- | A point in 2D space with its mass.
type MassPoint = (Double, Double, Double)
-- | Bodies consist of a MassPoint, but also carry their velocity
-- and acceleration between steps of the simulation.
type Body = (MassPoint, Velocity, Accel)
-- Body -----------------------------------------------------------------------
-- | Make a body with unit mass and zero vel and acc.
unitBody :: Double -> Double -> Body
unitBody x y
= ((x, y, 1), (0, 0), (0, 0))
-- | Take the MassPoint of a body.
massPointOfBody :: Body -> MassPoint
massPointOfBody (mp, vel, acc)
= mp
-- | Set the mass of a body.
setMassOfBody :: Double -> Body -> Body
setMassOfBody mass ((x, y, _), vel, acc)
= ((x, y, mass), vel, acc)
-- | Set the acceleration of a body.
setAccelOfBody :: Accel -> Body -> Body
setAccelOfBody acc' (mp, vel, _)
= (mp, vel, acc')
-- | Set the starting velocity of a body.
-- It is set to rotate around the origin, with the speed proportional
-- to the sqrt of the distance from it. This seems to make nice simulations.
setStartVelOfBody :: Double -> Body -> Body
setStartVelOfBody startVel (mp@(x, y, mass), vel, acc)
= let pos = (x, y)
(x', y') = normaliseV (x, y)
vel' = (y', -x')
vel'' = mulSV (sqrt (magV pos) * startVel) vel'
in (mp, vel'', acc)
-- | Advance a body forwards in time.
advanceBody :: Double -> Body -> Body
advanceBody time
( (px, py, mass)
, (vx, vy)
, acc@(ax, ay))
= ( (px + time * vx, py + time * vy, mass)
, (vx + time * ax, vy + time * ay)
, acc)
|