gps 0.5.4 → 0.6
raw patch · 2 files changed
+51/−36 lines, 2 filesdep −bytestringdep ~basedep ~prettydep ~prettyclass
Dependencies removed: bytestring
Dependency ranges changed: base, pretty, prettyclass
Files
- Data/GPS.hs +48/−30
- gps.cabal +3/−6
Data/GPS.hs view
@@ -1,22 +1,10 @@-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, EmptyDataDecls #-}--- |Author: Thomas DuBuisson--- Copyright: Thomas DuBuisson--- License: BSD3------ A basic GPS library with calculations for distance and speed along+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, EmptyDataDecls, BangPatterns #-}+-- |A basic GPS library with calculations for distance and speed along -- with helper functions for filtering/smoothing trails. All distances -- are in meters and time is in seconds. Speed is thus meters/second------ The current intent of this library is to--- 1) Provide a standard type class interface for coordinates--- 2) Include fleshed out support for relevant libraries, a task--- too often neglected in modern Hackage packages.------ Integration includes KML support via the xml package, pretty printing,--- anb binary. module Data.GPS- ( -- * Types and Classes+ ( -- * Types Distance , Heading , Speed@@ -28,17 +16,26 @@ , east , west , radiusOfEarth- -- * Helper Functions+ -- * Coordinate Functions , heading- , restLocations- , closestDistance- , getRadianPair+ , distance+ , speed , addVector+ , getRadianPair+ , getDMSPair , divideArea+ -- * Trail Functions+ , totalDistance+ , restLocations+ , closestDistance+ , filterByMaxSpeed , convexHull+ -- * Other helpers+ , readGPX , module Data.Geo.GPX ) where +import Data.Function (on) import Data.Ord (comparing) import Data.List (sort, mapAccumL, minimumBy, maximumBy, sortBy) import Data.Geo.GPX hiding (none, cmt)@@ -49,6 +46,7 @@ import Data.Time import Data.Maybe (listToMaybe) import Data.Fixed+import Control.Monad -- |Distances are expressed in meters type Distance = Double@@ -76,6 +74,10 @@ (lat1, lon1) = getRadianPairD a (lat2, lon2) = getRadianPairD b +-- | Find the total distance traveled+totalDistance :: (Lat a, Lon a) => [a] -> Distance+totalDistance as = sum $ zipWith distance as (drop 1 as)+ -- | Direction two points aim toward (0 = North, pi/2 = West, pi = South, 3pi/2 = East) heading :: (Lat a, Lon a) => a -> a -> Heading -- ^ 0 = North, pi/2 = West... heading a b =@@ -89,13 +91,21 @@ getVector :: (Lat a, Lon a) => a -> a -> Vector getVector a b = (distance a b, heading a b) --- | Speed in meters per second+-- | Speed in meters per second, only if a 'Time' was recorded for each waypoint. speed :: (Lat loc, Lon loc, Time loc) => loc -> loc -> Maybe Speed speed a b = case (getUTCTime b, getUTCTime a) of (Just x, Just y) -> Just $ realToFrac (diffUTCTime x y) / (distance a b) _ -> Nothing +-- |Filter out all points that result in a speed greater than a given value+-- (the second point is dropped)+filterByMaxSpeed :: (Lat loc, Lon loc, Time loc) => Speed -> Trail loc -> Trail loc+filterByMaxSpeed mx xs =+ let ss = zipWith speed xs (drop 1 xs)+ fs = filter ((< Just mx) . fst) (zip ss $ drop 1 xs)+ in take 1 xs ++ map snd fs+ data TempTrail a = T (Trail a) a -- |radius of the earth in meters@@ -141,6 +151,9 @@ getRadianPairD :: (Lat c, Lon c) => c -> (Double,Double) getRadianPairD = (\(a,b) -> (realToFrac a, realToFrac b)) . getRadianPair +getDMSPair :: (Lat c, Lon c) => c -> (LatitudeType, LongitudeType)+getDMSPair c = (lat c, lon c)+ -- |Provides a lat/lon pair of doubles in radians getRadianPair :: (Lat p, Lon p) => p -> (LatitudeType, LongitudeType) getRadianPair p = (t, g)@@ -174,14 +187,14 @@ where go [] = [] go (a:as) =- let (lst, close, far) = takeWhileLast ((<= d) . distance a) as- in case lst of- Just x -> case (getUTCTime a, getUTCTime x) of- (Just a', Just x') ->- let d = diffUTCTime a' x'- in if d >= s then close : go far else go as+ case takeWhileLast ((<=) d . distance a) as of+ (Just l, close, far) ->+ case (getUTCTime a, getUTCTime l) of+ (Just t1, Just t2) ->+ let diff = diffUTCTime t2 t1+ in if diff >= s then (a:close) : go far else go as _ -> go as- Nothing -> go as+ _ -> go as takeWhileLast :: (a -> Bool) -> [a] -> (Maybe a, [a], [a]) takeWhileLast p [] = (Nothing, [], [])@@ -189,10 +202,10 @@ | not (p x) = (Nothing, [], x:xs) | otherwise = go x xs where- go a [] = (Just a, [a], [])- go a (b:bs)+ go !a [] = (Just a, [], [])+ go !a (b:bs) | p b = let (c,d,f) = go b bs in (c, a:d, f)- | otherwise = (Just a, [a], b:bs)+ | otherwise = (Just a, [], b:bs) -- |Returns the closest distance between two trails (or Nothing if a trail is empty) -- O( (n * m) * log (n * m) )@@ -212,6 +225,11 @@ columnOne = takeWhile ( (<= west) . heading se) . iterate (addVector (vDist, south)) $ nw buildRow = takeWhile ((>= north) . heading se) . iterate (addVector (hDist, east)) in map buildRow columnOne++-- |Reads a GPX file (using the GPX library) by simply concatenating all the+-- tracks, segments, and points ('trkpts', 'trksegs', 'trks') into a single 'Trail'.+readGPX :: FilePath -> IO (Trail WptType)+readGPX = liftM (concatMap trkpts . concatMap trksegs . concatMap trks) . readGpxFile -- | Uses Grahams scan to compute the convex hull of the given points. -- This operation requires sorting of the points, so don't try it unless
gps.cabal view
@@ -1,5 +1,5 @@ name: gps-version: 0.5.4+version: 0.6 license: BSD3 license-file: LICENSE author: Thomas DuBuisson <thomas.dubuisson@gmail.com>@@ -13,12 +13,9 @@ tested-with: GHC == 6.10.3 extra-source-files: -Flag small_base- Description: Choose the split-up base package.- Library- Build-Depends: base >= 4 && < 6, bytestring >= 0.9 && < 1.0,- pretty >= 1.0 && < 1.1 , prettyclass >= 1.0 && < 1.1,+ Build-Depends: base >= 3 && < 6,+ pretty >= 1.0 , prettyclass >= 1.0, time >= 1.1 && < 1.3, GPX == 0.4.*, hxt >= 8.5, xsd == 0.3.* hs-source-dirs: exposed-modules: Data.GPS