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