module IGraph.Layout
( getLayout
, LayoutMethod(..)
, defaultKamadaKawai
, defaultLGL
) where
import Control.Applicative ((<$>))
import Data.Default.Class
import Data.Maybe (isJust)
import Foreign (nullPtr)
import System.IO.Unsafe (unsafePerformIO)
import IGraph
import IGraph.Internal.Clique
import IGraph.Internal.Data
import IGraph.Internal.Layout
data LayoutMethod =
KamadaKawai { kk_seed :: !(Maybe [(Double, Double)])
, kk_nIter :: !Int
, kk_sigma :: (Int -> Double)
, kk_startTemp :: !Double
, kk_coolFact :: !Double
, kk_const :: (Int -> Double)
}
| LGL { lgl_nIter :: !Int
, lgl_maxdelta :: (Int -> Double)
, lgl_area :: (Int -> Double)
, lgl_coolexp :: !Double
, lgl_repulserad :: (Int -> Double)
, lgl_cellsize :: (Int -> Double)
}
defaultKamadaKawai :: LayoutMethod
defaultKamadaKawai = KamadaKawai
{ kk_seed = Nothing
, kk_nIter = 10
, kk_sigma = \x -> fromIntegral x / 4
, kk_startTemp = 10
, kk_coolFact = 0.99
, kk_const = \x -> fromIntegral $ x^2
}
defaultLGL :: LayoutMethod
defaultLGL = LGL
{ lgl_nIter = 100
, lgl_maxdelta = \x -> fromIntegral x
, lgl_area = area
, lgl_coolexp = 1.5
, lgl_repulserad = \x -> fromIntegral x * area x
, lgl_cellsize = \x -> area x ** 0.25
}
where
area x = fromIntegral $ x^2
getLayout :: Graph d => LGraph d v e -> LayoutMethod -> IO [(Double, Double)]
getLayout gr method = do
case method of
KamadaKawai seed niter sigma initemp coolexp kkconst -> do
mptr <- case seed of
Nothing -> igraphMatrixNew 0 0
Just xs -> if length xs /= nNodes gr
then error "Seed error: incorrect size"
else fromRowLists $ (\(x,y) -> [x,y]) $ unzip xs
igraphLayoutKamadaKawai gptr mptr niter (sigma n) initemp coolexp
(kkconst n) (isJust seed) nullPtr nullPtr nullPtr nullPtr
[x, y] <- toColumnLists mptr
return $ zip x y
LGL niter delta area coolexp repulserad cellsize -> do
mptr <- igraphMatrixNew 0 0
igraphLayoutLgl gptr mptr niter (delta n) (area n) coolexp
(repulserad n) (cellsize n) (-1)
[x, y] <- toColumnLists mptr
return $ zip x y
where
n = nNodes gr
gptr = _graph gr