packages feed

twentefp-0.4: examples/RoseTree.hs

module RoseTree where
-- Grafische weergave van tamelijk algemene bomen (zie typedef).
-- Aanroepen:
--     voor enkele boom t:  showTree t
--     voor lijst bomen ts: showTreeList ts
--
-- Jan Kuper, 10 januari 2003

import Prelude
import FPPrac.Graphics

---------------boomtype-----------------------------------------
data RoseTree = RoseNode String [RoseTree]
  deriving (Show, Eq)

---------------schalingsfactoren--------------------------------

verticaleftshift = 50.0
leftshift        = 5.0
horizontalfactor = 19.0
letterheight     = 16.0

---------------breedte ve boom berekenen------------------------
-- in principe: breedte = het aantal characters (fixed font)
-- opletten: string aan interne knoop kan meer ruimte nodig hebben
--    dan alle subbomen op dat punt samen.
-- opletten: ook bij de lege string een positieve treewidth (1) opleveren

treewidth :: RoseTree -> Float
treewidth (RoseNode a ts) = maximum [1.0, fromIntegral $ length a, sum (map treewidth ts)]

---------------coordinaten van de wortels ve (sub)boom----------
-- hor_pos berekent de horizontale positie van de wortel van de
--    i-de boom uit een lijst ts van bomen - BINNEN die lijst van bomen.
--    Die positie is de totale breedte van alle bomen links van
--    boom i, plus de halve breedte van boom i zelf (in gehele getallen).
-- hor_poss berekent de horizontale posities van alle bomen in een
--    lijst ts - uitgaande van het midden van de lijst ts.

hor_pos :: [RoseTree] -> Int -> Float
hor_pos ts i = (sum . map treewidth . take i) ts + treewidth (ts!!i) / 2.0

hor_poss :: Float -> [RoseTree] -> [Float]
hor_poss midden ts                                      -- (x,y): midden
     = ( map (+links) . map (hor_pos ts) ) [0..(length ts)-1]
     where
       links = midden - sum (map treewidth ts) / 2.0

---------------deelgraphics-------------------------------------
-- textgraphical, linegraphical produceren graphics-waarden voor
--    een string, resp edge ve boom.
--    Zetten bovendien de horizontale positie om in een
--    x-coordinaat in het grafische vlak (bij Amanda 1.29
--    loopt dat vlak van x=-1 tot x=+1, en van y=-1 tot y=+1).

textgraphical :: (Float,Float) -> String -> Picture
textgraphical (x,y) a = Translate xlabel (y - 12.0) $ Scale 0.1 0.1 $ Color black $ Text a
                      where
                        xlabel = horizontalfactor * (x - (fromIntegral $ length a) / leftshift)

linegraphical :: (Float,Float) -> (Float,Float) -> Picture
linegraphical (x,y) (x1,y1) = Color red $ Line [(horizontalfactor*x,y), (horizontalfactor*x1,y1)]

---------------graphics ve boom, resp lijst v bomen-------------
-- drawTree, drawTreeList zetten een boom (bomen) om in grafische waarden,
--    uitgaande van de coordinaten (x,y) van de wortel van de boom.
--    Daarbij maakt drawTree recursief gebruik van drawTreeList, met een
--    kleinere y-coordinaat (rekening houdend met een eventuele
--    lege string aan een knoop).
--    Op zijn beurt maakt drawTreeList gebruik van drawTree voor elke boom
--    uit een lijst van bomen apart.

drawTree :: ((Float,Float) , RoseTree) -> Picture
drawTree ((x,y), (RoseNode a ts))
     = Pictures ((textgraphical (x,y) a
                 :  map (linegraphical (x,yc)) (zip (hor_poss x ts) [y-verticaleftshift|i<-[1..]]))
            ++ [drawTreeList ((x,y-verticaleftshift), ts)])
     where
       yc | a == ""   = y
          | otherwise = y-letterheight

drawTreeList :: ((Float,Float) , [RoseTree]) -> Picture
drawTreeList ((x,y), ts)
     = (Pictures . map drawTree) (zip xy_coords ts)
     where
       xy_coords = zip (hor_poss x ts) [y|i<-[1.0 ..]]

-- =============output===========================================
-- Let op: keuzes voor GraphResize, GraphFont, en bovenstaande
-- schalingsfactoren zijn op elkaar afgestemd. Verandering daarvan
-- kan de netheid van de output beinvloeden.

startpuntMainRoot = (0, 200)         -- midden bovenaan het scherm

showTreeList :: [RoseTree] -> IO ()
showTreeList ts = graphicsout $ drawTreeList (startpuntMainRoot, ts)

showTree :: RoseTree -> IO ()
showTree t = showTreeList [t]


-- ======voorbeeldboom===========================================

exampleTree = RoseNode "z"
                        [ RoseNode "aaa"
                                    [ RoseNode "bbb"
                                                [ RoseNode "ccc" [],
                                                  RoseNode "ddd" []
                                                ],
                                      RoseNode ""
                                                [RoseNode "fff" [],
                                                 RoseNode "ggg" [],
                                                 RoseNode "hhh" []
                                                ],
                                      RoseNode "iii"
                                                [RoseNode "" []
                                                ]
                                    ],
                          RoseNode "kkk"
                                    [RoseNode "lll" [],
                                     RoseNode "mmm"
                                               [RoseNode "nnn"
                                                          [RoseNode "q" [],
                                                           RoseNode "r" []
                                                          ],
                                                RoseNode "ooo" [],
                                                RoseNode "ppp" []
                                               ]
                                    ]
                        ]