jord-2.0.0.0: src/Data/Geo/Jord/Geocentric.hs
-- |
-- Module: Data.Geo.Jord.Geocentric
-- Copyright: (c) 2020 Cedric Liegeois
-- License: BSD3
-- Maintainer: Cedric Liegeois <ofmooseandmen@yahoo.fr>
-- Stability: experimental
-- Portability: portable
--
-- Geocentric coordinates of points (X, Y, and Z Cartesian coordinates) in specified models.
--
-- For the Earth the coordinate system is known as ECEF (acronym for earth-centered, earth-fixed),
-- or ECR (initialism for earth-centered rotational).
--
-- In order to use this module you should start with the following imports:
--
-- @
-- import qualified Data.Geo.Jord.Geocentric as Geocentric
-- import qualified Data.Geo.Jord.Length as Length
-- import Data.Geo.Jord.Models
-- @
--
-- see "Data.Geo.Jord.Models" for supported models.
module Data.Geo.Jord.Geocentric
( Position(..)
, coords
, metresCoords
, metresPos
, metresPos'
, antipode
, northPole
, southPole
) where
import Data.Geo.Jord.Ellipsoid (polarRadius)
import Data.Geo.Jord.Length (Length)
import qualified Data.Geo.Jord.Length as Length (metres, toMetres)
import qualified Data.Geo.Jord.Math3d as Math3d
import Data.Geo.Jord.Model
-- | Geocentric coordinates (cartesian X, Y, Z) of a position in a specified 'Model'.
--
-- @gx-gy@ plane is the equatorial plane, @gx@ is on the prime meridian, and @gz@ on the polar axis.
--
-- On a spherical celestial body, an /n/-vector is equivalent to a normalised version of a
-- geocentric cartesian coordinate.
data Position a =
Position
{ gx :: Length -- ^ x-coordinate
, gy :: Length -- ^ y-coordinate
, gz :: Length -- ^ z-coordinate
, model :: a -- ^ model (e.g. WGS84)
}
deriving (Eq, Show)
-- | 3d vector representing the (X, Y, Z) coordinates in __metres__ of the given position.
metresCoords :: (Model a) => Position a -> Math3d.V3
metresCoords p = coords p Length.toMetres
-- | @coords p f@ returns the 3d vector representing the (X, Y, Z) coordinates in the unit
-- of @f@. For example:
--
-- >>> Geocentric.coords (Geocentric.metresPos 3194669.145061 3194669.145061 4487701.962256 WGS84) Length.toKilometres
-- V3 {vx = 3194.669145061, vy = 3194.669145061, vz = 4487.701962256}
coords :: (Model a) => Position a -> (Length -> Double) -> Math3d.V3
coords (Position x y z _) f = Math3d.vec3 (f x) (f y) (f z)
-- | Geocentric position from given (X, Y, Z) in __metres__ an given 'Model'.
metresPos :: (Model a) => Double -> Double -> Double -> a -> Position a
metresPos xm ym zm = Position (Length.metres xm) (Length.metres ym) (Length.metres zm)
-- | Geocentric position from given 3d vector (X, Y, Z) in __metres__ an given 'Model'.
metresPos' :: (Model a) => Math3d.V3 -> a -> Position a
metresPos' v = metresPos (Math3d.v3x v) (Math3d.v3y v) (Math3d.v3z v)
-- | @antipode p@ computes the antipodal position of @p@: the position which is diametrically
-- opposite to @p@.
antipode :: (Model a) => Position a -> Position a
antipode p = metresPos (Math3d.v3x avm) (Math3d.v3y avm) (Math3d.v3z avm) (model p)
where
c = metresCoords p
avm = Math3d.scale c (-1.0)
-- | Surface position of the North Pole in the given model.
northPole :: (Model a) => a -> Position a
northPole m = metresPos 0 0 r m
where
r = Length.toMetres . polarRadius . surface $ m
-- | Surface position of the South Pole in the given model.
southPole :: (Model a) => a -> Position a
southPole m = metresPos 0 0 (-r) m
where
r = Length.toMetres . polarRadius . surface $ m