```-- |

-- Module:      Data.Geo.Jord.Earth

-- Copyright:   (c) 2018 Cedric Liegeois

-- License:     BSD3

-- Maintainer:  Cedric Liegeois <ofmooseandmen@yahoo.fr>

-- Stability:   experimental

-- Portability: portable

--

-- Ellipsoidal and derived spherical earth models.

--

module Data.Geo.Jord.Earth
( Earth(..)
, Ellipsoid(..)
, eccentricity
, meanRadius
, polarRadius
, spherical
-- * Reference ellipsoids.

, wgs84
, grs80
, wgs72
-- * Spherical models dervived from reference ellipsoids.

, s84
, s80
, s72
, r84
, r80
, r72
) where

import Data.Geo.Jord.Length

-- | Earth model: ellipsoidal or spherical.

data Earth
= Ellipsoidal Ellipsoid
| Spherical Length
deriving (Eq, Show)

-- | Primary ellipsoid parameters.

data Ellipsoid = Ellipsoid
{ equatorialRadius :: Length -- ^ equatorial radius or semi-major axis (a).

, inverseFlattening :: Double -- ^ inverse flattening.

} deriving (Eq, Show)

-- | Computes the eccentricity of the given 'Earth' model.

eccentricity :: Earth -> Double
eccentricity (Ellipsoidal e) = sqrt (1.0 - (b * b) / (a * a))
where
a = semiMajorAxis e
b = semiMinorAxis a (inverseFlattening e)
eccentricity (Spherical _) = 0

-- | Computes the mean radius of the given 'Earth' model.

--

-- This radius can be used for geodetic calculations assuming a spherical earth model.

meanRadius :: Earth -> Length
meanRadius (Ellipsoidal e) = metres ((2.0 * a + b) / 3.0)
where
a = semiMajorAxis e
b = semiMinorAxis a (inverseFlattening e)
meanRadius (Spherical r) = r

-- | Computes the polar radius or semi-minor axis (b) of the given 'Earth' model.

polarRadius :: Earth -> Length
polarRadius (Ellipsoidal e) = metres (semiMinorAxis a f)
where
a = semiMajorAxis e
f = inverseFlattening e
polarRadius (Spherical r) = r

-- | Spherical model derived from given model.

spherical :: Earth -> Earth
spherical e = Spherical (meanRadius e)

-- | World Geodetic System WGS84 ellipsoid.

wgs84 :: Earth
wgs84 = Ellipsoidal (Ellipsoid (metres 6378137.0) (1.0 / 298.257223563))

-- | Geodetic Reference System 1980 ellipsoid.

grs80 :: Earth
grs80 = Ellipsoidal (Ellipsoid (metres 6378137.0) (1.0 / 298.257222101))

-- | World Geodetic System WGS72 ellipsoid.

wgs72 :: Earth
wgs72 = Ellipsoidal (Ellipsoid (metres 6378135.0) (1.0 / 298.26))

-- | Spherical earth model derived from 'wgs84'.

s84 :: Earth
s84 = spherical wgs84

-- | Spherical earth model derived from 'grs80'.

s80 :: Earth
s80 = spherical grs80

-- | Spherical earth model derived from 'wgs72'.

s72 :: Earth
s72 = spherical wgs72

-- | Mean earth radius derived from the 'wgs84' ellipsoid.

r84 :: Length
r84 = meanRadius s84

-- | Mean earth radius derived from the 'grs80' ellipsoid.

r80 :: Length
r80 = meanRadius s80

-- | Mean earth radius derived from the 'wgs72' ellipsoid.

r72 :: Length
r72 = meanRadius s72

-- | semi-major axis (a) in metres.

semiMajorAxis :: Ellipsoid -> Double
semiMajorAxis = toMetres . equatorialRadius

-- | Computes the polar semi-minor axis (b) from @a@ anf @f@.

semiMinorAxis :: Double -> Double -> Double
semiMinorAxis a f = a * (1.0 - f)
```