jord-0.5.0.0: Geographical Position Calculations

Copyright(c) 2018 Cedric Liegeois
LicenseBSD3
MaintainerCedric Liegeois <ofmooseandmen@yahoo.fr>
Stabilityexperimental
Portabilityportable
Safe HaskellSafe
LanguageHaskell2010

Data.Geo.Jord.Geodetics

Contents

Description

Geodetic calculations assuming a spherical earth model.

All functions are implemented using the vector-based approached described in Gade, K. (2010). A Non-singular Horizontal Position Representation

Synopsis

The GreatCircle type

data GreatCircle Source #

A circle on the surface of the Earth which lies in a plane passing through the Earth's centre. Every two distinct and non-antipodal points on the surface of the Earth define a Great Circle.

It is internally represented as its normal vector - i.e. the normal vector to the plane containing the great circle.

see IsGreatCircle.

class IsGreatCircle a where Source #

Class for data from which a GreatCircle can be computed.

Minimal complete definition

greatCircleE

Methods

greatCircle Source #

Arguments

:: a 
-> GreatCircle

GreatCircle from a, if greateCircleE returns a Left, this function errors.

greatCircleE Source #

Arguments

:: a 
-> Either String GreatCircle

GreatCircle from a, A Left indicates an error.

greatCircleF Source #

Arguments

:: MonadFail m 
=> a 
-> m GreatCircle

GreatCircle from a, if greateCircleE returns a Left, this function fails.

Instances
IsGreatCircle GreatArc Source #

GreatCircle from given GreatArc.

Instance details

Defined in Data.Geo.Jord.Geodetics

NTransform a => IsGreatCircle (Track a) Source #

GreatCircle from track.

Instance details

Defined in Data.Geo.Jord.Kinematics

NTransform a => IsGreatCircle (a, Angle) Source #

GreatCircle passing by the given position and heading on given bearing.

    greatCircle (readLatLong "283321N0290700W", decimalDegrees 33.0)
Instance details

Defined in Data.Geo.Jord.Geodetics

NTransform a => IsGreatCircle (a, a) Source #

GreatCircle passing by both given positions'. A Left indicates that given positions are equal or antipodal.

    let p1 = decimalLatLongHeight 45.0 (-143.5) (metres 1500)
    let p2 = decimalLatLongHeight 46.0 14.5 (metres 3000)
    greatCircle (p1, p2) -- heights are ignored, great circle are always at earth surface.
Instance details

Defined in Data.Geo.Jord.Geodetics

gcPos :: GreatCircle -> NVector Source #

position (n-vector) on the great circle

The GreatArc type

data GreatArc Source #

A closed segment of GreatCircle. It represent the shortest path on the surface of the Earth between the two positions.

see IsGreatArc.

class IsGreatArc a where Source #

Class for data from which a GreatArc can be computed.

Minimal complete definition

greatArcE

Methods

greatArc Source #

Arguments

:: a 
-> GreatArc

GreatCircle from a, if greatArcE returns a Left, this function errors.

greatArcE Source #

Arguments

:: a 
-> Either String GreatArc

GreatArc from a, A Left indicates an error.

greatArcF Source #

Arguments

:: MonadFail m 
=> a 
-> m GreatArc

GreatArc from a, if greatArcE returns a Left, this function fails.

Instances
NTransform a => IsGreatArc (a, a) Source #

GreatArc passing by both given positions'. A Left indicates that given positions are equal or antipodal.

    let p1 = decimalLatLongHeight 45.0 (-143.5) (metres 1500)
    let p2 = decimalLatLongHeight 46.0 14.5 (metres 3000)
    greatArc (p1, p2) -- heights are ignored, great arc are always at earth surface.
Instance details

Defined in Data.Geo.Jord.Geodetics

Methods

greatArc :: (a, a) -> GreatArc Source #

greatArcE :: (a, a) -> Either String GreatArc Source #

greatArcF :: MonadFail m => (a, a) -> m GreatArc Source #

NTransform a => IsGreatArc (Track a, Duration) Source #

