module Point exposing(Pos, Point, decoder, downsample, duration, subseq, startTime, centre) import Json.Decode as D type alias Pos = { lat : Float , lon : Float , ele : Maybe Float } type alias Point = { time : Float , pos : Pos , cadence : Maybe Int , power : Maybe Int , heartRate : Maybe Int } posDecoder : D.Decoder Pos posDecoder = D.map3 Pos (D.field "lat" D.float) (D.field "lon" D.float) (D.field "ele" (D.maybe D.float)) decoder : D.Decoder Point decoder = D.map5 Point (D.field "time" D.float) (D.field "pos" posDecoder) (D.field "cadence" (D.maybe D.int)) (D.field "power" (D.maybe D.int)) (D.field "heartRate" (D.maybe D.int)) last x xs = case xs of [] -> x (x_::xs_) -> last x_ xs_ tracef x = Debug.log (String.fromFloat x) x -- divide the points into n equal time buckets and return the first -- point in each downsample n points = let nextpoint step prev points_ = case points_ of (next::rest) -> if next.time - prev.time > step then prev :: (nextpoint step next rest) else nextpoint step prev rest _ -> [prev] in case points of (first::rest) -> let step = (duration points) / (toFloat n) in nextpoint step first rest [] -> [] duration points = case points of (p::ps) -> (last p ps).time - p.time _ -> 0 startTime points = case points of (p::ps) -> Just p.time _ -> Nothing type Bound = Bound Pos Pos | NoBound extendBound : Pos -> Bound -> Bound extendBound pos b = let {lat, lon} = pos in case b of (Bound p1 p2) -> Bound (Pos (min lat p1.lat) (min lon p1.lon) Nothing) (Pos (max lat p2.lat) (max lon p2.lon) Nothing) NoBound -> Bound pos pos bounds points = List.foldr extendBound NoBound (List.map .pos points) centre points = case bounds points of Bound min max -> Pos ((max.lat + min.lat) / 2) ((max.lon + min.lon) / 2) Nothing NoBound -> Pos 0 0 Nothing subseq points start dur = case points of [] -> [] (p::ps) -> if p.time < start then subseq ps start dur else if p.time >= (start + dur) then [] else p::(subseq ps start dur)