module Data.Geo.Coordinate.Coordinate(
Coordinate
, AsCoordinate(..)
, latitudeMinutes
, latitudeSeconds
, longitudeMinutes
, longitudeSeconds
, (.#.)
, (<°>)
, antipode
) where
import Control.Applicative(Applicative((<*>)))
import Control.Category(Category(id, (.)))
import Control.Lens(Identity, Const, Prism', Choice, Iso', swapped, Profunctor, Optic', (^.), iso, from, lens, prism', swapped, (^?), (#))
import Control.Monad(Monad(return))
import Data.Eq(Eq)
import Data.Functor(Functor, (<$>))
import Data.Geo.Coordinate.Latitude(AsLatitude(_Latitude), Latitude, antipodeLatitude)
import Data.Geo.Coordinate.Longitude(AsLongitude(_Longitude), Longitude, antipodeLongitude)
import Data.Geo.Coordinate.DegreesLatitude(AsDegreesLatitude(_DegreesLatitude), DegreesLatitude)
import Data.Geo.Coordinate.DegreesLongitude(AsDegreesLongitude(_DegreesLongitude), DegreesLongitude)
import Data.Geo.Coordinate.Minutes(Minutes, AsMinutes(_Minutes))
import Data.Geo.Coordinate.Seconds(Seconds, AsSeconds(_Seconds))
import Data.Maybe(Maybe)
import Data.Monoid(First)
import Data.Ord(Ord)
import Data.Tagged(Tagged)
import Data.Tuple(curry, uncurry)
import Prelude(Show, Double)
data Coordinate =
Coordinate
Latitude
Longitude
deriving (Eq, Ord, Show)
(.#.) ::
(
AsLatitude (->) (Const Latitude) lat
, AsLongitude (->) (Const Longitude) lon
) =>
lat
-> lon
-> Coordinate
lat .#. lon =
Coordinate
(lat ^. _Latitude)
(lon ^. _Longitude)
(<°>) ::
Double
-> Double
-> Maybe Coordinate
(<°>) =
curry (^? _Coordinate)
class AsCoordinate p f s where
_Coordinate ::
Optic' p f s Coordinate
instance AsCoordinate p f Coordinate where
_Coordinate =
id
instance (Profunctor p, Functor f) => AsCoordinate p f (Latitude, Longitude) where
_Coordinate =
iso (uncurry Coordinate) (\(Coordinate lat lon) -> (lat, lon))
instance (Profunctor p, Functor f) => AsCoordinate p f (Longitude, Latitude) where
_Coordinate =
swapped . _Coordinate
instance (Profunctor p, Functor f) => AsCoordinate p f ((DegreesLatitude, Minutes, Seconds), Longitude) where
_Coordinate =
iso
(\(lat, lon) -> Coordinate (lat ^. _Latitude) lon)
(\(Coordinate lat lon) -> (_Latitude # lat, lon))
instance (Profunctor p, Functor f) => AsCoordinate p f (Longitude, (DegreesLatitude, Minutes, Seconds)) where
_Coordinate =
swapped . _Coordinate
instance (Profunctor p, Functor f) => AsCoordinate p f (Latitude, (DegreesLongitude, Minutes, Seconds)) where
_Coordinate =
iso
(\(lat, lon) -> Coordinate lat (lon ^. _Longitude))
(\(Coordinate lat lon) -> (lat, _Longitude # lon))
instance (Profunctor p, Functor f) => AsCoordinate p f ((DegreesLongitude, Minutes, Seconds), Latitude) where
_Coordinate =
swapped . _Coordinate
instance (Profunctor p, Functor f) => AsCoordinate p f ((DegreesLatitude, Minutes, Seconds), (DegreesLongitude, Minutes, Seconds)) where
_Coordinate =
iso
(\(lat, lon) -> Coordinate (lat ^. _Latitude) (lon ^. _Longitude))
(\(Coordinate lat lon) -> (_Latitude # lat, _Longitude # lon))
instance (Profunctor p, Functor f) => AsCoordinate p f ((DegreesLongitude, Minutes, Seconds), (DegreesLatitude, Minutes, Seconds)) where
_Coordinate =
swapped . _Coordinate
coordinatePrism' ::
(
AsLatitude Tagged Identity lat
, AsLatitude (->) (Const (First Latitude)) lat
, AsLongitude Tagged Identity lon
, AsLongitude (->) (Const (First Longitude)) lon) =>
Prism' (lat, lon) Coordinate
coordinatePrism' =
coordinatePrism (_Latitude #) (_Longitude #) (^? _Latitude) (^? _Longitude)
coordinatePrism ::
(Latitude -> lat)
-> (Longitude -> lon)
-> (lat -> Maybe Latitude)
-> (lon -> Maybe Longitude)
-> Prism' (lat, lon) Coordinate
coordinatePrism f g h i =
prism'
(\(Coordinate lat lon) -> (f lat, g lon))
(\(lat, lon) ->
do lat' <- h lat
lon' <- i lon
return (Coordinate lat' lon'))
instance (Choice p, Applicative f) => AsCoordinate p f (Double, Double) where
_Coordinate =
coordinatePrism'
instance (Choice p, Applicative f) => AsCoordinate p f (Latitude, Double) where
_Coordinate =
coordinatePrism id (_Longitude #) return (^? _Longitude)
instance (Choice p, Applicative f) => AsCoordinate p f (Double, Longitude) where
_Coordinate =
coordinatePrism (_Latitude #) id (^? _Latitude) return
instance (Choice p, Applicative f) => AsCoordinate p f ((DegreesLatitude, Minutes, Seconds), Double) where
_Coordinate =
coordinatePrism'
instance (Choice p, Applicative f) => AsCoordinate p f (Double, (DegreesLongitude, Minutes, Seconds)) where
_Coordinate =
coordinatePrism'
instance (p ~ (->), Functor f) => AsLatitude p f Coordinate where
_Latitude =
lens (\(Coordinate lat _) -> lat) (\(Coordinate _ lon) lat -> Coordinate lat lon)
instance (p ~ (->), Functor f) => AsDegreesLatitude p f Coordinate where
_DegreesLatitude =
_Latitude . _DegreesLatitude
instance (p ~ (->), Functor f) => AsLongitude p f Coordinate where
_Longitude =
lens (\(Coordinate _ lon) -> lon) (\(Coordinate lat _) lon -> Coordinate lat lon)
instance (p ~ (->), Functor f) => AsDegreesLongitude p f Coordinate where
_DegreesLongitude =
_Longitude . _DegreesLongitude
instance (p ~ (->), Applicative f) => AsMinutes p f Coordinate where
_Minutes f (Coordinate lat lon) =
(\m1 m2 ->
Coordinate
(from _Latitude # (lat ^. _DegreesLatitude, m1, lat ^. _Seconds))
(from _Longitude # (lon ^. _DegreesLongitude, m2, lon ^. _Seconds))) <$>
f (lat ^. _Minutes) <*>
f (lon ^. _Minutes)
instance (p ~ (->), Applicative f) => AsSeconds p f Coordinate where
_Seconds f (Coordinate lat lon) =
(\s1 s2 ->
Coordinate
(from _Latitude # (lat ^. _DegreesLatitude, lat ^. _Minutes, s1))
(from _Longitude # (lon ^. _DegreesLongitude, lon ^. _Minutes, s2))) <$>
f (lat ^. _Seconds) <*>
f (lon ^. _Seconds)
latitudeMinutes ::
(AsCoordinate (->) f coord, Functor f) =>
Optic' (->) f coord Minutes
latitudeMinutes =
_Coordinate . _Latitude . _Minutes
latitudeSeconds ::
(AsCoordinate (->) f coord, Functor f) =>
Optic' (->) f coord Seconds
latitudeSeconds =
_Coordinate . _Latitude . _Seconds
longitudeMinutes ::
(AsCoordinate (->) f coord, Functor f) =>
Optic' (->) f coord Minutes
longitudeMinutes =
_Coordinate . _Longitude . _Minutes
longitudeSeconds ::
(AsCoordinate (->) f coord, Functor f) =>
Optic' (->) f coord Seconds
longitudeSeconds =
_Coordinate . _Longitude . _Seconds
antipode ::
Iso'
Coordinate
Coordinate
antipode =
let n (Coordinate lat lon) = Coordinate (antipodeLatitude # lat) (antipodeLongitude # lon)
in iso
n
n