{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} -- | A geodetic curve is made of a distance in metres, an azimuth and a reverse azimuth. module Data.Geo.Geodetic.Curve( Curve , AsCurve(..) , curve , curveDistance , curveAzimuth , curveReverseAzimuth ) where import Control.Category(id) import Control.Lens(Optic', Lens', Profunctor, lens, iso) import Data.Eq(Eq) import Data.Functor(Functor) import Data.List(unwords) import Data.Ord(Ord((>))) import Data.Geo.Geodetic.Azimuth import Text.Printf(printf) import Prelude(Show(show, showsPrec), Double, showString, showParen) data Curve = Curve Double -- The ellipsoidal distance. Azimuth -- The azimuth. Azimuth -- The reverse azimuth. deriving (Eq, Ord) -- | A show instance that prints to 4 decimal places. -- This is to take floating-point rounding errors into account. instance Show Curve where showsPrec n (Curve d a r) = showParen (n > 10) (showString (unwords ["GeodeticCurve", printf "%0.4f" d, show a, show r])) -- | Construct a geodetic curve with the given parameters. curve :: Double -- ^ The ellipsoidal distance. -> Azimuth -- ^ The azimuth. -> Azimuth -- ^ The reverse azimuth. -> Curve curve = Curve curveDistance :: Lens' Curve Double curveDistance = lens (\(Curve d _ _) -> d) (\(Curve _ a r) d -> Curve d a r) curveAzimuth :: Lens' Curve Azimuth curveAzimuth = lens (\(Curve _ a _) -> a) (\(Curve d _ r) a -> Curve d a r) curveReverseAzimuth :: Lens' Curve Azimuth curveReverseAzimuth = lens (\(Curve _ _ r) -> r) (\(Curve d a _) r -> Curve d a r) class AsCurve p f s where _Curve :: Optic' p f s Curve instance AsCurve p f Curve where _Curve = id instance (Profunctor p, Functor f) => AsCurve p f (Double, Azimuth, Azimuth) where _Curve = iso (\(d, a, r) -> Curve d a r) (\(Curve d a r) -> (d, a, r))