cpsa-3.4.0: src/CPSA/Graph/Preskeleton.hs
-- Draws preskeletons
-- Copyright (c) 2009 The MITRE Corporation
--
-- This program is free software: you can redistribute it and/or
-- modify it under the terms of the BSD License as published by the
-- University of California.
module CPSA.Graph.Preskeleton (skel) where
import CPSA.Lib.SExpr (SExpr)
import CPSA.Lib.Notation (printMsg, printEnv)
import CPSA.Graph.XMLOutput
import CPSA.Graph.Config
import CPSA.Graph.SVG
import CPSA.Graph.Loader
import CPSA.Graph.Layout
import qualified Data.List as L
showMsg :: Config -> SExpr a -> String
showMsg conf x =
case notation conf of
Prefix -> show x
Infix -> printMsg margin indent x
showEnv :: Config -> SExpr a -> String
showEnv conf x =
case notation conf of
Prefix -> show x
Infix -> printEnv margin indent x
margin :: Int
margin = 1024
indent :: Int
indent = 0
-- Compute a node's position.
npos :: Config -> Rank -> Node -> (Float, Float)
npos conf rank (s, p) =
(xpos, ypos)
where
-- Node x coordinate is determined by its strand
xpos = mx conf + dx conf * fromIntegral s
-- Node y coordinate is determined by its rank
ypos = my conf + dy conf * fromIntegral (rank (s, p) + 1)
-- Dimension of the diagram
dim :: Config -> Int -> Int -> (Float, Float)
dim conf strands maxRank =
(w, h)
where
w = 2 * mx conf + dx conf * fromIntegral (strands - 1)
h = 2 * my conf + dy conf * fromIntegral (maxRank + 1)
-- Add a cross strand arrow
addEdge :: Config -> Rank -> Vertex -> Float -> Float ->
String -> [Element] -> Vertex -> [Element]
addEdge conf rank src x1 y1 color elements n =
let (x2, y2) = npos conf rank (vnode n) in
arrow conf (sameMsg src n) x1 y1 x2 y2 color : elements
sameMsg :: Vertex -> Vertex -> Bool
sameMsg src dest =
case (dir src, dir dest) of
(OutDir, InDir) -> msg src == msg dest
(SyncDir, SyncDir) -> True
_ -> False
-- Add a strand node
addNode :: Config -> Preskel -> Rank -> [Element] -> Vertex -> [Element]
addNode conf k rank elements node =
let (x, y) = npos conf rank (vnode node)
bullet = circ conf (nodeColor k node) x y
es = tooltip (showMsg conf $ msg node) [bullet] : elements
es' = foldl (addEdge conf rank node x y "black") es (succs node L.\\ leadstosuccs node)
es'' = foldl (addEdge conf rank node x y "blue") es' (leadstosuccs node) in
maybe es'' (addNode conf k rank es'') (next node)
nodeColor :: Preskel -> Vertex -> Maybe String
nodeColor k node =
case dir node of
OutDir -> Nothing -- Transmission nodes are black
SyncDir
| elem node (maybe [] id (unrealized k)) -> Just "orange"
| otherwise -> Just "gray" -- Realized nodes are gray
InDir
| elem node (maybe [] id (unrealized k)) -> Just "red"
| otherwise -> Just "blue" -- Realized nodes are blue
-- Add role above a strand
addRole :: Config -> [Element] -> Vertex -> [Element]
addRole conf es node =
if null r then
es
else
tooltip (showEnv conf e) [text conf x y r] : es
where
r = role node
e = env node
(x, y0) = npos conf snd (strand node, 0)
(_, y1) = npos conf snd (strand node, (-1))
y = (y0 + y1) / 2
-- Add strand lines
addStrand :: Config -> Rank -> [Element] -> Vertex -> [Element]
addStrand conf rank es n =
line conf x1 y1 x2 y2 : es
where
(x1, y1) = npos conf rank (vnode n)
(x2, y2) = npos conf rank (vnode (lastVertex n))
-- Add title of diagram
title :: Config -> Preskel -> [Element]
title conf k =
foldl (addRole conf) [header] (initial k)
where
(w, _) = dim conf (strands k) 0
(_, y) = npos conf snd (0, (-1))
content = protocol k ++ " " ++ show (label k)
header = text conf (w / 2) y (content ++ annotation)
annotation =
case unrealized k of
Nothing -> ""
Just [] -> " (realized)"
_ -> ""
-- Draw a preskeleton
skel :: Config -> Preskel -> (Float, Float, [Element])
skel conf k =
(w, h, lines)
where
(w, h) = dim conf (strands k) (maxRank k rank)
circs = foldl (addNode conf k rank) (title conf k) (initial k)
lines = foldl (addStrand conf rank) circs (initial k)
rank = layout k