packages feed

wumpus-tree 0.12.0 → 0.13.0

raw patch · 8 files changed

+504/−184 lines, 8 filesdep +wumpus-drawingdep ~wumpus-basicdep ~wumpus-corePVP ok

version bump matches the API change (PVP)

Dependencies added: wumpus-drawing

Dependency ranges changed: wumpus-basic, wumpus-core

API changes (from Hackage documentation)

- Wumpus.Tree: type DTreeDrawing = TreeDrawing Double
- Wumpus.Tree: type TreeDrawing u = Drawing u
- Wumpus.Tree: uniformScaling :: Num u => u -> ScaleFactors u
- Wumpus.Tree.Design: instance Eq (XPos u) => Eq (Extent u)
- Wumpus.Tree.Design: instance Eq (XPos u) => Eq (Span u)
- Wumpus.Tree.Design: instance Ord (XPos u) => Ord (Span u)
- Wumpus.Tree.Design: instance Show (XPos u) => Show (Extent u)
- Wumpus.Tree.Design: instance Show (XPos u) => Show (Span u)
+ Wumpus.Tree: TREE_DOWN :: TreeDirection
+ Wumpus.Tree: TREE_LEFT :: TreeDirection
+ Wumpus.Tree: TREE_RIGHT :: TreeDirection
+ Wumpus.Tree: TREE_UP :: TreeDirection
+ Wumpus.Tree: data TreeDirection
+ Wumpus.Tree: drawScaledTreeD :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) => ScaleFactors u -> Point2 u -> TreeDirection -> TreeBuildAns u -> TreeDrawing u
+ Wumpus.Tree: instance Eq TreeDirection
+ Wumpus.Tree: instance Ord TreeDirection
+ Wumpus.Tree: instance Show TreeDirection
+ Wumpus.Tree: uniformSF :: Num u => u -> ScaleFactors u
+ Wumpus.Tree.Base: Design :: CoordTree u a -> BoundingBox u -> Design u a
+ Wumpus.Tree.Base: data Design u a
+ Wumpus.Tree.Base: tree_bbox :: Design u a -> BoundingBox u
+ Wumpus.Tree.Base: tree_design :: Design u a -> CoordTree u a
+ Wumpus.Tree.Design: instance Eq u => Eq (Extent u)
+ Wumpus.Tree.Design: instance Eq u => Eq (HSpan u)
+ Wumpus.Tree.Design: instance Ord u => Ord (HSpan u)
+ Wumpus.Tree.Design: instance Show u => Show (Extent u)
+ Wumpus.Tree.Design: instance Show u => Show (HSpan u)
+ Wumpus.Tree.Design: rotateAboutRoot :: (Real u, Floating u) => Radian -> CoordTree u a -> CoordTree u a
+ Wumpus.Tree.TreeBuildMonad: annotate :: u ~ (DUnit a) => NodeId a -> NodeAnno u -> TreeBuild u ()
+ Wumpus.Tree.TreeBuildMonad: branch :: NodeId a -> [TreeSpec a] -> TreeSpec a
+ Wumpus.Tree.TreeBuildMonad: data NodeId a
+ Wumpus.Tree.TreeBuildMonad: data TreeBuild u a
+ Wumpus.Tree.TreeBuildMonad: instance Applicative (TreeBuild u)
+ Wumpus.Tree.TreeBuildMonad: instance Eq a => Eq (NodeId a)
+ Wumpus.Tree.TreeBuildMonad: instance Functor (TreeBuild u)
+ Wumpus.Tree.TreeBuildMonad: instance Monad (TreeBuild u)
+ Wumpus.Tree.TreeBuildMonad: label :: a -> NodeId a
+ Wumpus.Tree.TreeBuildMonad: leaf :: NodeId a -> TreeSpec a
+ Wumpus.Tree.TreeBuildMonad: nodeId :: TreeNode u -> TreeBuild u (NodeId a)
+ Wumpus.Tree.TreeBuildMonad: regularBuild :: Tree a -> TreeBuild u (TreeSpec a)
+ Wumpus.Tree.TreeBuildMonad: runTreeBuild :: (Real u, Floating u, FromPtSize u) => (a -> TreeNode u) -> TreeBuild u (TreeSpec a) -> TreeBuildAns u
+ Wumpus.Tree.TreeBuildMonad: type NodeAnno u = DotAnchor u -> Graphic u
+ Wumpus.Tree.TreeBuildMonad: type NodeAnnoRefs u = IntMap (NodeAnno u)
+ Wumpus.Tree.TreeBuildMonad: type TreeBuildAns u = (Tree (TreeNodeAns u), NodeAnnoRefs u)
+ Wumpus.Tree.TreeBuildMonad: type TreeNodeAns u = (TreeNode u, Maybe Int)
+ Wumpus.Tree.TreeBuildMonad: type TreeSpec a = Tree (NodeId a)
+ Wumpus.Tree.TreeBuildMonad: type ZNodeId u = NodeId (UNil u)
+ Wumpus.Tree.TreeBuildMonad: type ZTreeSpec u = TreeSpec (UNil u)
+ Wumpus.Tree.TreeBuildMonad: zbranch :: [ZTreeSpec u] -> ZTreeSpec u
+ Wumpus.Tree.TreeBuildMonad: zleaf :: ZTreeSpec u
- Wumpus.Tree: drawScaledFamilyTree :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) => (a -> TreeNode u) -> ScaleFactors u -> Tree a -> TreeDrawing u
+ Wumpus.Tree: drawScaledFamilyTree :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) => ScaleFactors u -> Point2 u -> TreeBuildAns u -> TreeDrawing u
- Wumpus.Tree: drawScaledTree :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) => (a -> TreeNode u) -> ScaleFactors u -> Tree a -> TreeDrawing u
+ Wumpus.Tree: drawScaledTree :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) => ScaleFactors u -> Point2 u -> TreeBuildAns u -> TreeDrawing u
- Wumpus.Tree.Base: type TreeDrawing u = Drawing u
+ Wumpus.Tree.Base: type TreeDrawing u = TraceDrawing u ()
- Wumpus.Tree.Design: design :: (Fractional u, Ord u) => ScalingContext u Int u -> Tree a -> CoordTree u a
+ Wumpus.Tree.Design: design :: (Fractional u, Ord u) => Point2 u -> ScalingContext u Int u -> Tree a -> CoordTree u a
- Wumpus.Tree.Draw: drawFamilyTree :: (Real u, Floating u, FromPtSize u) => (a -> TreeNode u) -> CoordTree u a -> Drawing u
+ Wumpus.Tree.Draw: drawFamilyTree :: (Real u, Floating u, FromPtSize u) => NodeAnnoRefs u -> CoordTree u (TreeNodeAns u) -> TreeDrawing u
- Wumpus.Tree.Draw: drawTree :: (Real u, Floating u, FromPtSize u) => (a -> TreeNode u) -> CoordTree u a -> Drawing u
+ Wumpus.Tree.Draw: drawTree :: (Real u, Floating u, FromPtSize u) => NodeAnnoRefs u -> CoordTree u (TreeNodeAns u) -> TreeDrawing u

