Write up initial Cow DSL.
This commit is contained in:
commit
321df82944
99
src/Cdl/Cow.hs
Normal file
99
src/Cdl/Cow.hs
Normal file
|
@ -0,0 +1,99 @@
|
|||
module Cdl.Cow where
|
||||
import Control.Monad.State
|
||||
import Data.Fixed
|
||||
import Data.List
|
||||
|
||||
data Coord = Coord
|
||||
{ longitude :: Float
|
||||
, latitude :: Float
|
||||
}
|
||||
|
||||
data CowState = CowState
|
||||
{ id :: Int
|
||||
, samplingFrequency :: Float
|
||||
, movementSpeed :: Float
|
||||
, movementDirection :: Float
|
||||
, position :: Coord
|
||||
, time :: Float
|
||||
, dataPoints :: [Coord]
|
||||
}
|
||||
|
||||
type CowBehavior = State CowState
|
||||
|
||||
type Collar = (Int, Float, Coord, CowBehavior ())
|
||||
type DataPoint = (Int, Coord)
|
||||
|
||||
emitPoint :: Coord -> CowBehavior ()
|
||||
emitPoint c = modify (\s -> s { dataPoints = c : dataPoints s })
|
||||
|
||||
setPosition :: Coord -> CowBehavior ()
|
||||
setPosition c = modify (\s -> s { position = c })
|
||||
|
||||
setDirection :: Float -> CowBehavior ()
|
||||
setDirection d = modify (\s -> s { movementDirection = d })
|
||||
|
||||
increaseTime :: Float -> CowBehavior ()
|
||||
increaseTime t = modify (\s -> s { time = time s + t })
|
||||
|
||||
repeatUntil :: (CowState -> Bool) -> CowBehavior a -> CowBehavior a
|
||||
repeatUntil p m = ((,) <$> m <*> gets p) >>= (\(a,b) -> if b then return a else m)
|
||||
|
||||
repeatTimes :: Int -> CowBehavior a -> CowBehavior ()
|
||||
repeatTimes n m = sequence_ $ replicate n m
|
||||
|
||||
addOffset :: (Float, Float) -> Coord -> Coord
|
||||
addOffset (x, y) c = Coord (longitude c + longitudeDelta) (latitude c + latitudeDelta)
|
||||
where
|
||||
latitudeDelta = y / 111111
|
||||
longitudeDelta = x / (111111 * cos (latitude c))
|
||||
|
||||
samplingDeltas :: Float -> CowBehavior [Float]
|
||||
samplingDeltas t = do
|
||||
currentTime <- gets time
|
||||
frequency <- gets samplingFrequency
|
||||
let firstDelta = (frequency * fromIntegral (ceiling (currentTime/frequency))) - currentTime
|
||||
return $ takeWhile (< t) [firstDelta + frequency*i | i <- [0..]]
|
||||
|
||||
move :: Float -> CowBehavior ()
|
||||
move d = do
|
||||
speed <- gets movementSpeed
|
||||
dir <- gets movementDirection
|
||||
pos <- gets position
|
||||
let movementTime = d/speed
|
||||
deltas <- samplingDeltas movementTime
|
||||
let coords = map (\d -> addOffset (speed * d * cos dir, speed * d * sin dir) pos) deltas
|
||||
let finalPos = addOffset (d * cos dir, d * sin dir) pos
|
||||
mapM emitPoint coords
|
||||
increaseTime movementTime
|
||||
setPosition finalPos
|
||||
|
||||
turn :: Float -> CowBehavior ()
|
||||
turn a = do
|
||||
dir <- gets movementDirection
|
||||
let newDir = dir + (a/180 * pi)
|
||||
setDirection (newDir `mod'` (2*pi))
|
||||
|
||||
wait :: Float -> CowBehavior ()
|
||||
wait t = do
|
||||
deltas <- samplingDeltas t
|
||||
pos <- gets position
|
||||
mapM (const $ emitPoint pos) deltas
|
||||
increaseTime t
|
||||
|
||||
runCow :: Float -> Collar -> [DataPoint]
|
||||
runCow f (id, speed, pos, behavior) = zip (cycle [id]) coords
|
||||
where
|
||||
coords = reverse (position finalState : dataPoints finalState)
|
||||
finalState = snd $ runState behavior initialState
|
||||
initialState = CowState
|
||||
{ Cdl.Cow.id = id
|
||||
, samplingFrequency = f
|
||||
, movementSpeed = speed
|
||||
, movementDirection = 0
|
||||
, position = pos
|
||||
, time = 0
|
||||
, dataPoints = []
|
||||
}
|
||||
|
||||
runCows :: Float -> [Collar] -> [[DataPoint]]
|
||||
runCows f cs = transpose $ map (runCow f) $ cs
|
Loading…
Reference in New Issue
Block a user