lsystem-1.2: src/Main.hs
{-|
User Interface and Compilation process for L-System and Turtle movement
student: Carlos Gomez
date: Sat May 15 22:51:57 BOT 2010
-}
module Main where
import Graphics.UI.WXCore
import Graphics.UI.WX
import GenSequences
import Process
import ParserLS
import SistemaL
main :: IO()
main = start gui
-- | GUI for L-system
gui :: IO()
gui = do -- read the data base file of l-system
db <- readDataBase
-- variables
dbls <- variable [value := db] -- lista of l-systems
points <- variable [value := []] -- list of point draw lines
lsystem <- variable [value := head db] -- actual l-system to use
f <- frame [text := "L-System And Turtle Movement"]
screen <- panel f [on paint := onScreenPaint points] -- screen is the place where to draw the lines
-- state turtle
spanel <- panel f []
xs <- entry spanel [text := "200"]
ys <- entry spanel [text := "200"]
as <- entry spanel [text := "0"]
ds <- entry spanel [text := "10"]
bs <- entry spanel [text := "90"]
nl <- entry spanel [text := "1"]
brender <- button f [text := "Render", on command := render lsystem points xs ys as ds bs nl screen]
bclear <- button f [text := "Clear" , on command := set points [value := []] >> repaint screen]
let opts = map getNombre db
lstB <- choice spanel [items := opts, selection := 0]
set lstB [on select := chgSystem lsystem lstB dbls]
updateDB <- button spanel [text := "Update DB", on command := updateDataBase lstB dbls lsystem]
set spanel [layout := row 5 $
[ boxed "state turtle" (column 5 [ row 5 [label "x:", widget xs, label "y:", widget ys, label "angle a:", widget as]
, row 5 [label "distance:", widget ds, label "angle b:", widget bs]])
, hfill $ boxed "L-System" (row 5 [label "L-System", widget lstB, label "Nro-Iterations", widget nl, widget updateDB])
]]
set f [layout := column 5 [ hfill $ widget spanel
, fill $ widget screen
, row 5 [hfill $ widget brender, hfill $ widget bclear]]]
return ()
updateDataBase lstB dbls lsystem
= do db <- readDataBase
set dbls [value := db]
let opts = map getNombre db
set lstB [items := opts]
set lsystem [value := head db]
return ()
readDataBase
= do lss <- catch (parseFileSistemasL "./db/db.sl") (\err -> putStrLn (show err) >> return [])
let defaultLS = SistemaL "Single Line" [Simbolo "F"] [Simbolo "F"] [(Simbolo "F",[Simbolo "F"])]
return $ defaultLS : lss
-- | change the actual L-System to another
chgSystem lsystem chc dbls
= do n <- get chc selection
db <- get dbls value
let ls = db !! n
set lsystem [value := ls]
-- | generate a sequence and then render the sequence on screen
render lsystem points xs ys an ds bn nl screen
= do x <- get xs text
y <- get ys text
a <- get an text
d <- get ds text
b <- get bn text
ns <- get nl text
ls <- get lsystem value
let c = black -- default init color
-- we generate the sequense
let sequence = generate ls (toInt ns)
let tortuga = ((toDouble x, toDouble y, toRad (toDouble a)), toDouble d, toRad (toDouble b), c)
listPoints <- get points value
let newPoints = processSequence sequence tortuga listPoints
set points [value := newPoints]
repaint screen
-- | draw lines on screen according to the list of points
onScreenPaint points dc (Rect rx ry dx dy)
= do lst <- get points value
mapM_ drawP lst
where drawP ((x,y), (x',y'), c) = line dc (pt x (dy-y)) (pt x' (dy-y')) [color := c]
-- | Converts to Radians
toRad :: Double -> Double
toRad n = n / 360 * 2 * pi
-- | Converts to Int
toInt :: String -> Int
toInt = read
-- | Converts to Double
toDouble :: String -> Double
toDouble = read . fix
where fix xss@(x:xs) = if x == '.' then '0':xss
else let (tr, sr) = splitAt 2 xss
in if tr == "-." then "-0."++sr
else xss