gps-1.0.2: For manipulating GPS coordinates and trails.

Data.GPS

Description

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

Synopsis

# Types

type Distance = DoubleSource

Distances are expressed in meters

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

type Speed = DoubleSource

Speed is hard coded as meters per second

type Trail a = [a]Source

type Circle a = (a, Distance)Source

Genearlly a circle indicates a known area in which we are searching (so a center point and maximum possible distance from that point)

An arc is represented as a circle, starting heading and ending heading

class (LatL a, LonL a) => Coordinate a whereSource

Methods

lat :: a -> DoubleSource

lon :: a -> DoubleSource

Instances

 Coordinate Wpt Coordinate Pt

# Constants

South, being 180 degrees from North, is pi.

East is 270 degrees (3 pi / 2)

West is 90 degrees (pi/2)

radius of the earth in meters

Circumference of earth (meters)

# Coordinate Functions

heading :: (Coordinate a, Coordinate b) => a -> b -> HeadingSource

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

speed :: (Coordinate loc, TimeL loc, Coordinate b, TimeL b) => loc -> b -> Maybe SpeedSource

Speed in meters per second, only if a `Time` was recorded for each waypoint.

addVector :: Coordinate 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 :: Coordinate p => p -> (Latitude, Longitude)Source

Provides a lat/lon pair of doubles in radians

divideArea :: Coordinate 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 :: Coordinate a => a -> a -> Double -> aSource

`interpolate c1 c2 w` where `0 <= w <= 1` Gives a point on the line between c1 and c2 equal to c1 when `w == 0` (weighted linearly toward c2).

circleIntersectionPoints :: Coordinate a => (a, Distance) -> (a, Distance) -> Maybe (a, a)Source

Compute the points at which two circles intersect (assumes a flat plain). If the circles do not intersect or are identical then the result is `Nothing`.

intersectionArcsOf :: Coordinate a => [Circle a] -> [Arc a]Source

Find the area in which all given circles intersect. The resulting area is described in terms of the bounding arcs. All cirlces must intersect at two points.

# IO helpers

Reads a GPX file (using the GPX library) by simply concatenating all the tracks, segments, and points (`trkpts`, `trksegs`, `trks`) into a single `Trail`.

# Types

data AvgMethod c Source

Constructors

 AvgMean Obtain the `mean` of the considered points AvgHarmonicMean Obtain the `harmonicMean` AvgGeometricMean Obtain the `geometricMean` 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)

data Selected a Source

When grouping points, lists of points are either marked as `Select` or `NotSelect`.

Constructors

 Select FieldsunSelect :: a NotSelect FieldsunSelect :: a

Instances

 Functor Selected Eq a => Eq (Selected a) Ord a => Ord (Selected a) Show a => Show (Selected a)

type PointGrouping c = Trail c -> [Selected (Trail c)]Source

A PointGrouping is a function that selects segments of a trail.

Grouping point _does not_ result in deleted points. It is always true that:

forall g :: PointGrouping c --> concatMap unSelect (g ts) == ts

The purpose of grouping is usually for later processing. Any desire to drop points that didn't meet a particular grouping criteria can be filled with a composition with `filter` (or directly via `filterPoints`).

type TransformGrouping c = [Selected (Trail c)] -> [Selected (Trail c)]Source

Given a selection of coordinates, transform the selected coordinates in some way (while leaving the non-selected coordinates unaffected).

# Utility Functions

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

# Trail Functions

## Queries

totalDistance :: Coordinate a => [a] -> DistanceSource

Find the total distance traveled

avgSpeeds :: (Coordinate a, TimeL 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 :: (Coordinate a, TimeL 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 :: Coordinate 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, Coordinate 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 :: (Coordinate a, TimeL 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 :: (Coordinate a, TimeL 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 :: (Coordinate a, TimeL 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 :: (Coordinate a, TimeL 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)

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

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

chunk the trail into groups of N points

## Group Transformations

intersectionOf :: (Coordinate a, TimeL a) => [PointGrouping a] -> PointGrouping aSource

intersects the given groupings

Inverts the selected/nonselected segments

`firstGrouping f ps` only the first segment remains `Select`ed, and only if it was already selected by `f`.

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

unionOf :: (Coordinate a, TimeL a) => [PointGrouping a] -> PointGrouping aSource

Union all the groupings

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.

(/\) :: [Selected (Trail a)] -> TransformGrouping aSource

Intersection binary operator

(\/) :: [Selected (Trail a)] -> TransformGrouping aSource

Union binary operator

# Misc

bezierPoint :: Coordinate a => [a] -> Double -> aSource