GreatArc from track and duration using the mean radius of the WGS84 reference ellipsoid.

Instance details

Defined in Data.Geo.Jord.Kinematics

NTransform a => IsGreatArc (Track a, Duration, Length) Source #

GreatArc from track, duration and earth mean radius.

Instance details

Defined in Data.Geo.Jord.Kinematics

gaStart :: GreatArc -> NVector Source #

start position (n-vector) of the great arc

gaEnd :: GreatArc -> NVector Source #

end position (n-vector) of the great arc

Calculations

alongTrackDistance :: NTransform a => a -> GreatArc -> Length -> Length Source #

alongTrackDistance p ga r how far position p is along a path described by great arc ga: if a perpendicular is drawn from p to the great arc, the along-track distance is the signed distance from the start point to where the perpendicular crosses the path.

    let p = decimalLatLong 53.2611 (-0.7972)
    let ga = greatArc (decimalLatLong 53.3206 (-1.7297)) (decimalLatLong 53.1887 0.1334)
    alongTrackDistance p ga r84 -- 62.3315757 kilometres

alongTrackDistance84 :: NTransform a => a -> GreatArc -> Length Source #

alongTrackDistance using the mean radius of the WGS84 reference ellipsoid.

angularDistance :: NTransform a => a -> a -> Maybe a -> Angle Source #

angularDistance p1 p2 n computes the angle between the horizontal positions p1 and p2. If n is Nothing, the angle is always in [0..180], otherwise it is in [-180, +180], signed + if p1 is clockwise looking along n, - in opposite direction.

antipode :: NTransform a => a -> a Source #

antipode p computes the antipodal horizontal position of p: the horizontal position on the surface of the Earth which is diametrically opposite to p.

crossTrackDistance :: NTransform a => a -> GreatCircle -> Length -> Length Source #

crossTrackDistance p gc r computes the signed distance from horizontal position p to great circle gc. Returns a negative Length if position if left of great circle, positive Length if position if right of great circle; the orientation of the great circle is therefore important:

    let gc1 = greatCircle (decimalLatLong 51 0) (decimalLatLong 52 1)
    let gc2 = greatCircle (decimalLatLong 52 1) (decimalLatLong 51 0)
    crossTrackDistance p gc1 r84 = (- crossTrackDistance p gc2 r84)

    let p = decimalLatLong 53.2611 (-0.7972)
    let gc = greatCircleBearing (decimalLatLong 53.3206 (-1.7297)) (decimalDegrees 96.0)
    crossTrackDistance p gc r84 -- -305.663 metres

crossTrackDistance84 :: NTransform a => a -> GreatCircle -> Length Source #

crossTrackDistance using the mean radius of the WGS84 reference ellipsoid.

destination :: NTransform a => a -> Angle -> Length -> Length -> a Source #

destination p b d r computes the destination position from position p having travelled the distance d on the initial bearing (compass angle) b (bearing will normally vary before destination is reached) and using the earth radius r.

    let p0 = ecefToNVector (ecefMetres 3812864.094 (-115142.863) 5121515.161) s84
    let p1 = ecefMetres 3826406.4710518294 8900.536398998282 5112694.233184049
    let p = destination p0 (decimalDegrees 96.0217) (metres 124800) r84
    nvectorToEcef p s84 = p1

destination84 :: NTransform a => a -> Angle -> Length -> a Source #

destination using the mean radius of the WGS84 reference ellipsoid.

finalBearing :: (Eq a, NTransform a) => a -> a -> Maybe Angle Source #

finalBearing p1 p2 computes the final bearing arriving at p2 from p1 in compass angle.

Compass angles are clockwise angles from true north: 0 = north, 90 = east, 180 = south, 270 = west.

The final bearing will differ from the initialBearing by varying degrees according to distance and latitude.

Returns Nothing if both horizontal positions are equals.

initialBearing :: (Eq a, NTransform a) => a -> a -> Maybe Angle Source #

initialBearing p1 p2 computes the initial bearing from p1 to p2 in compass angle.

