jord-1.0.0.0: Geographical Position Calculations

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

Data.Geo.Jord.Geodesic

Contents

Description

Solutions to the direct and inverse geodesic problems on ellipsoidal models using Vincenty formulaes. A geodesic is the shortest path between two points on a curved surface - here an ellispoid. Using these functions improves on the accuracy available using Data.Geo.Jord.GreatCircle at the expense of higher CPU usage.

In order to use this module you should start with the following imports:

    import Data.Geo.Jord.Geodesic
    import Data.Geo.Jord.Position

If you wish to use both this module and the Data.Geo.Jord.GreatCircle module you must qualify both imports.

T Vincenty, "Direct and Inverse Solutions of Geodesics on the Ellipsoid with application of nested equations", Survey Review, vol XXIII no 176, 1975.

Synopsis

The Geodesic type

data Geodesic a Source #

Geodesic line: shortest route between two positions on the surface of a model.

Instances
Model a => Eq (Geodesic a) Source # 
Instance details

Defined in Data.Geo.Jord.Geodesic

Methods

(==) :: Geodesic a -> Geodesic a -> Bool #

(/=) :: Geodesic a -> Geodesic a -> Bool #

Model a => Show (Geodesic a) Source # 
Instance details

Defined in Data.Geo.Jord.Geodesic

Methods

showsPrec :: Int -> Geodesic a -> ShowS #

show :: Geodesic a -> String #

showList :: [Geodesic a] -> ShowS #

geodesicPos1 :: Geodesic a -> Position a Source #

geodesic start position, p1.

geodesicPos2 :: Geodesic a -> Position a Source #

geodesic end position, p2.

geodesicBearing1 :: Geodesic a -> Maybe Angle Source #

initial bearing from p1 to p2, if p1 and p2 are different.

geodesicBearing2 :: Geodesic a -> Maybe Angle Source #

final bearing from p1 to p2, if p1 and p2 are different

geodesicLength :: Geodesic a -> Length Source #

length of the geodesic: the surface distance between p1 and p2.

Calculations

directGeodesic :: Ellipsoidal a => Position a -> Angle -> Length -> Maybe (Geodesic a) Source #

directGeodesic p1 b1 d solves the direct geodesic problem using Vicenty formula: position along the geodesic, reached from position p1 having travelled the surface distance d on the initial bearing (compass angle) b1 at constant height; it also returns the final bearing at the reached position. The Vincenty formula for the direct problem should always converge, however this function returns Nothing if it would ever fail to do so (probably thus indicating a bug in the implementation).

Examples

Expand
>>> import Data.Geo.Jord.Geodesic
>>> import Data.Geo.Jord.Position
>>> 
>>> directGeodesic (northPole WGS84) zero (kilometres 20003.931458623)
Just (Geodesic {geodesicPos1 = 90°0'0.000"N,0°0'0.000"E 0.0m (WGS84)
              , geodesicPos2 = 90°0'0.000"S,180°0'0.000"E 0.0m (WGS84)
              , geodesicBearing1 = Just 0°0'0.000"
              , geodesicBearing2 = Just 180°0'0.000"
              , geodesicLength = 20003.931458623km})

inverseGeodesic :: Ellipsoidal a => Position a -> Position a -> Maybe (Geodesic a) Source #

inverseGeodesic p1 p2 solves the inverse geodesic problem using Vicenty formula: surface distance, and initial/final bearing between the geodesic line between positions p1 and p2. The Vincenty formula for the inverse problem can fail to converge for nearly antipodal points in which case this function returns Nothing.

Examples

Expand
>>> import Data.Geo.Jord.Geodesic
>>> import Data.Geo.Jord.Position
>>> 
>>> inverseGeodesic (latLongPos 0 0 WGS84) (latLongPos 0.5 179.5 WGS84)
Just (Geodesic {geodesicPos1 = 0°0'0.000"N,0°0'0.000"E 0.0m (WGS84)
              , geodesicPos2 = 0°30'0.000"N,179°30'0.000"E 0.0m (WGS84)
              , geodesicBearing1 = Just 25°40'18.742"
              , geodesicBearing2 = Just 154°19'37.507"
              , geodesicLength = 19936.288578981km})
>>> 
>>> inverseGeodesic (latLongPos 0 0 WGS84) (latLongPos 0.5 179.7 WGS84)
Nothing

destination :: Ellipsoidal a => Position a -> Angle -> Length -> Maybe (Position a) Source #

destination p b d computes the position along the geodesic, reached from position p having travelled the surface distance d on the initial bearing (compass angle) b at constant height. Note that the bearing will normally vary before destination is reached.

    fmap geodesicPos2 (directGeodesic p b d)

Examples

Expand
>>> import Data.Geo.Jord.Geodesic
>>> import Data.Geo.Jord.Position
>>> 
>>> destination (wgs84Pos 54 154 (metres 15000)) (decimalDegrees 33) (kilometres 1000)
Just 61°10'8.983"N,164°7'52.258"E 15.0km (WGS84)

finalBearing :: Ellipsoidal a => Position a -> Position 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 initial bearing by varying degrees according to distance and latitude. Returns Nothing if both positions are equals or if inverseGeodesic fails to converge.

This is equivalent to:

    (inverseGeodesic p1 p2) >>= geodesicBearing2

Examples

Expand
>>> import Data.Geo.Jord.Geodesic
>>> import Data.Geo.Jord.Position
>>> 
>>> p1 = latLongPos (-37.95103341666667) 144.42486788888888 WGS84
>>> p2 = latLongPos (-37.65282113888889) 143.92649552777777 WGS84
>>> initialBearing p1 p2
Just 307°10'25.070"

initialBearing :: Ellipsoidal a => Position a -> Position 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 positions are equals or if inverseGeodesic fails to converge.

    (inverseGeodesic p1 p2) >>= geodesicBearing1

Examples

Expand
>>> import Data.Geo.Jord.Geodesic
>>> import Data.Geo.Jord.Position
>>> 
>>> p1 = latLongPos (-37.95103341666667) 144.42486788888888 WGS84
>>> p2 = latLongPos (-37.65282113888889) 143.92649552777777 WGS84
>>> initialBearing p1 p2
Just 306°52'5.373"

surfaceDistance :: Ellipsoidal a => Position a -> Position a -> Maybe Length Source #

surfaceDistance p1 p2 computes the surface distance on the geodesic between the positions p1 and p2. This function relies on inverseGeodesic and can therefore fail to compute the distance for nearly antipodal positions.

    fmap geodesicLength (inverseGeodesic p1 p2)

Examples

Expand
>>> import Data.Geo.Jord.Geodesic
>>> import Data.Geo.Jord.Position
>>> 
>>> surfaceDistance (northPole WGS84) (southPole WGS84)
Just 20003.931458623km