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

- type Distance = Double
- type Heading = Double
- type Speed = Double
- type Vector = (Distance, Heading)
- type Trail a = [a]
- north :: Heading
- south :: Heading
- east :: Heading
- west :: Heading
- radiusOfEarth :: Double
- circumferenceOfEarth :: Double
- heading :: (Lat a, Lon a, Lat b, Lon b) => a -> b -> Heading
- distance :: (Lat a, Lon a, Lat b, Lon b) => a -> b -> Distance
- speed :: (Lat loc, Lon loc, Time loc, Lat b, Lon b, Time b) => loc -> b -> Maybe Speed
- getVector :: (Lat a, Lon a, Lat b, Lon b) => a -> b -> Vector
- addVector :: (Lat c, Lon c) => Vector -> c -> c
- getRadianPair :: (Lat p, Lon p) => p -> (LatitudeType, LongitudeType)
- getDMSPair :: (Lat c, Lon c) => c -> (LatitudeType, LongitudeType)
- divideArea :: (Lat c, Lon c) => Distance -> Distance -> c -> c -> [[c]]
- interpolate :: (Lat a, Lon a) => a -> a -> Double -> a
- writeGPX :: FilePath -> Trail WptType -> IO ()
- readGPX :: FilePath -> IO (Trail WptType)
- readGPXSegments :: FilePath -> IO [Trail WptType]
- getUTCTime :: Time a => a -> Maybe UTCTime
- module Data.Geo.GPX
- data AvgMethod c
- = AvgMean
- | AvgHarmonicMean
- | AvgGeometricMean
- | AvgMedian
- | AvgEndPoints
- | AvgMinOf [AvgMethod c]
- | AvgWith ([c] -> Speed)

- data Selected a
- isSelected :: Selected a -> Bool
- isNotSelected :: Selected a -> Bool
- onSelected :: (a -> b) -> (a -> b) -> Selected a -> b
- selLength :: Selected [a] -> Int
- totalDistance :: (Lat a, Lon a) => [a] -> Distance
- totalTime :: Time a => Trail a -> NominalDiffTime
- avgSpeeds :: (Lat a, Lon a, Time a) => NominalDiffTime -> Trail a -> [(UTCTime, Speed)]
- slidingAverageSpeed :: (Lat a, Lon a, Time a) => AvgMethod a -> NominalDiffTime -> Trail a -> [(UTCTime, Speed)]
- closestDistance :: (Lat a, Lon a) => Trail a -> Trail a -> Maybe Distance
- convexHull :: (Eq c, Lat c, Lon c) => [c] -> [c]
- bezierCurveAt :: (Lat a, Lon a, Time a) => [UTCTime] -> Trail a -> Trail a
- bezierCurve :: (Lat a, Lon a, Time a) => [Selected (Trail a)] -> Trail a
- linearTime :: (Lon a, Lat a, Time a) => [a] -> [a]
- filterPoints :: PointGrouping a -> Trail a -> Trail a
- betweenSpeeds :: (Lat a, Lon a, Time a) => Double -> Double -> PointGrouping a
- restLocations :: (Lat a, Lon a, Time a) => Distance -> NominalDiffTime -> PointGrouping a
- spansTime :: (Lat a, Lon a, Time a) => NominalDiffTime -> PointGrouping a
- everyNPoints :: Int -> PointGrouping a
- intersectionOf :: (Lat a, Lon a, Time a) => [PointGrouping a] -> PointGrouping a
- invertSelection :: TransformGrouping a
- firstGrouping :: TransformGrouping a
- lastGrouping :: TransformGrouping a
- unionOf :: (Lat a, Lon a, Time a) => [PointGrouping a] -> PointGrouping a
- refineGrouping :: PointGrouping a -> TransformGrouping a
- (/\) :: [Selected (Trail a)] -> TransformGrouping a
- (\/) :: [Selected (Trail a)] -> TransformGrouping a
- smoothRests :: (Lat a, Lon a, Time a) => Trail a -> Trail a
- smoothSegments :: (Lat a, Lon a, Time a) => Trail a -> Trail a
- bezierPoint :: (Lat a, Lon a) => [a] -> Double -> a

# Types

Angles are expressed in radians from North.
0 == North
pi/2 == West
pi == South
(3*2)pi == East == - (pi * 2)

# Constants

radius of the earth in meters

circumferenceOfEarth :: DoubleSource

Circumference of earht (meters)

# Coordinate Functions

heading :: (Lat a, Lon a, Lat b, Lon b) => a -> b -> HeadingSource

Direction two points aim toward (0 = North, pi*2 = West, pi = South, 3pi*2 = East)

speed :: (Lat loc, Lon loc, Time loc, Lat b, Lon b, Time b) => loc -> b -> Maybe SpeedSource

Speed in meters per second, only if a `Time`

was recorded for each waypoint.

addVector :: (Lat c, Lon c) => Vector -> c -> cSource

Given a vector and coordinate, computes a new coordinate. Within some epsilon it should hold that if

dest = addVector (dist,heading) start

then

heading == heading start dest

dist == distance start dest

getRadianPair :: (Lat p, Lon p) => p -> (LatitudeType, LongitudeType)Source