Compass angles are clockwise angles from true north: 0 = north, 90 = east, 180 = south, 270 = west.

Returns Nothing if both horizontal positions are equals.

interpolate :: NTransform a => a -> a -> Double -> a Source #

interpolate p0 p1 f# computes the horizontal position at fraction f between the p0 and p1@.

Special conditions:

    interpolate p0 p1 0.0 = p0
    interpolate p0 p1 1.0 = p1

errors if f || f 1

    let p1 = latLongHeight (readLatLong "53°28'46''N 2°14'43''W") (metres 10000)
    let p2 = latLongHeight (readLatLong "55°36'21''N 13°02'09''E") (metres 20000)
    interpolate p1 p2 0.5 = decimalLatLongHeight 54.7835574 5.1949856 (metres 15000)

intersection :: NTransform a => GreatArc -> GreatArc -> Maybe a Source #

Computes the intersection between the two given GreatArcs.

see also intersections

    let spd = kilometresPerHour 1000
    let t1 = Track (decimalLatLong 51.885 0.235) (decimalDegrees 108.63) spd
    let t2 = Track (decimalLatLong 49.008 2.549) (decimalDegrees 32.72) spd
    let oneHour = hours 1
    let ga1 = greatArc (t1, oneHour)
    let ga2 = greatArc (t2, oneHour)
    intersection ga1 ga2 = Just (decimalLatLong 50.9017225 4.494278333333333)

intersections :: NTransform a => GreatCircle -> GreatCircle -> Maybe (a, a) Source #

Computes the intersections between the two given GreatCircles. Two GreatCircles intersect exactly twice unless there are equal (regardless of orientation), in which case Nothing is returned.

    let gc1 = greatCircleBearing (decimalLatLong 51.885 0.235) (decimalDegrees 108.63)
    let gc2 = greatCircleBearing (decimalLatLong 49.008 2.549) (decimalDegrees 32.72)
    let (i1, i2) = fromJust (intersections gc1 gc2)
    i1 = decimalLatLong 50.9017226 4.4942782
    i2 = antipode i1

isBetween :: NTransform a => a -> GreatArc -> Bool Source #

isBetween p ga determines whether position p is between start and end points of great arc ga. If p is not on the great arc, returns whether p is within the area bound by perpendiculars to the great arc at each point (in the same hemisphere).

isInsideSurface :: (Eq a, NTransform a) => a -> [a] -> Bool Source #

isInsideSurface p ps determines whether the p is inside the polygon defined by the list of positions ps. The polygon is closed if needed (i.e. if head ps /= last ps).

Uses the angle summation test: on a sphere, due to spherical excess, enclosed point angles will sum to less than 360°, and exterior point angles will be small but non-zero.

Always returns False if ps does not at least defines a triangle.

    let malmo = decimalLatLong 55.6050 13.0038
    let ystad = decimalLatLong 55.4295 13.82
    let lund = decimalLatLong 55.7047 13.1910
    let helsingborg = decimalLatLong 56.0465 12.6945
    let kristianstad = decimalLatLong 56.0294 14.1567
    let polygon = [malmo, ystad, kristianstad, helsingborg, lund]
    let hoor = decimalLatLong 55.9295 13.5297
    let hassleholm = decimalLatLong 56.1589 13.7668
    isInsideSurface hoor polygon = True
    isInsideSurface hassleholm polygon = False

mean :: NTransform a => [a] -> Maybe a Source #

mean ps computes the mean geographic horitzontal position of ps, if it is defined.

The geographic mean is not defined for antipodals position (since they cancel each other).

Special conditions:

    mean [] = Nothing
    mean [p] = Just p
    mean [p1, p2, p3] = Just circumcentre
    mean [p1, .., antipode p1] = Nothing

surfaceDistance :: NTransform a => a -> a -> Length -> Length Source #

surfaceDistance p1 p2 computes the surface distance (length of geodesic) between the positions p1 and p2.

surfaceDistance84 :: NTransform a => a -> a -> Length Source #

surfaceDistance using the mean radius of the WGS84 reference ellipsoid.