Files

demo/Demo01.hs view
@@ -15,6 +15,7 @@ module Demo01 where  import Wumpus.Tree+import Wumpus.Tree.TreeBuildMonad  import Wumpus.Basic.Kernel                      -- package: wumpus-basic import Wumpus.Basic.System.FontLoader.Afm@@ -53,113 +54,106 @@  makePictures :: GlyphMetrics -> IO () makePictures base_metrics = do -    ---    let pic1 = runDrawingU (makeCtx 18 base_metrics) tree_drawing1-    writeEPS "./out/tree01.eps"  pic1-    writeSVG "./out/tree01.svg"  pic1-    ---    let pic2 = runDrawingU (makeCtx 24 base_metrics) tree_drawing2-    writeEPS "./out/tree02.eps"  pic2-    writeSVG "./out/tree02.svg"  pic2-    ---    let pic3 = runDrawingU (makeCtx 14 base_metrics) tree_drawing3-    writeEPS "./out/tree03.eps"  pic3-    writeSVG "./out/tree03.svg"  pic3-    ---    let pic4 = runDrawingU (makeCtx 24 base_metrics) tree_drawing4-    writeEPS "./out/tree04.eps"  pic4-    writeSVG "./out/tree04.svg"  pic4-    ---    let pic5 = runDrawingU (makeCtx 24 base_metrics) tree_drawing5-    writeEPS "./out/tree05.eps"  pic5-    writeSVG "./out/tree05.svg"  pic5+    let pic1 = runCtxPictureU (makeCtx 18 base_metrics) tree_pic1+    writeEPS "./out/regular_tree01.eps"  pic1+    writeSVG "./out/regular_tree01.svg"  pic1 ++ makeCtx :: FontSize -> GlyphMetrics -> DrawingContext makeCtx sz m = fontFace times_roman $ metricsContext sz m   -tree_drawing1 :: DTreeDrawing-tree_drawing1 = drawScaledTree charNode  (uniformScaling 30) tree1+tree_pic1 :: DCtxPicture+tree_pic1 = drawTracing $ do+    --+    draw $ textline "Tree 1:"        `at` (P2 0  530)+    drawScaledTree (uniformSF 30)         (P2 80 530) $ +       runTreeBuild charNode tree1+    --+    draw $ textline "Tree 2:"       `at` (P2 160 530) +    drawScaledTree (uniformSF 30)        (P2 240 530) $ +        runTreeBuild (diskNode red) tree2 -tree_drawing2 :: DTreeDrawing-tree_drawing2 = drawScaledTree (diskNode red) (uniformScaling 30) tree2+    draw $ textline "Tree 3:"       `at` (P2 0  410) +    localize (fontSize 12) $ +        drawScaledFamilyTree (uniformSF 25) (P2 280 410) $ +          runTreeBuild charNode tree3 --- This should be drawn in the /family tree/ style...--- -tree_drawing3 :: DTreeDrawing-tree_drawing3 = drawScaledFamilyTree charNode (uniformScaling 25) tree3+    --+    draw $ textline "Tree 4:"       `at` (P2 0  200)+    drawScaledTree (scaleFactors 20 30)  (P2 80 200) $ +        runTreeBuild (circleNode black) tree4+    --+    draw $ textline "Tree 5:"        `at` zeroPt+    drawScaledTree (scaleFactors 20 30)  (P2 240 0) $+        runTreeBuild (circleNode black)  tree5  -tree_drawing4 :: DTreeDrawing-tree_drawing4 = drawScaledTree (circleNode black) (scaleFactors 20 30) tree4 -tree_drawing5 :: DTreeDrawing-tree_drawing5 = drawScaledTree (circleNode black) (scaleFactors 20 30) tree5+tree1 :: TreeBuild u (TreeSpec Char)+tree1 = regularBuild $ Node 'A' [Node 'B' bs, Node 'F' fs]+  where+    bs = [Node 'C' [], Node 'D' [], Node 'E' []]+    fs = [Node 'G' [Node 'H' [], Node 'I' [], Node 'J' []]]  -tree1 :: Tree Char-tree1 = Node 'A' [Node 'B' bs, Node 'F' fs]+tree2 :: TreeBuild u (TreeSpec Char)+tree2 = regularBuild $ Node 'A' [Node 'B' bs, Node 'F' [], Node 'G' gs]   where-   bs = [Node 'C' [], Node 'D' [], Node 'E' []]-   fs = [Node 'G' [Node 'H' [], Node 'I' [], Node 'J' []]]+    bs = [Node 'C' [], Node 'D' [], Node 'E' []]+    gs = [Node 'H' [], Node 'I' [], Node 'J' []] -tree2 :: Tree Char-tree2 = Node 'A' [Node 'B' bs, Node 'F' [], Node 'G' gs]-  where-   bs = [Node 'C' [], Node 'D' [], Node 'E' []]-   gs = [Node 'H' [], Node 'I' [], Node 'J' []]  -- This is the tree from Andrew Kennedy's  -- /Functional Pearl Drawing Trees/ ----- Currently Wumpus-tree cannot render in the /family tree/ style.----tree3 :: Tree Char-tree3 = Node 'A' [a1, a2, a3]+tree3 :: TreeBuild u (TreeSpec Char)+tree3 = regularBuild $ Node 'A' [a1, a2, a3]   where     a1 = Node 'B' [b1, b2]     a2 = Node 'S' [b3,b4]     a3 = Node 'o' [b5]-    b1 = Node 'C' [leaf 'D', c1]-    b2 = Node 'P' [leaf 'Q', leaf 'R']-    b3 = Node 'T' [leaf 'U', leaf 'V', c2]-    b4 = Node 'e' [c3, leaf 'h', c4]-    b5 = Node 'p' [c5, c6, leaf '2']+    b1 = Node 'C' [tleaf 'D', c1]+    b2 = Node 'P' [tleaf 'Q', tleaf 'R']+    b3 = Node 'T' [tleaf 'U', tleaf 'V', c2]+    b4 = Node 'e' [c3, tleaf 'h', c4]+    b5 = Node 'p' [c5, c6, tleaf '2']     c1 = Node 'E' [d1]     c2 = Node 'W' [d2, d3]-    c3 = Node 'f' [leaf 'g']+    c3 = Node 'f' [tleaf 'g']     c4 = Node 'i' [d4]-    c5 = Node 'q' [leaf 'r', leaf 's', leaf 't', leaf 'u']-    c6 = Node 'v' [leaf 'w', d5, leaf '0', leaf '1']-    d1 = Node 'F' [leaf 'G', e1, leaf 'M', e2]-    d2 = Node 'X' [leaf 'Y']-    d3 = Node 'Z' [leaf 'a', leaf 'b', leaf 'c', leaf 'd']-    d4 = Node 'j' [leaf 'k', leaf 'l', leaf 'm', leaf 'n']-    d5 = Node 'x' [leaf 'y', leaf 'z'] -    e1 = Node 'H' [leaf 'I', leaf 'J', leaf 'K', leaf 'L']-    e2 = Node 'N' [leaf 'O']+    c5 = Node 'q' [tleaf 'r', tleaf 's', tleaf 't', tleaf 'u']+    c6 = Node 'v' [tleaf 'w', d5, tleaf '0', tleaf '1']+    d1 = Node 'F' [tleaf 'G', e1, tleaf 'M', e2]+    d2 = Node 'X' [tleaf 'Y']+    d3 = Node 'Z' [tleaf 'a', tleaf 'b', tleaf 'c', tleaf 'd']+    d4 = Node 'j' [tleaf 'k', tleaf 'l', tleaf 'm', tleaf 'n']+    d5 = Node 'x' [tleaf 'y', tleaf 'z'] +    e1 = Node 'H' [tleaf 'I', tleaf 'J', tleaf 'K', tleaf 'L']+    e2 = Node 'N' [tleaf 'O'] -leaf :: a -> Tree a-leaf a = Node a []+tleaf :: a -> Tree a+tleaf a = Node a []   -- This is the tree (a) T3 from Buchheim, Junger and Leipert -- /Improving Walker\'s Algorithm to Run in Linear Time/. -- -tree4 :: Tree Int-tree4 = Node 1 [a1, a2]+tree4 :: TreeBuild u (TreeSpec Int)+tree4 = regularBuild $ Node 1 [a1, a2]   where     a1 = Node  2 [b1]     a2 = Node  3 [b2, b3]     b1 = Node  4 [c1]     b2 = Node  5 [c2]-    b3 = Node  6 [leaf 9, c3]+    b3 = Node  6 [tleaf 9, c3]     c1 = Node  7 [d1]-    c2 = Node  8 [leaf 12]+    c2 = Node  8 [tleaf 12]     c3 = Node 10 [d2] -    d1 = Node 11 [leaf 14]-    d2 = Node 13 [leaf 15]+    d1 = Node 11 [tleaf 14]+    d2 = Node 13 [tleaf 15]  -- This is the tree (b) T3 from Buchheim, Junger and Leipert -- /Improving Walker\'s Algorithm to Run in Linear Time/.@@ -168,13 +162,14 @@ -- spaces the leaves, it looks like the trees in that paper are  -- evenly spaced at the interior nodes too. -- -tree5 :: Tree Int-tree5 = Node 1 [a1, leaf 3, leaf 4, leaf 5, a2, leaf 7, leaf 8, leaf 9, a3]+tree5 :: TreeBuild u (TreeSpec Int)+tree5 = regularBuild $+    Node 1 [a1, tleaf 3, tleaf 4, tleaf 5, a2, tleaf 7, tleaf 8, tleaf 9, a3]   where-    a1 = Node  2 [leaf 11, leaf 12, leaf 13, leaf 14, leaf 15, leaf 16-                 , leaf 17, leaf 18, leaf 19, leaf 20, b1]-    a2 = Node  6 [leaf 22]-    a3 = Node 10 [b2]-    b1 = Node 21 [leaf 24, leaf 25, leaf 26, leaf 27, leaf 28, leaf 29-                 ,leaf 30, leaf 31, leaf 32, leaf 33, leaf 34]-    b2 = Node 23 [leaf 35]+    a1 = Node  2 [ tleaf 11, tleaf 12, tleaf 13, tleaf 14, tleaf 15, tleaf 16+                 , tleaf 17, tleaf 18, tleaf 19, tleaf 20, b1]+    a2 = Node  6 [ tleaf 22 ]+    a3 = Node 10 [ b2 ]+    b1 = Node 21 [ tleaf 24, tleaf 25, tleaf 26, tleaf 27, tleaf 28, tleaf 29+                 , tleaf 30, tleaf 31, tleaf 32, tleaf 33, tleaf 34]+    b2 = Node 23 [ tleaf 35 ]
src/Wumpus/Tree.hs view
@@ -17,14 +17,15 @@ module Wumpus.Tree   (   -- * The type of rendered trees-    TreeDrawing-  , DTreeDrawing        -- re-export. -  , ScaleFactors-  , uniformScaling+    ScaleFactors+  , uniformSF   , scaleFactors    , drawScaledTree+  , TreeDirection(..)+  , drawScaledTreeD+   , drawScaledFamilyTree  @@ -40,6 +41,7 @@ import Wumpus.Tree.Base import Wumpus.Tree.Design import Wumpus.Tree.Draw+import Wumpus.Tree.TreeBuildMonad  import Wumpus.Basic.Kernel                      -- package: wumpus-basic import Wumpus.Drawing.Dots.AnchorDots@@ -48,7 +50,6 @@  import Data.VectorSpace                         -- package: vector-space -import Data.Tree hiding ( drawTree )   @@ -71,48 +72,55 @@  -- | Build uniform x- and y-scaling factors, i.e. @ x == y @. ---uniformScaling :: Num u => u -> ScaleFactors u-uniformScaling u = ScalingContext (\x -> u * x)-                                  (\y -> u * fromIntegral y) +uniformSF :: Num u => u -> ScaleFactors u+uniformSF u = ScalingContext (\x -> u * x)+                             (\y -> u * fromIntegral y)  + scaleFactors :: Num u => u -> u -> ScaleFactors u scaleFactors sx sy = ScalingContext (\x -> sx * x)                                     (\y -> sy * fromIntegral y)	  --- | 'drawTreePicture' : @ draw_fun * attr * scale_factors * tree -> TreePicture @------ The rendering function.+ -- --- @draw_fun@ renders the individual nodes. Usually 'charNode', --- 'circleNode'------ @attr@ is the font size (translates to node size), stroke --- colour, fill colour.------ @scale_factors@ scales the distances between parent and child --- (y-scale) and sibling nodes (x-scale).------ @tree@ is the input tree to be rendered.------+ drawScaledTree :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) -                => (a -> TreeNode u) -                -> ScaleFactors u-                -> Tree a +               => ScaleFactors u -> Point2 u -> TreeBuildAns u +               -> TreeDrawing u+drawScaledTree scale_f ogin (tree,annos) = +    drawTree annos $ design ogin scale_f tree++++data TreeDirection = TREE_UP | TREE_DOWN | TREE_LEFT | TREE_RIGHT+  deriving (Eq,Ord,Show)++drawScaledTreeD :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) +                => ScaleFactors u -> Point2 u +                -> TreeDirection -> TreeBuildAns u                  -> TreeDrawing u-drawScaledTree drawF scale_f tree = drawTree drawF $ design scale_f tree+drawScaledTreeD scale_f ogin tdir (tree,annos) = +    drawTree annos $ rotTree tdir $ design ogin scale_f tree    +rotTree :: (Real u, Floating u) +        => TreeDirection -> CoordTree u a -> CoordTree u a+rotTree TREE_UP     = rotateAboutRoot pi+rotTree TREE_DOWN   = id+rotTree TREE_LEFT   = rotateAboutRoot (1.5*pi)+rotTree TREE_RIGHT  = rotateAboutRoot (0.5*pi)++++ drawScaledFamilyTree :: (Real u, Floating u, FromPtSize u, InnerSpace (Vec2 u)) -                     => (a -> TreeNode u) -                     -> ScaleFactors u-                     -> Tree a -                     -> TreeDrawing u-drawScaledFamilyTree drawF scale_f tree = -    drawFamilyTree drawF $ design scale_f tree+               => ScaleFactors u -> Point2 u -> TreeBuildAns u +               -> TreeDrawing u+drawScaledFamilyTree scale_f ogin (tree,annos) = +    drawFamilyTree annos $ design ogin scale_f tree  -------------------------------------------------------------------------------- -- Drawing functions
src/Wumpus/Tree/Base.hs view
@@ -17,12 +17,15 @@  module Wumpus.Tree.Base   (+     TreeDrawing   , DTreeDrawing   , CoordTree      , TreeNode +  , Design(..)+   ) where  import Wumpus.Basic.Kernel                      -- package: wumpus-basic@@ -32,21 +35,35 @@  import Data.Tree + -- | A rendered tree - alias for for @Picture Double@ in  -- Wumpus-Core. ---type TreeDrawing u = Drawing u+type TreeDrawing u      = TraceDrawing u () -type DTreeDrawing = TreeDrawing Double+type DTreeDrawing       = TreeDrawing Double  +++ -- | Tree annotated with positions. -- type CoordTree u a = Tree (Point2 u, a)   +-- | Tree nodes are currently a /Dot/ from Wumpus-Drawing.+--+-- At some point this should change to allow any object that +-- supports anchors.+-- type TreeNode u = DotLocImage u ++data Design u a = Design +      { tree_design     :: CoordTree u a+      , tree_bbox       :: BoundingBox u+      }  
src/Wumpus/Tree/Design.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# OPTIONS -Wall #-} @@ -26,6 +27,7 @@ module Wumpus.Tree.Design   (     design+  , rotateAboutRoot   )   where @@ -33,12 +35,15 @@  import Wumpus.Basic.Kernel              -- package: wumpus-basic +import Wumpus.Core                      -- package: wumpus-core+ import Data.List  import Data.Maybe import Data.Tree   + -- | XPos is an absolute position -- type XPos u = u     @@ -50,30 +55,35 @@ -- type Delta u = u -data Span u = S !(XPos u) !(XPos u)+-- A horizontal span.+--+data HSpan u = HSpan !u !u   deriving (Eq,Ord,Show)   -outsideMerge :: Span u -> Span u -> Span u-outsideMerge (S p _) (S _ q) = S p q+outsideMerge :: HSpan u -> HSpan u -> HSpan u+outsideMerge (HSpan p _) (HSpan _ q) = HSpan p q -moveSpan :: Num u => Delta u -> Span u -> Span u-moveSpan d (S p q) = S (p+d) (q+d)  -newtype Extent u = Extent { span_list :: [Span u] }++moveSpan :: Num u => Delta u -> HSpan u -> HSpan u+moveSpan d (HSpan p q) = HSpan (p+d) (q+d)+++newtype Extent u = Extent { span_list :: [HSpan u] }   deriving (Eq,Show)  -extlink :: XPos u -> Extent u -> Extent u-extlink a (Extent as) = Extent (S a a:as)+extlink :: u -> Extent u -> Extent u+extlink a (Extent as) = Extent $ (HSpan a a) :as   -- note is this just for left ... ? ---midtop :: Fractional u => XPos u -> Extent u -> XPos u+midtop :: Fractional u => u -> Extent u -> XPos u midtop r (Extent [])        = r-midtop _ (Extent (S p q:_)) = p + (0.5*(q-p))+midtop _ (Extent (HSpan p q:_)) = p + (0.5*(q-p))   -- merge \"moving right\"...@@ -100,7 +110,7 @@ extentZero = Extent []  extentOne :: XPos u -> Extent u-extentOne x = Extent [S x x]+extentOne x = Extent [HSpan x x]   -- 'moveTree' is now recursive...@@ -114,10 +124,10 @@  fit :: (Fractional u, Ord u)      => Extent u -> Extent u -> u-fit a b = step (span_list a) (span_list b) 0.0 +fit a b = go (span_list a) (span_list b) 0.0    where-    step (S _ p:ps) (S q _:qs) acc = step ps qs (max acc (p - q + 1.0))-    step _          _          acc = acc  +    go (HSpan _ p:ps) (HSpan q _:qs) acc = go ps qs (max acc (p - q + 1.0))+    go _          _                  acc = acc     -- Fitting the children of a node...@@ -182,37 +192,72 @@     ext1            = xpos `extlink` ext0  +-- | Design a tree, properly balancing the child nodes oriented +-- at root. +--+-- As the design has no y-positions (but by recursion they can be +-- counted) and x-positions are respective to the unit distance +-- 1.0 separating nodes it is rescaled as a post-processing step+-- into drawable coordinates. +-- design :: (Fractional u, Ord u)-       => ScalingContext u Int u -> Tree a -> CoordTree u a-design sctx t = runScaling sctx (label 0 t3)+       => Point2 u -> ScalingContext u Int u -> Tree a -> CoordTree u a+design ro sctx t = rootOrientate ro $ scaleDesign sctx 0 t3   where     (t1,ext)                    = designl t-    (h,S xmin xmax)             = stats ext+    (_, HSpan xmin xmax)        = stats ext     width                       = xmax - xmin     (t2,_)                      = designr width t          -- reconcile the left and right drawings...     t3                          = treeZipWith zfn t1 t2+    zfn (x0,a) (x1,_)           = (mean x0 x1,a)+++-- Scale the tree. Originally the tree has no y-positions (but by +-- recursion they can be counted) and x-positions are respective +-- to the unit width 1.0.+--+scaleDesign :: Num uy +            => ScalingContext ux uy u -> uy -> Tree (XPos ux, a) -> CoordTree u a+scaleDesign ctx lvl (Node (xpos,a) kids) = Node (pt,a) kids'+  where+    pt    = scalePt ctx xpos lvl+    kids' = map (scaleDesign ctx (lvl-1)) kids+          -    mkPt x lvl                  = scalePt x (h - lvl)-    label lvl (Node (x,a) kids) = do pt <- mkPt x lvl-                                     kids' <- mapM (label (lvl+1)) kids-                                     return $ Node (pt,a) kids' -    zfn (x0,a) (x1,_)           = (mean x0 x1,a)+rootOrientate :: Num u => Point2 u -> CoordTree u a -> CoordTree u a+rootOrientate (P2 ox oy) (Node (P2 x0 y0, val) kids) = +    Node (P2 ox oy, val) $ map (mv (ox-x0) (oy-y0)) kids+  where+    mv dx dy (Node (P2 x y, a) ks) = let ks' = map (mv dx dy) ks +                                     in Node (P2 (x+dx) (y+dy), a) ks'  +rotateAboutRoot :: (Real u, Floating u) +                => Radian -> CoordTree u a -> CoordTree u a+rotateAboutRoot ang (Node (ogin,val) kids) =  +    Node (ogin, val) $ map step kids+  where+    step (Node (p0, a) ks) = Node (rotA p0, a) $ map step ks +    rotA                   = rotateAbout ang ogin+ -- find height and width ---stats :: (Num u, Ord u) => Extent u -> (Int, Span u)-stats (Extent [])     = (0,S 0 0)+stats :: (Num u, Ord u) => Extent u -> (Int, HSpan u)+stats (Extent [])     = (0,HSpan 0 0) stats (Extent (e:es)) = foldr fn (1,e) es   where-    fn (S x0 x1) (h, S xmin xmax) = (h+1, S (min x0 xmin) (max x1 xmax))+    fn s1 (h, acc_span) = (h+1, minmaxMerge s1 acc_span)  mean :: Fractional u => u -> u -> u mean x y = (x+y) / 2.0+++minmaxMerge :: Ord u => HSpan u -> HSpan u -> HSpan u+minmaxMerge (HSpan p q) (HSpan p' q') = HSpan (min p p') (max q q')   treeZipWith :: (a -> b -> c) -> Tree a -> Tree b -> Tree c
src/Wumpus/Tree/Draw.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE FlexibleContexts           #-} {-# OPTIONS -Wall #-} @@ -23,6 +24,7 @@   ) where  import Wumpus.Tree.Base+import Wumpus.Tree.TreeBuildMonad  import Wumpus.Basic.Kernel                      -- package: wumpus-basic import Wumpus.Drawing.Dots.AnchorDots@@ -32,39 +34,53 @@   import Control.Monad+import qualified Data.IntMap as IntMap import Data.Tree hiding ( drawTree )   ------------------------------------------------------------------------------------- Draw individual connector between parent and each child node.  drawTree :: (Real u, Floating u, FromPtSize u) -         => (a -> TreeNode u) -         -> CoordTree u a -         -> Drawing u-drawTree drawF tree = drawTracing $ drawTop drawF tree +          => NodeAnnoRefs u -> CoordTree u (TreeNodeAns u) -> TreeDrawing u+drawTree annos tree = drawStep annos radialConns tree >> return ()  -drawTop :: (Real u, Floating u) -        => (a -> TreeNode u) -> CoordTree u a -> TraceDrawing u ()-drawTop fn (Node (pt,a) ns) = do -    ancr <- drawi $ fn a `at` pt-    mapM_ (draw1 fn ancr) ns -draw1 :: (Real u, Floating u)-      => (a -> TreeNode u) -      -> DotAnchor u -      -> CoordTree u a -      -> TraceDrawing u ()-draw1 fn ancr_from (Node (pt,a) ns) = do-    ancr <- drawi $ fn a `at` pt-    draw $ connector ancr_from ancr-    mapM_ (draw1 fn ancr) ns   +drawFamilyTree :: (Real u, Floating u, FromPtSize u) +          => NodeAnnoRefs u -> CoordTree u (TreeNodeAns u) -> TreeDrawing u+drawFamilyTree annos tree = drawStep annos familyConn tree >> return ()  -connector :: (Real u, Floating u) -          => DotAnchor u -> DotAnchor u -> Graphic u+drawStep :: (Real u, Floating u) +         => NodeAnnoRefs u +         -> (DotAnchor u -> [DotAnchor u] -> Graphic u)+         -> CoordTree u (TreeNodeAns u) -> TraceDrawing u (DotAnchor u)+drawStep annos connF (Node (pt,(fn, mb_ix)) ns) = do +    ancr <- drawi $ fn `at` pt+    xs   <- mapM (drawStep annos connF) ns   +    when (not $ null xs) $ draw $ connF ancr xs+    drawAnno annos ancr mb_ix+    return ancr++drawAnno :: NodeAnnoRefs u -> DotAnchor u -> Maybe Int -> TraceDrawing u ()+drawAnno _    _    Nothing   = return ()+drawAnno refs ancr (Just ix) = maybe (return ()) sk $ IntMap.lookup ix refs+  where+    sk fn = draw $ fn ancr++++radialConns :: ( Real u, Floating u+               , CenterAnchor a, RadialAnchor a, u ~ DUnit a ) +            => a -> [a] -> Graphic u+radialConns a []            = emptyLocGraphic `at` center a+radialConns a (x:xs)        = oconcat (connector a x) (map (connector a) xs)++++connector :: ( Real u, Floating u+             , CenterAnchor a, RadialAnchor a, u ~ DUnit a )  +          => a -> a -> Graphic u connector a1 a2 = openStroke $ vertexPath [p1,p2]   where       (ang0,ang1)    = anchorAngles (center a1) (center a2)@@ -74,34 +90,27 @@   -anchorAngles :: (Floating u, Real u) +anchorAngles :: (Real u, Floating u)               => Point2 u -> Point2 u -> (Radian,Radian) anchorAngles f t = (theta0, theta1)   where     conn_v  = pvec f t-    theta0  = direction conn_v+    theta0  = vdirection conn_v     theta1  = if theta0 < pi then theta0 + pi else theta0 - pi      ------------------------------------------------------------------------------------ Draw in /family tree/ style -drawFamilyTree :: (Real u, Floating u, FromPtSize u) -               => (a -> TreeNode u) -               -> CoordTree u a -               -> Drawing u-drawFamilyTree drawF tree = drawTracing $ drawFamily drawF tree   -drawFamily :: (Fractional u, Ord u) -           => (a -> TreeNode u)  -           -> CoordTree u a -           -> TraceDrawing u (DotAnchor u)-drawFamily fn (Node (pt,a) ns) = do-    ancr <- drawi $ fn a `at` pt-    xs   <- mapM (drawFamily fn) ns   -    when (not $ null xs) $ draw $ famconn (south ancr) (map north xs)-    return ancr++--------------------------------------------------------------------------------+-- ++familyConn :: ( Real u, Fractional u+              , CenterAnchor a, CardinalAnchor a, u ~ DUnit a ) +           => a -> [a] -> Graphic u+familyConn a []            = emptyLocGraphic `at` center a+familyConn a xs            = famconn (south a) (map north xs)  famconn :: (Fractional u, Ord u) => Point2 u -> [Point2 u] -> Graphic u famconn _       []         = error "famconn - empty list"
+ src/Wumpus/Tree/TreeBuildMonad.hs view
@@ -0,0 +1,217 @@+{-# LANGUAGE TypeFamilies               #-}+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Tree.TreeBuildMonad+-- Copyright   :  (c) Stephen Tetley 2010+-- License     :  BSD3+--+-- Maintainer  :  stephen.tetley@gmail.com+-- Stability   :  unstable+-- Portability :  GHC+--+-- Build a tree within a monad - the monad allows anchor references.+--+--------------------------------------------------------------------------------++module Wumpus.Tree.TreeBuildMonad+  (+    NodeId+  , ZNodeId+  , NodeAnno+  , NodeAnnoRefs+  +  , TreeBuild+  , TreeSpec+  , ZTreeSpec++  , TreeNodeAns+  , TreeBuildAns+  , runTreeBuild++  , regularBuild++  , nodeId+  , label+  , annotate++  , branch+  , zbranch+  , leaf+  , zleaf++  ) where++import Wumpus.Tree.Base++import Wumpus.Basic.Kernel                      -- package: wumpus-basic+import Wumpus.Drawing.Dots.AnchorDots++import Wumpus.Core                              -- package: wumpus-core++import Control.Applicative+import qualified Data.IntMap as IntMap+import Data.Monoid+import Data.Tree++++++-- | Nodes can be bound with @(>>=)@ or in the do-notation before +-- they are drawn. This is similar to the concept of /embedded/ +-- nodes in TikZ. Bound nodes can be referenced by their anchors +-- e.g. to give them an extra annotation.+--+-- This opaque type represents bound nodes and regular nodes that +-- are just drawn and cannot be annotated.+-- +data NodeId a = NodeId Int+              | RegularNode a+  deriving (Eq)++-- The default node type. With this type, regular nodes have no+-- payload so can only be drawn as some common graphic e.g. a +-- filled or stroked disk.+--+type ZNodeId u = NodeId (UNil u)++type NodeDrawRefs u = IntMap.IntMap (TreeNode u)++type NodeAnno u     = DotAnchor u -> Graphic u++type NodeAnnoRefs u = IntMap.IntMap (NodeAnno u)++data St u = St+      { uid_counter     :: Int+      , node_refs       :: NodeDrawRefs u+      , anno_refs       :: NodeAnnoRefs u+      }++type instance DUnit (St u) = u++zeroSt :: St u+zeroSt = St { uid_counter = 0, node_refs = mempty, anno_refs = mempty }+++newtype TreeBuild u a = TreeBuild { getTreeBuild :: St u -> (a, St u) }++instance Functor (TreeBuild u) where+  fmap f ma = TreeBuild $ \s -> let (a,s1) = getTreeBuild ma s in (f a, s1)++instance Applicative (TreeBuild u) where+  pure a    = TreeBuild $ \s -> (a,s)+  mf <*> ma = TreeBuild $ \s -> let (f,s1) = getTreeBuild mf s+                                    (a,s2) = getTreeBuild ma s1+                                in (f a,s2)++instance Monad (TreeBuild u) where+  return a  = TreeBuild $ \s -> (a,s)+  ma >>= k  = TreeBuild $ \s -> let (a,s1) = getTreeBuild ma s +                                in getTreeBuild (k a) s1 +++++type instance MonUnit (TreeBuild u) = u+++type TreeSpec a   = Tree (NodeId a)+type ZTreeSpec u  = TreeSpec (UNil u)+++type TreeNodeAns  u = (TreeNode u, Maybe Int)+type TreeBuildAns u = (Tree (TreeNodeAns u), NodeAnnoRefs u)++-- | This is the @run@ function for the TreeBuild monad.+--+-- Note the monadic /command/ is type specialized to +-- @(TreeSpec a)@, this is because evaluation in the TreeBuild+-- monad is only significant for producing a @Tree (TreeNode u)@.+--++runTreeBuild :: (Real u, Floating u, FromPtSize u)+               => (a -> TreeNode u) -> TreeBuild u (TreeSpec a) -> TreeBuildAns u+runTreeBuild regDrawF ma = +    let (a,s) = getTreeBuild ma zeroSt+        t1    = postRun regDrawF (a, node_refs s)+    in (t1, anno_refs s)+++-- As the constructor to build NodeIds is not exposed a +-- TreeBuild should not be able to refer to uninstantiated+-- nodes, however while the failure continuation should be +-- unreachable we still need it in the code to make the +-- IntMap.lookup total.+--+postRun :: (Real u, Floating u, FromPtSize u)+        => (a -> TreeNode u) -> (TreeSpec a,NodeDrawRefs u) +        -> Tree (TreeNode u, Maybe Int)+postRun regDrawF (tree1,table) = fmap changeNode tree1+  where+    changeNode (RegularNode a)  = (regDrawF a, Nothing)+    changeNode (NodeId ix)      = maybe fk (sk ix) $ IntMap.lookup ix table +    +    sk ix                       = \a -> (a, Just ix)+    fk                          = (dotText "Error missing node", Nothing)+ +++-- | Turn an ordinary @Data.Tree@ into a /regular/ 'TreeSpec'.+--+-- All nodes become /regular/ nodes, no nodes are /bound/. Thus+-- nodes cannot be annotated etc.+--  +regularBuild :: Tree a -> TreeBuild u (TreeSpec a)+regularBuild (Node a kids) =  +    Node (RegularNode a) <$> mapM regularBuild kids+++nodeId :: TreeNode u -> TreeBuild u (NodeId a)+nodeId drawF = +    TreeBuild $ \(St ix nodes annos) -> +      let nodes' = IntMap.insert ix drawF nodes+      in (NodeId ix, St (ix+1) nodes' annos)++-- | Note - this is not /in/ the TreeBuild monad.+--+label :: a -> NodeId a +label a = RegularNode a+++-- | Annotate a /node/ with a 'NodeAnno'.+-- +-- Note - /regular/ nodes cannot be annotated, a node must be +-- bound to a variable first with 'nodeId'.+--+annotate :: u ~ DUnit a => NodeId a -> NodeAnno u -> TreeBuild u ()+annotate (RegularNode _) _     = return ()+annotate (NodeId nid)    annoF = +    TreeBuild $ \(St ix nodes annos) -> +      let annos' = IntMap.insert nid annoF annos+      in ((), St ix nodes annos')++++branch :: NodeId a -> [TreeSpec a] -> TreeSpec a+branch uid kids = Node uid kids+++-- | Default /branch/ - has children.+--+zbranch :: [ZTreeSpec u] -> ZTreeSpec u+zbranch kids = Node (RegularNode uNil) kids ++leaf :: NodeId a -> TreeSpec a+leaf uid = Node uid []++-- | Default /leaf/ - tree node with no children.+--+zleaf :: ZTreeSpec u+zleaf = Node (RegularNode uNil) []+++            ++
src/Wumpus/Tree/VersionNumber.hs view
@@ -22,7 +22,7 @@  -- | Version number ----- > (0,12,0)+-- > (0,13,0) -- wumpus_tree_version :: (Int,Int,Int)-wumpus_tree_version = (0,12,0)+wumpus_tree_version = (0,13,0)
wumpus-tree.cabal view
@@ -1,5 +1,5 @@ name:             wumpus-tree-version:          0.12.0+version:          0.13.0 license:          BSD3 license-file:     LICENSE copyright:        Stephen Tetley <stephen.tetley@gmail.com>@@ -28,12 +28,39 @@   <https://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/Core14_AFMs.tar>   .   .-  \*\* WARNING \*\* - the API is unstable and will change. +  \*\* WARNING \*\* - the API is unstable and will change.   .   Changelog:   .-  v0.11.1 to v.0.12.0:+  v0.12.0 to v0.13.0:   .+  * Changed the specification of trees so that they are built in a+    monad. The bind operation of the monad allows /anchors/ to be +    extracted from tree nodes so they can be annotated with +    supplementary graphics. At the moment this is rather limited +    as Wumpus-Basic and Wumpus-Drawing do not offer much support +    for anchors other than the basic type classes.+  .+  * Changed the type of the rendering functions so they produce a +    TreeDrawing. This type is more suitable for building composite+    pictures than the previous type TreePicture. +  .+  * Also the rendering functions now take a start point for the +    root node, again this should be more convenient for drawing +    composite pictures - see the demo which now draws all the +    example trees on one page.+  .+  * Internally the tree design is now more flexible - trees can be +    designed upwards or leftwards rightwards, rather than just +    downwards; and edge drawing style is lifted out of the +    rendering to use a supplied combinator. Currently these +    features are not exposed by the API, the API needs more +    thought (possibly warranting changes to Wumpus-Basic and +    Wumpus-Drawing).+  .+  .+  v0.11.1 to v0.12.0:+  .   * Internal changes to track updates to Wumpus-Basic.   .    .@@ -52,8 +79,9 @@   build-depends:      base              <  5,                        containers        >= 0.3.0     && <= 0.6.0,                       vector-space      >= 0.6       && <  1.0,-                      wumpus-core       == 0.41.0,-                      wumpus-basic      == 0.14.0+                      wumpus-core       >= 0.42.0    && <  0.43.0,+                      wumpus-basic      == 0.15.0,+                      wumpus-drawing    == 0.1.0       exposed-modules:@@ -61,6 +89,7 @@     Wumpus.Tree.Base,     Wumpus.Tree.Design,     Wumpus.Tree.Draw,+    Wumpus.Tree.TreeBuildMonad,     Wumpus.Tree.VersionNumber    other-modules: