module Data.Geo.Jord.Tx
(
Tx(..)
, inverseTx
, TxParams(..)
, TxParams7
, TxRates
, TxParams15(..)
, txParams7
, txRates
, txParamsAt
, TxGraph
, txGraph
, txParamsBetween
, transformGeoc
) where
import Data.List (find, foldl', sortOn)
import Data.Maybe (mapMaybe)
import Data.Geo.Jord.Model
import Data.Geo.Jord.Vector3d
data Tx a =
Tx
{ modelA :: ModelId
, modelB :: ModelId
, txParams :: a
}
inverseTx :: (TxParams a) => Tx a -> Tx a
inverseTx t = Tx (modelB t) (modelA t) (inverseTxParams (txParams t))
class TxParams a where
idTxParams :: a
inverseTxParams :: a -> a
data TxParams7 =
TxParams7 !Vector3d !Double !Vector3d
deriving (Show)
instance TxParams TxParams7 where
idTxParams = TxParams7 (Vector3d 0 0 0) 0 (Vector3d 0 0 0)
inverseTxParams (TxParams7 c s r) = TxParams7 (vscale c (-1.0)) (-s) (vscale r (-1.0))
instance TxParams TxParams15 where
idTxParams = TxParams15 (Epoch 0) idTxParams (TxRates (Vector3d 0 0 0) 0 (Vector3d 0 0 0))
inverseTxParams (TxParams15 e p (TxRates c s r)) =
TxParams15 e (inverseTxParams p) (TxRates (vscale c (-1.0)) (-s) (vscale r (-1.0)))
data TxRates =
TxRates !Vector3d !Double !Vector3d
deriving (Show)
data TxParams15 =
TxParams15 Epoch TxParams7 TxRates
deriving (Show)
txParams7 ::
(Double, Double, Double)
-> Double
-> (Double, Double, Double)
-> TxParams7
txParams7 c s r = TxParams7 (mmToMetres c) (s / 1e9) (masToRadians r)
txRates ::
(Double, Double, Double)
-> Double
-> (Double, Double, Double)
-> TxRates
txRates c s r = TxRates (mmToMetres c) (s / 1e9) (masToRadians r)
mmToMetres :: (Double, Double, Double) -> Vector3d
mmToMetres (cx, cy, cz) = vscale (Vector3d cx cy cz) (1.0 / 1000.0)
masToRadians :: (Double, Double, Double) -> Vector3d
masToRadians (rx, ry, rz) = vscale (Vector3d rx ry rz) (pi / (3600.0 * 1000.0 * 180.0))
txParamsAt :: Epoch -> TxParams15 -> TxParams7
txParamsAt (Epoch e) (TxParams15 (Epoch pe) (TxParams7 c s r) (TxRates rc rs rr)) =
TxParams7 c' s' r'
where
de = e - pe
c' = vadd c (vscale rc de)
s' = s + de * rs
r' = vadd r (vscale rr de)
data Connection =
Connection
{ node :: !ModelId
, adjacents :: ![ModelId]
}
data Edge a =
Edge ModelId a ModelId
type Path = [ModelId]
data State =
State [ModelId] [Path]
data TxGraph a =
TxGraph ![Connection] ![Edge a]
txGraph :: (TxParams a) => [Tx a] -> TxGraph a
txGraph = foldl' addTx emptyGraph
txParamsBetween :: (TxParams a) => ModelId -> ModelId -> TxGraph a -> [a]
txParamsBetween m0 m1 g
| m0 == m1 = [idTxParams]
| null ms = []
| otherwise = findParams ms g
where
ms = dijkstra (State [m0] []) m1 g
emptyGraph :: TxGraph a
emptyGraph = TxGraph [] []
addTx :: (TxParams a) => TxGraph a -> Tx a -> TxGraph a
addTx (TxGraph cs es) t = TxGraph cs' es'
where
ma = modelA t
mb = modelB t
cs1 = addConnection cs ma mb
cs' = addConnection cs1 mb ma
txp = txParams t
es' = Edge ma txp mb : Edge mb (inverseTxParams txp) ma : es
addConnection :: [Connection] -> ModelId -> ModelId -> [Connection]
addConnection cs m1 m2
| null filtered = Connection m1 [m2] : cs
| otherwise =
map
(\c' ->
if node c' == m1
then updated
else c')
cs
where
filtered = filter (\c -> node c == m1) cs
cur = head filtered
updated = cur {adjacents = m2 : adjacents cur}
successors :: ModelId -> TxGraph a -> [ModelId]
successors m (TxGraph cs _) = concatMap adjacents (filter (\c -> node c == m) cs)
visit :: ModelId -> [ModelId] -> State -> State
visit f ms (State q0 v0) = State q1 v1
where
toVisit = filter (`notElem` concat v0) ms
fs = filter (\v -> head v == f) v0
q1 = q0 ++ toVisit
updatedPaths = concatMap (\x -> map (: x) toVisit) fs
v1 = updatedPaths ++ filter (\v -> head v /= f) v0
shortest :: ModelId -> ModelId -> [Path] -> [ModelId]
shortest c m ps = reverse (m : s)
where
fs = filter (\v -> head v == c) ps
s = head (sortOn length fs)
dijkstra :: State -> ModelId -> TxGraph a -> [ModelId]
dijkstra (State [] _) _ _ = []
dijkstra (State [c] []) t g = dijkstra (State [c] [[c]]) t g
dijkstra (State (c:r) v) t g
| t `elem` succs = shortest c t v
| otherwise = dijkstra s'' t g
where
s' = State r v
succs = successors c g
s'' = visit c succs s'
findParams :: [ModelId] -> TxGraph a -> [a]
findParams ms (TxGraph _ es)
| length ps == length r = r
| otherwise = []
where
ps = zip ms (tail ms)
r = mapMaybe (`findParam` es) ps
findParam :: (ModelId, ModelId) -> [Edge a] -> Maybe a
findParam p es = fmap (\(Edge _ pa _) -> pa) (find (edgeEq p) es)
edgeEq :: (ModelId, ModelId) -> Edge a -> Bool
edgeEq (m1, m2) (Edge m1' _ m2') = m1 == m1' && m2 == m2'
transformGeoc :: Vector3d -> TxParams7 -> Vector3d
transformGeoc gc (TxParams7 c s r) = vadd c (vscale (vmultm gc (rotation r)) (1.0 + s))
rotation :: Vector3d -> [Vector3d]
rotation (Vector3d x y z) = [Vector3d 1.0 (-z) y, Vector3d z 1.0 (-x), Vector3d (-y) x 1.0]