{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE Safe #-}

{- | 
Module      :  Physics.Learn.CoordinateSystem
Copyright   :  (c) Scott N. Walck 2012-2018
License     :  BSD3 (see LICENSE)
Maintainer  :  Scott N. Walck <walck@lvc.edu>
Stability   :  experimental

A module for working with coordinate systems.
-}

module Physics.Learn.CoordinateSystem
    ( CoordinateSystem(..)
    , standardCartesian
    , standardCylindrical
    , standardSpherical
    , newCoordinateSystem
    )
    where

import Physics.Learn.Position
    ( Position
    , cartesian
    , cartesianCoordinates
    , cylindrical
    , cylindricalCoordinates
    , spherical
    , sphericalCoordinates
    )

-- | Specification of a coordinate system requires
--   a map from coordinates into space, and
--   a map from space into coordinates.
data CoordinateSystem
    = CoordinateSystem { CoordinateSystem -> (Double, Double, Double) -> Position
toPosition   :: (Double,Double,Double) -> Position  -- ^ a map from coordinates into space
                       , CoordinateSystem -> Position -> (Double, Double, Double)
fromPosition :: Position -> (Double,Double,Double)  -- ^ a map from space into coordinates
                       }

-- | The standard Cartesian coordinate system
standardCartesian :: CoordinateSystem
standardCartesian :: CoordinateSystem
standardCartesian = ((Double, Double, Double) -> Position)
-> (Position -> (Double, Double, Double)) -> CoordinateSystem
CoordinateSystem (Double, Double, Double) -> Position
cartesian Position -> (Double, Double, Double)
cartesianCoordinates

-- | The standard cylindrical coordinate system
standardCylindrical :: CoordinateSystem
standardCylindrical :: CoordinateSystem
standardCylindrical = ((Double, Double, Double) -> Position)
-> (Position -> (Double, Double, Double)) -> CoordinateSystem
CoordinateSystem (Double, Double, Double) -> Position
cylindrical Position -> (Double, Double, Double)
cylindricalCoordinates

-- | The standard spherical coordinate system
standardSpherical :: CoordinateSystem
standardSpherical :: CoordinateSystem
standardSpherical = ((Double, Double, Double) -> Position)
-> (Position -> (Double, Double, Double)) -> CoordinateSystem
CoordinateSystem (Double, Double, Double) -> Position
spherical Position -> (Double, Double, Double)
sphericalCoordinates

-- | Define a new coordinate system in terms of an existing one.
--   First parameter is a map from old coordinates to new coordinates.
--   Second parameter is the inverse map from new coordinates to old coordinates.
newCoordinateSystem :: ((Double,Double,Double) -> (Double,Double,Double))  -- ^ (x',y',z') = f(x,y,z)
                    -> ((Double,Double,Double) -> (Double,Double,Double))  -- ^ (x,y,z) = g(x',y',z')
                    -> CoordinateSystem  -- ^ old coordinate system
                    -> CoordinateSystem
newCoordinateSystem :: ((Double, Double, Double) -> (Double, Double, Double))
-> ((Double, Double, Double) -> (Double, Double, Double))
-> CoordinateSystem
-> CoordinateSystem
newCoordinateSystem (Double, Double, Double) -> (Double, Double, Double)
f (Double, Double, Double) -> (Double, Double, Double)
g (CoordinateSystem (Double, Double, Double) -> Position
tp Position -> (Double, Double, Double)
fp)
    = ((Double, Double, Double) -> Position)
-> (Position -> (Double, Double, Double)) -> CoordinateSystem
CoordinateSystem ((Double, Double, Double) -> Position
tp forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double, Double, Double) -> (Double, Double, Double)
g) ((Double, Double, Double) -> (Double, Double, Double)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Position -> (Double, Double, Double)
fp)