Programación de animaciones en Haskell con Gloss

1 Animaciones de dibujos

1.1 Rotando un cuadrado

import Graphics.Gloss

main :: IO ()
main = animate (InWindow "Rotando un cuadrado" (500,500) (20,20)) 
               green animacion

animacion :: Float -> Picture
animacion t = rotate (60 * t) (rectangleSolid 100 100)

1.2 Moviendo un círculo

import Graphics.Gloss

main :: IO ()
main = animate (InWindow "Moviendo un circulo" (500,500) (20,20)) 
               green animacion

animacion :: Float -> Picture
animacion t = translate (50 * t) 0 (color red (circleSolid 25))

1.3 Expandiendo un círculo

import Graphics.Gloss

main :: IO ()
main = animate (InWindow "Expandiendo un circulo" (500,500) (20,20)) 
               green animacion

animacion :: Float -> Picture
animacion t = circle (20 * t)

1.4 Rotación alrededor de un punto

import Graphics.Gloss

main :: IO ()
main = animate (InWindow "Rotacion alrededor de un punto" (500,500) (20,20)) 
               green animacion

animacion :: Float -> Picture
animacion t = rotate (60 * t) (translate 100 0 (circleSolid 25))

1.5 Reloj

import Graphics.Gloss

main :: IO ()
main = animate (InWindow "Reloj" (500,500) (20,20)) green animacion

animacion :: Float -> Picture
animacion t = reloj t

reloj t = pictures [ fondo,
                     minutero t,
                     segundero t ]

fondo = color (dark white) (circleSolid 250)

minutero t = rotate (0.1 * t) (line [(0,0), (0,250)])

2 Animaciones de fractales

2.1 Árbol animado

import Graphics.Gloss

main :: IO ()
main = animate (InWindow "Zen" (800,500) (5,5)) (greyN 0.2) frame

-- Produce one frame of the animation.
frame :: Float -> Picture
frame timeS = Pictures  
          -- the red rectangles
          [ Translate 0 150     backRec
          , Translate 0 0       backRec
          , Translate 0 (-150)  backRec
                          
          -- the tree
          , Translate 0 (-150) $    treeFrac 7 timeS ]

-- One of the red backing rectangles, with a white outline.
backRec :: Picture
backRec     = Pictures
      [ Color red   (rectangleSolid 400 100)
      , Color white     (rectangleWire  400 100) ]

-- The color for the outline of the tree's branches.
treeOutline :: Color
treeOutline = makeColor 0.3 0.3 1.0 1.0

-- The color for the shading of the tree's branches.
-- The Alpha here is set to 0.5 so the branches are partly transparent.
treeColor :: Color
treeColor = makeColor 0.0 1.0 0.0 0.5

-- The tree fractal.
-- The position of the branches changes depending on the animation time
-- as well as the iteration number of the fractal.
treeFrac :: Int -> Float -> Picture
treeFrac 0 timeS = Blank
treeFrac n timeS = 
    Pictures [ Color treeColor    $ rectangleUpperSolid 20 300
             , Color treeOutline  $ rectangleUpperWire  20 300
             , Translate 0 30
             $ Rotate  (200 * sin timeS / (fromIntegral n) )
             $ Scale   0.9 0.9 
             $ treeFrac (n-1) timeS
             , Translate 0 70
             $ Rotate  (-200 * sin timeS / (fromIntegral n))
             $ Scale      0.8 0.8 
             $ treeFrac (n-1) timeS ]

2.2 Fractal con relojes animados

import Graphics.Gloss

main = animate (InWindow "Clock" (500, 500) (20, 20)) black frame

-- Build the fractal, scale it so it fits in the window
-- and rotate the whole thing as time moves on.
frame :: Float -> Picture
frame time = Color white
             $ Scale 110 110
             $ Rotate (time * 2*pi)
             $ clockFractal 5 time

-- The basic fractal consists of three circles offset from the origin
-- as follows.
--
--         1
--         |
--         .
--       /   \
--      2     3
--
-- The direction of rotation switches as n increases.
-- Components at higher iterations also spin faster.
--
clockFractal :: Int -> Float -> Picture
clockFractal 0 s = Blank
clockFractal n s = Pictures [circ1, circ2, circ3, lines]
    where
      -- y offset from origin to center of circle 1.
      a = 1 / sin (2 * pi / 6)

      -- x offset from origin to center of circles 2 and 3.
      b = a * cos (2 * pi / 6)

      nf  = fromIntegral n
      rot = if n `mod` 2 == 0
            then   50 * s * (log (1 + nf))
            else (-50 * s * (log (1 + nf)))

      -- each element contains a copy of the (n-1) iteration contained
      -- within a larger circle, and some text showing the time since 
      -- the animation started.
      --
      circNm1 = Pictures
                [ circle 1
                , Scale (a/2.5) (a/2.5) $ clockFractal (n-1) s
                , if n > 2
                  then Color cyan
                           $ Translate (-0.15) 1
                           $ Scale 0.001 0.001 
                           $ Text (show s) 
                  else Blank
                ]

      circ1 = Translate 0 a       $ Rotate rot    circNm1
      circ2 = Translate 1 (-b)    $ Rotate (-rot) circNm1
      circ3 = Translate (-1) (-b) $ Rotate rot    circNm1

      -- join each iteration to the origin with some lines.
      lines = Pictures
              [ Line [(0, 0), ( 0,  a)]
              , Line [(0, 0), ( 1, -b)]
              , Line [(0, 0), (-1, -b)] ]

3 Bibliografía



Universidad de Sevilla

José A. Alonso Jiménez
Grupo de Lógica Computacional
Dpto. de Ciencias de la Computación e I.A.
Universidad de Sevilla