gps 1.1 → 1.2
raw patch · 6 files changed
+93/−83 lines, 6 filesdep +textdep −GPXdep −hxtdep −xsddep ~gpx-conduitdep ~test-frameworkdep ~test-framework-quickcheck2PVP ok
version bump matches the API change (PVP)
Dependencies added: text
Dependencies removed: GPX, hxt, xsd
Dependency ranges changed: gpx-conduit, test-framework, test-framework-quickcheck2
API changes (from Hackage documentation)
- Geo.Computations: readGPXFile :: FilePath -> IO (Maybe GPX)
+ Geo.Types: Point :: Latitude -> Longitude -> Maybe Double -> Maybe UTCTime -> Point
+ Geo.Types: Segment :: [Point] -> Segment
+ Geo.Types: Track :: Maybe Text -> Maybe Text -> [Segment] -> Track
+ Geo.Types: data Point
+ Geo.Types: data Segment
+ Geo.Types: data Track
+ Geo.Types: instance Eq Point
+ Geo.Types: instance Eq Segment
+ Geo.Types: instance Eq Track
+ Geo.Types: instance Ord Point
+ Geo.Types: instance Ord Segment
+ Geo.Types: instance Ord Track
+ Geo.Types: instance Read Point
+ Geo.Types: instance Read Segment
+ Geo.Types: instance Read Track
+ Geo.Types: instance Show Point
+ Geo.Types: instance Show Segment
+ Geo.Types: instance Show Track
+ Geo.Types: pntEle :: Point -> Maybe Double
+ Geo.Types: pntLat :: Point -> Latitude
+ Geo.Types: pntLon :: Point -> Longitude
+ Geo.Types: pntTime :: Point -> Maybe UTCTime
+ Geo.Types: points :: Segment -> [Point]
+ Geo.Types: pt :: Latitude -> Longitude -> Maybe Double -> Maybe UTCTime -> Point
+ Geo.Types: segments :: Track -> [Segment]
+ Geo.Types: trkDescription :: Track -> Maybe Text
+ Geo.Types: trkName :: Track -> Maybe Text
+ Geo.Types: type Latitude = Double
+ Geo.Types: type Longitude = Double
+ Geo.Types: zeroPoint :: Point
- Geo.Computations: data Point :: *
+ Geo.Computations: data Point
Files
- Geo/Computations.hs +2/−0
- Geo/Computations/Basic.hs +16/−18
- Geo/Computations/Trail.hs +2/−1
- Geo/Types.hs +35/−0
- Test/GpsTest.hs +19/−45
- gps.cabal +19/−19
Geo/Computations.hs view
@@ -6,7 +6,9 @@ module Geo.Computations ( module Geo.Computations.Basic , module Geo.Computations.Trail+ , module Geo.Types ) where import Geo.Computations.Basic import Geo.Computations.Trail+import Geo.Types
Geo/Computations/Basic.hs view
@@ -27,22 +27,20 @@ , circleIntersectionPoints , intersectionArcsOf , maximumDistanceOfArc- -- * IO helpers- , readGPXFile ) where import Data.Time import Data.Maybe-import Geo.GPX.Conduit+import Geo.Types -- |Distances are expressed in meters type Distance = Double -- |Angles are expressed in radians from North.--- 0 == North--- pi/2 == West--- pi == South--- (3/2)pi == East == - (pi / 2)+-- 0 == North+-- pi/2 == West+-- pi == South+-- (3/2)pi == East == - (pi / 2) type Heading = Double -- |Speed is hard coded as meters per second@@ -71,8 +69,8 @@ -- | Direction two points aim toward (0 = North, pi/2 = West, pi = South, 3pi/2 = East) heading :: Point -> Point -> Heading heading a b =- atan2 (sin (diffLon) * cos (lat2))- (cos(lat1) * sin (lat2) - sin(lat1) * cos lat2 * cos (diffLon))+ atan2 (sin (diffLon) * cos (lat2))+ (cos(lat1) * sin (lat2) - sin(lat1) * cos lat2 * cos (diffLon)) where (lat1, lon1) = getRadianPair a (lat2, lon2) = getRadianPair b@@ -84,23 +82,23 @@ -- |Given a vector and coordinate, computes a new coordinate. -- Within some epsilon it should hold that if ----- @dest = addVector (dist,heading) start@+-- @dest = addVector (dist,heading) start@ -- -- then ----- @heading == heading start dest@--- --- @dist == distance start dest@+-- @heading == heading start dest@+-- +-- @dist == distance start dest@ addVector :: Vector -> Point -> Point addVector (d,h) p = p { pntLon = toDegrees lon2- , pntLat = toDegrees lat2- }+ , pntLat = toDegrees lat2+ } where- (lat,lon) = getRadianPair p- lat2 = asin (sin lat * cos (d / radiusOfEarth) + cos lat+ (lat,lon) = getRadianPair p+ lat2 = asin (sin lat * cos (d / radiusOfEarth) + cos lat * sin(d/radiusOfEarth) * cos h)- lon2 = lon - atan2 (sin h * sin (d / radiusOfEarth) * cos lat)+ lon2 = lon + atan2 (sin h * sin (d / radiusOfEarth) * cos lat) (cos (d/radiusOfEarth) - sin lat * sin lat2) -- | Speed in meters per second, only if a 'Time' was recorded for each waypoint.
Geo/Computations/Trail.hs view
@@ -45,7 +45,7 @@ import Text.Show.Functions () import Geo.Computations.Basic-import Geo.GPX.Conduit ()+import Geo.Types import Control.Arrow (first) import Control.Monad@@ -55,6 +55,7 @@ import Data.Maybe import Data.Ord import Data.Time+ import Statistics.Function as F import Statistics.Sample
+ Geo/Types.hs view
@@ -0,0 +1,35 @@+module Geo.Types where+import Data.Text+import Data.Time++data Track = Track+ { trkName :: Maybe Text+ , trkDescription :: Maybe Text+ , segments :: [Segment]+ }+ deriving (Eq, Ord, Show, Read)++-- |A GPX segments is just a bundle of points.+data Segment = Segment { points :: [Point] }+ deriving (Eq, Ord, Show, Read)++type Latitude = Double+type Longitude = Double++-- |Track point is a full-fledged representation of all the data+-- available in most GPS loggers. It is possible you don't want+-- all this data and can just made do with coordinates (via 'Pnt')+-- or a custom derivative.+data Point = Point+ { pntLat :: Latitude+ , pntLon :: Longitude+ , pntEle :: Maybe Double -- ^ In meters+ , pntTime :: Maybe UTCTime+ -- , pntSpeed :: Maybe Double -- ^ Non-standard. Usually in meters/second.+ }+ deriving (Eq, Ord, Show, Read)++pt :: Latitude -> Longitude -> Maybe Double -> Maybe UTCTime -> Point+pt t g e m = Point t g e m++zeroPoint = Point 0 0 Nothing Nothing
Test/GpsTest.hs view
@@ -1,4 +1,4 @@-import Data.GPS+import Geo.Computations import Data.Time import Data.List import Data.Ord@@ -6,19 +6,9 @@ import Test.QuickCheck import Test.Framework (Test, defaultMain, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty)-import Text.XML.XSD.DateTime import Control.Applicative import Control.Monad -instance Arbitrary LatitudeType where- arbitrary = liftM (latitudeType . flip mod' 180) arbitrary--instance Arbitrary LongitudeType where- arbitrary = liftM (longitudeType . flip mod' 180) arbitrary--instance Arbitrary DateTime where- arbitrary = liftM fromUTCTime arbitrary- instance Arbitrary UTCTime where arbitrary = UTCTime <$> arbitrary <*> liftM (secondsToDiffTime . abs) (arbitrary :: Gen Integer) @@ -27,53 +17,35 @@ instance Arbitrary NominalDiffTime where arbitrary = liftM fromIntegral (arbitrary :: Gen Int)-instance Arbitrary WptType where++instance Arbitrary Point where arbitrary =- wptType <$> arbitrary -- Lat- <*> arbitrary -- Lon+ pt <$> fmap (`mod'` 90) arbitrary -- Lat+ <*> fmap (`mod'` 180) arbitrary -- Lon <*> arbitrary -- Time <*> arbitrary -- elevation- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return [] -- LinkType- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing- <*> return Nothing -newtype Trl = Trl [WptType]+newtype Trl = Trl [Point] deriving (Show) instance Arbitrary Trl where arbitrary = do- b <- arbitrary :: Gen [Int]- u_ts_d <- mapM (\i -> (,,) <$> arbitrary <*> replicateM i arbitrary <*> arbitrary) b :: Gen [(UTCTime, [WptType],NominalDiffTime)]- let u_ts_d' = sortBy (comparing (\(a,_,_) -> a)) u_ts_d- xs = concat [zipWith (setTime' . fromUTCTime) (iterate (addUTCTime d) u) x | (u,x,d) <- u_ts_d']- return $ Trl xs+ b <- (`mod` 5) `fmap` arbitrary :: Gen Int+ pnts <- mapM (\_ -> arbitrary) [0..abs b]+ return $ Trl (sortBy (comparing pntTime) pnts) -approxEq :: WptType -> WptType -> Bool+approxEq :: Point -> Point -> Bool approxEq a b = distance a b <= 0.2 -- error of 13cm has been observed due to floating point issues when using add vector. -pSaneDistance :: WptType -> WptType -> Bool+pSaneDistance :: Point -> Point -> Bool pSaneDistance a b = distance a b <= circumferenceOfEarth / 2 -pTriangleTheorem :: WptType -> WptType -> WptType -> Bool+pTriangleTheorem :: Point -> Point -> Point -> Bool pTriangleTheorem a b c = distance a b + distance b c >= distance a c -- Traditional flat-surface geometry || distance a b + distance b c + distance c a == 2 * pi * radiusOfEarth -pAddVector_DistanceHeading_ident :: WptType -> WptType -> Bool+pAddVector_DistanceHeading_ident :: Point -> Point -> Bool pAddVector_DistanceHeading_ident a b = let v = (distance a b, heading a b) c = addVector v a@@ -82,7 +54,7 @@ pConvexHull_Has_Extreme_Points :: Trl -> Bool pConvexHull_Has_Extreme_Points (Trl ts) = let ch = convexHull ts- ts' = sortBy (comparing lat) ts+ ts' = sortBy (comparing pntLat) ts northMost = last ts' southMost = head ts' in length ts < 3 || (northMost `elem` ch && southMost `elem` ch)@@ -105,9 +77,11 @@ , testProperty "TriangleTheorem" pTriangleTheorem , testProperty "Vector identity" pAddVector_DistanceHeading_ident ]- , testGroup "Trail Computations"- [ testProperty "Hull has extreme points" pConvexHull_Has_Extreme_Points- , testProperty "HullContainsBezier" pConvexHull_Bezier_Const]+-- These might make some sense in a local scope, but in a global range what+-- is the "left most" point? On a sphere what is a convex hull?+-- , testGroup "Trail Computations"+-- [ testProperty "Hull has extreme points" pConvexHull_Has_Extreme_Points+-- , testProperty "HullContainsBezier" pConvexHull_Bezier_Const] ]
gps.cabal view
@@ -1,16 +1,16 @@-name: gps-version: 1.1-license: BSD3-license-file: LICENSE-author: Thomas DuBuisson <thomas.dubuisson@gmail.com>-maintainer: Thomas DuBuisson-description: Useful for manipulating GPS coordinages (in various forms), building paths, and performing basic computations.-synopsis: For manipulating GPS coordinates and trails.-category: Data-stability: stable-build-type: Simple-cabal-version: >= 1.8-tested-with: GHC == 6.10.3+name: gps+version: 1.2+license: BSD3+license-file: LICENSE+author: Thomas DuBuisson <thomas.dubuisson@gmail.com>+maintainer: Thomas DuBuisson+description: Useful for manipulating GPS coordinages (in various forms), building paths, and performing basic computations.+synopsis: For manipulating GPS coordinates and trails.+category: Data+stability: stable+build-type: Simple+cabal-version: >= 1.8+tested-with: GHC == 6.10.3 extra-source-files: Library@@ -18,11 +18,11 @@ pretty >= 1.0, prettyclass >= 1.0, time >= 1.4,- gpx-conduit >= 0.1, vector >= 0.7,- statistics >= 0.9+ statistics >= 0.9,+ text hs-source-dirs:- exposed-modules: Geo.Computations+ exposed-modules: Geo.Computations, Geo.Types other-modules: Geo.Computations.Basic, Geo.Computations.Trail ghc-options: -Wall @@ -34,9 +34,9 @@ build-depends: base >= 4.0, QuickCheck >= 2.4.0.1,- test-framework >= 0.3.3 && < 0.5,- test-framework-quickcheck2 >= 0.2.9 && < 0.3,- time, GPX, hxt, xsd, vector, statistics, gps+ test-framework >= 0.3.3,+ test-framework-quickcheck2 >= 0.2.9,+ time, vector, statistics, gps, gpx-conduit ghc-options: -Wall source-repository head