Provides a lat/lon pair of doubles in radians

getDMSPair :: (Lat c, Lon c) => c -> (LatitudeType, LongitudeType)Source

divideArea :: (Lat c, Lon c) => Distance -> Distance -> c -> c -> [[c]]Source

`divideArea vDist hDist nw se`

divides an area into a grid of equally
spaced coordinates within the box drawn by the northwest point (nw) and
southeast point (se). Because this uses floating point there might be a
different number of points in some rows (the last might be too far east based
on a heading from the se point).

interpolate :: (Lat a, Lon a) => a -> a -> Double -> aSource

# IO helpers

# Utility

getUTCTime :: Time a => a -> Maybe UTCTimeSource

module Data.Geo.GPX

# Types

AvgMean | Obtain the |

AvgHarmonicMean | Obtain the |

AvgGeometricMean | Obtain the |

AvgMedian | Obtain the median of the considered points |

AvgEndPoints | Compute the speed considering only the given endpoints |

AvgMinOf [AvgMethod c] | Take the minimum of the speeds from the given methods |

AvgWith ([c] -> Speed) |

# Utility Functions

isSelected :: Selected a -> BoolSource

isNotSelected :: Selected a -> BoolSource

onSelected :: (a -> b) -> (a -> b) -> Selected a -> bSource

# Trail Functions

## Queries

totalDistance :: (Lat a, Lon a) => [a] -> DistanceSource

Find the total distance traveled

totalTime :: Time a => Trail a -> NominalDiffTimeSource

avgSpeeds :: (Lat a, Lon a, Time a) => NominalDiffTime -> Trail a -> [(UTCTime, Speed)]Source

`avgSpeeds n points`

Average speed using a window of up to `n`

seconds and averaging by taking the
Median (`AvgMedian`

).

slidingAverageSpeed :: (Lat a, Lon a, Time a) => AvgMethod a -> NominalDiffTime -> Trail a -> [(UTCTime, Speed)]Source

`slidingAverageSpeed m n`

Average speed using a moving window of up to `n`

seconds
and an `AvgMethod`

of `m`

.

closestDistance :: (Lat a, Lon a) => Trail a -> Trail a -> Maybe DistanceSource

Returns the closest distance between two trails (or Nothing if a trail is empty). Inefficient implementation: O( (n * m) * log (n * m) )

convexHull :: (Eq c, Lat c, Lon c) => [c] -> [c]Source

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 you have notably more memory than the list of points will consume.

## Transformations

bezierCurveAt :: (Lat a, Lon a, Time a) => [UTCTime] -> Trail a -> Trail aSource

Construct a bezier curve using the provided trail. Construct a new trail by sampling the given bezier curve at the given times. The current implementation assumes the times of the input coordinates are available and all equal (Ex: all points are 5 seconds apart), the results will be poor if this is not the case!

bezierCurve :: (Lat a, Lon a, Time a) => [Selected (Trail a)] -> Trail aSource

Interpolate selected points onto a bezier curve. Note this gets exponentially more expensive with the length of the segement being transformed - it is not advisable to perform this operation on trail segements with more than ten points!

linearTime :: (Lon a, Lat a, Time a) => [a] -> [a]Source

Filters out any points that go backward in time (thus must not be valid if this is a trail)

filterPoints :: PointGrouping a -> Trail a -> Trail aSource

Remove all points that remain `NotSelect`

ed by the given grouping algorithm.

## Grouping Methods

betweenSpeeds :: (Lat a, Lon a, Time a) => Double -> Double -> PointGrouping aSource

Groups trail segments into contiguous points within the speed and all others outside of the speed. The speed from point p(i) to p(i+1) is associated with p(i) (execpt for the first speed value, which is associated with both the first and second point)

restLocations :: (Lat a, Lon a, Time a) => Distance -> NominalDiffTime -> PointGrouping aSource

A rest point means the coordinates remain within a given distance for at least a particular amount of time.

spansTime :: (Lat a, Lon a, Time a) => NominalDiffTime -> PointGrouping aSource

chunking points into groups spanning at most the given time interval.

everyNPoints :: Int -> PointGrouping aSource

chunk the trail into groups of N points

## Group Transformations

intersectionOf :: (Lat a, Lon a, Time a) => [PointGrouping a] -> PointGrouping aSource

intersects the given groupings

invertSelection :: TransformGrouping aSource

Inverts the selected/nonselected segments

firstGrouping :: TransformGrouping aSource

`firstGrouping f ps`

only the first segment remains `Select`

ed, and only
if it was already selected by `f`

.

lastGrouping :: TransformGrouping aSource

Only the last segment, if any, is selected (note: the current
implementation is inefficient, using `reverse`

)

unionOf :: (Lat a, Lon a, Time a) => [PointGrouping a] -> PointGrouping aSource

Union all the groupings

refineGrouping :: PointGrouping a -> TransformGrouping aSource

For every selected group, refine the selection using the second
grouping method. This differs from `IntersectionOf`

by restarting
the second grouping algorithm at the beginning each group selected
by the first algorithm.

## Composite Operations (Higher Level)

# Misc

bezierPoint :: (Lat a, Lon a) => [a] -> Double -> aSource