{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.PlanarGraph.IO where
import Control.Lens
import Control.Monad (forM_)
import Control.Monad.State.Strict
import Data.Aeson
import Data.Bifunctor
import Data.Ext
import qualified Data.Foldable as F
import Data.Maybe (fromJust)
import Data.Permutation
import Data.PlanarGraph.AdjRep (Face(Face), Vtx(Vtx),Gr(Gr))
import Data.PlanarGraph.Core
import Data.PlanarGraph.Dart
import Data.PlanarGraph.Dual
import Data.PlanarGraph.EdgeOracle
import Data.Proxy
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
instance (ToJSON v, ToJSON e, ToJSON f) => ToJSON (PlanarGraph s w v e f) where
toEncoding = toEncoding . toAdjRep
toJSON = toJSON . toAdjRep
instance (FromJSON v, FromJSON e, FromJSON f) => FromJSON (PlanarGraph s Primal v e f) where
parseJSON v = fromAdjRep (Proxy :: Proxy s) <$> parseJSON v
toAdjRep :: PlanarGraph s w v e f -> Gr (Vtx v e) (Face f)
toAdjRep g = Gr vs fs
where
vs = [ Vtx ui (map (mkEdge u) $ F.toList us) (g^.dataOf u)
| (u@(VertexId ui),us) <- toAdjacencyLists g
]
fs = [ Face (outerComponentEdge f) x
| (f,x) <- F.toList $ faces g
]
outerComponentEdge f = bimap (^.unVertexId) (^.unVertexId)
$ endPoints (boundaryDart f g) g
eo = edgeOracle g
findData u v = (\d -> g^.dataOf d) <$> findDart u v eo
mkEdge u v@(VertexId vi) = (vi,fromJust $ findData u v)
fromAdjRep :: proxy s -> Gr (Vtx v e) (Face f) -> PlanarGraph s Primal v e f
fromAdjRep px gr@(Gr as fs) = g&vertexData .~ reorder vs' _unVertexId
&dartData .~ ds
&faceData .~ reorder fs' (_unVertexId._unFaceId)
where
g = buildGraph px gr
oracle = edgeOracle g
findEdge' u v = fromJust $ findDart u v oracle
findFace ui vi = let d = findEdge' (VertexId ui) (VertexId vi) in rightFace d g
vs' = V.fromList [ VertexId vi :+ v | Vtx vi _ v <- as ]
fs' = V.fromList [ findFace ui vi :+ f | Face (ui,vi) f <- fs ]
ds = V.fromList $ concatMap (\(Vtx vi us _) ->
[(findEdge' (VertexId vi) (VertexId ui), x) | (ui,x) <- us]
) as
buildGraph :: proxy s -> Gr (Vtx v e) (Face f) -> PlanarGraph s Primal () () ()
buildGraph _ (Gr as' _) = fromAdjacencyLists as
where
as = [ (VertexId vi, V.fromList [VertexId ui | (ui,_) <- us])
| Vtx vi us _ <- as'
]
reorder :: V.Vector (i :+ a) -> (i -> Int) -> V.Vector a
reorder v f = V.create $ do
v' <- MV.new (V.length v)
forM_ v $ \(i :+ x) ->
MV.write v' (f i) x
pure v'
fromAdjacencyLists :: forall s w h. (Foldable h, Functor h)
=> [(VertexId s w, h (VertexId s w))]
-> PlanarGraph s w () () ()
fromAdjacencyLists adjM = planarGraph' . toCycleRep n $ perm
where
n = sum . fmap length $ perm
perm = map toOrbit $ adjM'
adjM' = fmap (second F.toList) adjM
oracle :: EdgeOracle s w Int
oracle = fmap (^.core) . assignArcs . buildEdgeOracle
. map (second $ map ext) $ adjM'
toOrbit (u,adjU) = concatMap (toDart u) adjU
toDart u v = let Just a = findEdge u v oracle
in case u `compare` v of
LT -> [Dart (Arc a) Positive]
EQ -> [Dart (Arc a) Positive, Dart (Arc a) Negative]
GT -> [Dart (Arc a) Negative]
assignArcs :: EdgeOracle s w e -> EdgeOracle s w (Int :+ e)
assignArcs o = evalState (traverse f o) 0
where
f :: e -> State Int (Int :+ e)
f e = do i <- get ; put (i+1) ; pure (i :+ e)