{-# LANGUAGE NoImplicitPrelude #-} module Geodetics.Types.Helmert( Helmert(..) , HasHelmert(..) , AsHelmert(..) , ManyHelmert(..) , GetHelmert(..) , SetHelmert(..) , FoldHelmert(..) , IsHelmert(..) , translations , rotations ) where import Control.Applicative((<*>)) import Control.Category((.), id) import Control.Lens(Lens', Prism', Traversal', Getter, Setter', Fold, Iso', prism, (^.)) import Data.Either(Either(Right)) import Data.Eq(Eq) import Data.Ord(Ord) import Data.Functor(fmap, (<$>)) import Data.Monoid(Monoid(mempty, mappend)) import Data.Semigroup(Semigroup((<>))) import Numeric.Units.Dimensional.Prelude(Length, Dimensionless, (+), (*~), meter, _0) import Prelude(Double, Show) -- | The 7 parameter Helmert transformation. The monoid instance allows composition. data Helmert = Helmert (Length Double) (Length Double) (Length Double) (Dimensionless Double) -- Parts per million (Dimensionless Double) (Dimensionless Double) (Dimensionless Double) deriving (Eq, Ord, Show) class HasHelmert a where helmert :: Lens' a Helmert cX :: Lens' a (Length Double) {-# INLINE cX #-} cY :: Lens' a (Length Double) {-# INLINE cY #-} cZ :: Lens' a (Length Double) {-# INLINE cZ #-} helmertScale :: Lens' a (Dimensionless Double) {-# INLINE helmertScale #-} rX :: Lens' a (Dimensionless Double) {-# INLINE rX #-} rY :: Lens' a (Dimensionless Double) {-# INLINE rY #-} rZ :: Lens' a (Dimensionless Double) {-# INLINE rZ #-} cX = helmert . cX cY = helmert . cY cZ = helmert . cZ helmertScale = helmert . helmertScale rX = helmert . rX rY = helmert . rY rZ = helmert . rZ instance HasHelmert Helmert where {-# INLINE cX #-} {-# INLINE cY #-} {-# INLINE cZ #-} {-# INLINE helmertScale #-} {-# INLINE rX #-} {-# INLINE rY #-} {-# INLINE rZ #-} helmert = id cX k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert x cY' cZ' helmertScale' rX' rY' rZ') (k cX') cY k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert cX' x cZ' helmertScale' rX' rY' rZ') (k cY') cZ k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert cX' cY' x helmertScale' rX' rY' rZ') (k cZ') helmertScale k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert cX' cY' cZ' x rX' rY' rZ') (k helmertScale') rX k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert cX' cY' cZ' helmertScale' x rY' rZ') (k rX') rY k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert cX' cY' cZ' helmertScale' rX' x rZ') (k rY') rZ k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = fmap (\x -> Helmert cX' cY' cZ' helmertScale' rX' rY' x) (k rZ') class ManyHelmert a => AsHelmert a where _Helmert :: Prism' a Helmert _HelmertFields :: Prism' a (Length Double, Length Double, Length Double, Dimensionless Double, Dimensionless Double, Dimensionless Double, Dimensionless Double) _HelmertFields = _Helmert . _HelmertFields instance AsHelmert Helmert where _Helmert = id _HelmertFields = prism (\(cX', cY', cZ', helmertScale', rX', rY', rZ') -> Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') (\(Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') -> Right (cX', cY', cZ', helmertScale', rX', rY', rZ')) class (FoldHelmert a, SetHelmert a) => ManyHelmert a where _ManyHelmert :: Traversal' a Helmert instance ManyHelmert Helmert where _ManyHelmert = id class FoldHelmert a => GetHelmert a where _GetHelmert :: Getter a Helmert instance GetHelmert Helmert where _GetHelmert = id class SetHelmert a where _SetHelmert :: Setter' a Helmert instance SetHelmert Helmert where _SetHelmert = id class FoldHelmert a where _FoldHelmert :: Fold a Helmert instance FoldHelmert Helmert where _FoldHelmert = id class (HasHelmert a, AsHelmert a) => IsHelmert a where _IsHelmert :: Iso' a Helmert instance IsHelmert Helmert where _IsHelmert = id instance Semigroup Helmert where h1 <> h2 = let p x = h1 ^. x + h2 ^. x in Helmert (p cX) (p cY) (p cZ) (p helmertScale) (p rX) (p rY) (p rZ) instance Monoid Helmert where mempty = Helmert (0 *~ meter) (0 *~ meter) (0 *~ meter) _0 _0 _0 _0 mappend = (<>) translations :: Traversal' Helmert (Length Double) translations k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = (\cX'' cY'' cZ'' -> Helmert cX'' cY'' cZ'' helmertScale' rX' rY' rZ') <$> k cX' <*> k cY' <*> k cZ' rotations :: Traversal' Helmert (Dimensionless Double) rotations k (Helmert cX' cY' cZ' helmertScale' rX' rY' rZ') = Helmert cX' cY' cZ' helmertScale' <$> k rX' <*> k rY' <*> k rZ'