Point.elm (2739B)
1 module Point exposing(Point, decoder, downsample, duration, subseq, startTime, centre) 2 3 import Json.Decode as D 4 import Pos exposing (Pos) 5 6 7 type alias Point = 8 { time : Float 9 , pos : Pos 10 , cadence : Maybe Int 11 , power : Maybe Int 12 , heartRate : Maybe Int 13 } 14 15 posDecoder : D.Decoder Pos 16 posDecoder = D.map3 Pos 17 (D.field "lat" D.float) 18 (D.field "lon" D.float) 19 (D.field "ele" (D.maybe D.float)) 20 21 22 decoder : D.Decoder Point 23 decoder = D.map5 Point 24 (D.field "time" D.float) 25 (D.field "pos" posDecoder) 26 (D.field "cadence" (D.maybe D.int)) 27 (D.field "power" (D.maybe D.int)) 28 (D.field "heartRate" (D.maybe D.int)) 29 30 31 last x xs = 32 case xs of 33 [] -> x 34 (x_::xs_) -> last x_ xs_ 35 36 -- divide the points into n equal time buckets and return the first 37 -- point in each 38 downsample : Int -> List Point -> List Point 39 downsample n points = 40 let 41 nextpoint step prev points_ = 42 case points_ of 43 (next::rest) -> 44 if next.time - prev.time > step 45 then prev :: (nextpoint step next rest) 46 else nextpoint step prev rest 47 _ -> [prev] 48 in 49 case points of 50 (first::rest) -> 51 let step = (duration points) / (toFloat n) 52 in nextpoint step first rest 53 [] -> [] 54 55 duration : List Point -> Float 56 duration points = 57 case points of 58 (p::ps) -> (last p ps).time - p.time 59 _ -> 0 60 61 startTime : List Point -> Maybe Float 62 startTime points = 63 case points of 64 (p::_) -> Just p.time 65 _ -> Nothing 66 67 type Bound = Bound Pos Pos | NoBound 68 69 extendBound : Pos -> Bound -> Bound 70 extendBound pos b = 71 let {lat, lon} = pos 72 in case b of 73 (Bound p1 p2) -> 74 Bound 75 (Pos (min lat p1.lat) (min lon p1.lon) Nothing) 76 (Pos (max lat p2.lat) (max lon p2.lon) Nothing) 77 NoBound -> 78 Bound pos pos 79 80 bounds : List Point -> Bound 81 bounds points = 82 List.foldr extendBound NoBound (List.map .pos points) 83 84 centre : List Point -> Pos 85 centre points = 86 case bounds points of 87 Bound min max -> Pos 88 ((max.lat + min.lat) / 2) 89 ((max.lon + min.lon) / 2) 90 Nothing 91 NoBound -> Pos 0 0 Nothing 92 93 subseq : List Point -> Float -> Float -> List Point 94 subseq points start dur = 95 case points of 96 [] -> [] 97 (p::ps) -> 98 if p.time < start 99 then subseq ps start dur 100 else if p.time >= (start + dur) 101 then [] 102 else p::(subseq ps start dur)