| Inicial | Temas | Manuales | Ejercicios | Exámenes | Documentación

Tema 25: Programación de dibujos con Gloss

Índice

1. Introducción

  • En este tema se estudia una librería de dibujos en Haskell.
  • La librería es Graphics.Gloss.
  • Nos centraremos en el uso de los tipos de datos algebraicos.
  • Aspectos importantes:
    • ¿Cómo representar los dibujos en Haskell?
    • ¿Cómo mostrar dichos dibujos?
  • Sólo consideraremos el primer aspecto.

2. Instalación de Gloss

  • En una terminal ejecutar

    > cabal update
    > cabal install gloss
    

3. Representación de dibujos

  • Representación de puntos:

    type Point = (Float, Float)
    
  • Elementos de los dibujos:
    • líneas: sucesiones de puntos que representan los extremos,
    • polígonos: sucesiones de puntos que representan los vértices.
    • textos: cadenas (escritas en el origen (centro de la ventana)).
  • Representación de caminos:

    type Path = [Point]
    

4. El TDA de los dibujos

4.1. Elementos básicos del TDA de los dibujos

data Picture = Line    Path
             | Polygon Path
             | Text    String

4.2. Ejemplo de líneas

  • Fichero lineas.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (300,300) (20,20)) white cuadrado
    
    cuadrado :: Picture
    cuadrado = Line [(72,72),(144,72),(144,144),(72,144),(72,72)]
    
  • Ejecución

    > stack runhaskell lineas.hs
    
  • Resultado:
    lineas.png
  • Comentarios:
    • (InWindow t (b,a) (x,y)) es una ventana de título t, base b y altura a con el vértice superior izquierdo en el punto (x,y).
    • (display v c d) dibuja en la ventana v, con color de fondo c, el dibujo d.
    • El dibujo puede desplazarse con el ratón.

4.3. Ejemplo de polígono

  • Fichero poligono.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (300,300) (20,20)) white cuadrado
    
    cuadrado :: Picture
    cuadrado = Polygon [(72,72),(144,72),(144,144),(72,144),(72,72)]
    
  • Ejecución

    > stack runhaskell poligono.hs
    
  • Resultado
    poligono.png

4.4. Ejemplo de texto

  • Fichero texto.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (800,300) (20,20)) white texto
    
    texto :: Picture
    texto = Text "Figura"
    
  • Ejecución

    > stack runhaskell texto.hs
    
  • Resultado
    texto.png

5. Ampliaciones del TDA de dibujos

5.1. Ampliación del TDA para incluir listas de dibujos

  • Ampliación

    data Picture = ...
                 | Pictures [Picture]
    
  • Ejemplo dosCuadrados.hs

    dibujo :: Picture
    dibujo = Pictures [cuadrado1, cuadrado2]
    
    cuadrado1 :: Picture
    cuadrado1 = Line [(72,72),(144,72),(144,144),(72,144),(72,72)]
    
    cuadrado2 :: Picture
    cuadrado2 = Line [(0,0),(100,0),(100,100),(0,100),(0,0)]
    
  • Ejecución

    > stack runhaskell dosCuadrados.hs
    
  • Resultado
    dosCuadrados.png

5.2. Ampliación del TDA para incluir transformaciones

  • Ampliación

    data Picture = ...
                 | Translate Float Float   Picture
                 | Rotate    Float Picture
                 | Scale     Float Float   Picture
    
    • Translate distancia-x distancia-y
    • Rotate grados en sentido horario alrededor del origen
    • Scale factor-x factor-y
  • Se pueden componer transformaciones. Por ejemplo,

    Translate 0 200 (Rotate 20 (Scale 0.5 0.3 algo))
    
  • Se pueden eliminar paréntesis usando el operador $. Por ejemplo,

    Translate 0 200 $ Rotate 20 $ Scale 0.5 0.3 algo
    
  • Ejemplo de transformaciones: transformaciones.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (300,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = Pictures [cuadrado, titulo]
    
    cuadrado :: Picture
    cuadrado = Line [(72,72),(144,72),(144,144),(72,144),(72,72)]
    
    titulo :: Picture
    titulo = Rotate (-10)
           $ Translate (-70) 0
           $ Scale 0.2 0.2
           $ Text "Un cuadrado"
    

    genera
    transformaciones.png

5.3. Ampliación del TDA para incluir colores

  • Ampliación

    data Picture = ...
                 | Color Color Picture
    
  • Color es otro tipo de dato algebraico

    data Color = RGBA Float Float Float Float
    
  • Los cuatros parámetros son valores entre 0 y 1, para los canales rojo, verde, azul y alfa, respectivamente.
  • Algunos colores están predefinidos en Graphics.Gloss.Data.Color: red, green, blue, yellow, cyan, magenta, rose, violet, azure, aquamarine, chartreuse, orange, greyN, black, white.
  • Ejemplo dosCuadradosColoreados.hs:

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (300,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = Pictures [cuadrado2, cuadrado1]
    
    cuadrado1 :: Picture
    cuadrado1 = Color red $ Polygon [(72,72),(144,72),(144,144),(72,144),(72,72)]
    

    genera
    dosCuadradosColoreados.png

6. Capas de dibujos

  • El orden en una lista de dibujos es importante.
  • El primer elemento de la lista es el primero que se dibuja, a continuación el segundo y así sucesivamente.
  • La lista de los dibujos forman las capas del dibujo combinado:

    Pictures [capa1, capa2, capa3, ...]
    
  • Ejemplo: En dosCuadradosColoreados.hs, las capas eran

    Pictures [cuadrado2, cuadrado1]
    

    por eso se pintaba primero el verde y encima el rojo. Si se cambia el orden de las capas por

    Pictures [cuadrado1, cuadrado2]
    

    el dibujo que se obtiene es
    dosCuadradosColoreados2.png

7. Dibujos predefinidos en Graphics.Gloss.Data.Picture

7.1. Círculos

  • (circle r) es un círculo de radio r. Por ejemplo

    circle 100
    

    genera
    circulo.png

  • (circleSolid r) es un círculo sólido de radio r. Por ejemplo

    circleSolid 100
    

    genera
    circulo_solido.png

  • (thickCircle r g) es la corona circular de radio r y grosor g. Por ejemplo

    thickCircle 100 30
    

    genera
    circuloGrueso1.png

7.2. Arcos circulares

  • (arc x y r) es el arco de radio r entre los ángulos (en grados) x e y. Por ejemplo

    arc 0 90 100
    

    genera
    arco.png

  • (arcSolid x y r) es el arco sólido de radio r entre los ángulos (en grados) x e y. Por ejemplo,

    arcSolid 0 90 100
    

    genera
    arco_solido.png

  • (thickArc x y r g) es el arco de radio r entre los ángulos (en grados) x e y, de grosor g. Por ejemplo,

    thickArc 0 90 100 50
    

    genera
    arco_grueso.png

  • (sectorWire x y r) es el sector circular de radio r entre los ángulos (en grados) x e y; las líneas van del origen a los extremos del arco. Por ejemplo

    sectorWire 0 90 100
    

    genera
    sector_circular.png

7.3. Bucles

  • (lineLoop ps) es la línea que une los puntos de ps, cada uno con el siguiente y el último con el primero. Por ejemplo,

    lineLoop [(-123,-99),(15,17),(107,-73)]
    

    genera
    bucle.png

7.4. Rectángulos

  • (rectanglePath x y) es la lista de los vértices del rectángulo de base x y altura y con centro en el origen. Por ejemplo,

    λ> rectanglePath 200 100
    [(-100.0,-50.0),(-100.0,50.0),(100.0,50.0),(100.0,-50.0)]
    
  • (rectangleWire x y) es el rectángulo de base x y altura y con centro en el origen. Por ejemplo,

    rectangleWire 200 100
    

    genera
    rectangulo2.png

  • (rectangleSolid x y) es el rectángulo sólido de base x y altura y con centro en el origen. Por ejemplo,

    rectangleSolid 200 100
    

    genera
    rectangulo_solido.png

  • (rectangleUpperPath x y) es la lista de los vértices del rectángulo de base x y altura y con centro en el origen, en el semiplano y > 0. Por ejemplo,

    λ> rectangleUpperPath 200 100
    [(-100.0,0.0),(-100.0,100.0),(100.0,100.0),(100.0,0.0)]
    
  • (rectangleUpperWire x y) es el rectángulo de base x y altura y con centro en el origen en el semiplano y > 0. Por ejemplo,

    rectangleUpperWire 200 100
    

    genera
    rectangulo_positivo.png

  • (rectangleUpperSolid x y) es el rectángulo sólido de base x y altura y con centro en el origen en el semiplano y > 0. Por ejemplo,

    rectangleUpperSolid 200 100
    

    genera
    rectangulo_positivo_solido.png

8. Dibujos con listas de comprensión

8.1. Círculos concéntricos

  • Dibujo:
    circulos_concentricos.png
  • Programa circulos_concentricos.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (300,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [ circle x | x <- [10,20..100] ]
    

8.2. Círculos trasladados

  • Dibujo
    circulos_trasladados.png
  • Programa circulos_trasladados.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [translate x 0 (circle 80) | x <- [-100,-60..100]]
    

8.3. Circulos trasladados y ampliados

  • Dibujo
    circulos_trasladados_ampliados.png
  • Programa circulos_trasladados_ampliados.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [translate x 0 (circle x) | x <- [10,20..100]]
    

8.4. Rectángulos girados

  • Dibujo
    rectangulos_girados.png
  • Programa rectangulos_girados.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [rotate x (rectangleWire 200 200) | x <- [0,10..90]]
    

8.5. Rectángulos girados y trasladados

  • Dibujo
    rectangulos_girados_y_trasladados.png
  • Programa rectangulos_girados_y_trasladados.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [translate x 0 (rotate x (rectangleWire 200 200)) |
                       x <- [-45,-35..45]]
    

8.6. Círculos en cuadrado

  • Dibujo
    circulos_en_cuadrado.png
  • Programa circulos_en_cuadrado.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [translate x y (circle 10) |
                       x <- [-200,-100..200],
                       y <- [-200,-100..200]]
    

8.7. Círculos en estrella

  • Dibujo
    circulos_en_estrella.png
  • Programa circulos_en_estrella.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [rotate angulo (translate x 0 (circle 10))
                      | x      <- [50,100..200],
                        angulo <- [ 0, 45..360]]
    

8.8. Círculos expandiéndose

  • Dibujo
    circulos_expandiendose.png
  • Programa circulos_expandiendose.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = pictures [rotate angulo (translate (5*x) 0 (circle x))
                      | x      <- [10,20.. 40],
                        angulo <- [ 0,45..360]]
    

9. Gráficas de funciones

  • El programa para dibujar la siguiente parábola (y = x²)
    parabola.png
    es parabola.hs

    import Graphics.Gloss
    
    main  :: IO ()
    main  =  display (InWindow "y = x^2" (500,500) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = Color red (Translate 0 (-200) parabola)
    
    parabola :: Picture
    parabola = Line (map puntosParabola [-200, -190 .. 200])
      where puntosParabola x = (x, x^2/100)
    

10. Dibujos programados (diseño descendente)

  • Los siguiente dibujos se diseñan de manera descendente: se inicia con el marco y se le va añadiendo elementos.

10.1. Elefante

  • Dibujo
    elefante.png
  • Programa elefante.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,300) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = elefante
    
    elefante =
      pictures
       [rotate 20 (scale 3 2 (translate 30 40 (circleSolid 25))),  -- cabeza
        translate 150 (-20) (rectangleSolid 40 80),                -- trompa
        translate (-10) 40 (scale 1.5 1 (circleSolid 80)),         -- cuerpo
        translate 50 (-50)(rectangleSolid 40 70),                  -- pata delantera
        translate (-60) (-50) (rectangleSolid 40 70),              -- pata trasera
        translate (-140) 50 (rotate (-100) (rectangleSolid 10 40)) -- cola
       ]
    

10.2. Plato de comida

  • Dibujo
    plato.png
  • Programa plato.hs

    import Graphics.Gloss
    
    main :: IO ()
    main = display (InWindow "Dibujo" (500,500) (20,20)) white dibujo
    
    dibujo :: Picture
    dibujo = platoConComida
    
    platoConComida :: Picture
    platoConComida =
      pictures [ mesa,
                 plato,
                 comida,
                 translate ( 200) 0 tenedor,
                 translate (-200) 0 cuchillo ]
    
    mesa :: Picture
    mesa = color marron (rectangleSolid 500 500)
    
    plato :: Picture
    plato =
      pictures [ color gris      (circleSolid 175),
                 color grisClaro (circleSolid 150) ]
    
    comida :: Picture
    comida =
      pictures [ translate (-50) ( 50) (rotate   45  zanahoria),
                 translate (-20) (-40) (rotate   20  brocoli),
                 translate ( 60) (-30) (rotate (-10) brocoli) ]
    
    zanahoria :: Picture
    zanahoria =
      color orange
            (polygon [(-5,-40),(-20,40),(20,40),(5,-40) ])
    
    brocoli :: Picture
    brocoli =
      color (dark green)
            (pictures [ translate (  0) (-15) (rectangleSolid 30 50), -- base
                        translate (-15) (  0) (circleSolid 25),       -- flor
                        translate ( 15) (  0) (circleSolid 25),       -- flor
                        translate (  0) ( 15) (circleSolid 25)        -- flor
                      ])
    
    tenedor :: Picture
    tenedor =
      color grisClaro
            (pictures [rectangleSolid 10 250,                        -- mango
                       translate (  0) ( 80) (rectangleSolid 40 10), -- base
                       translate (-15) (100) (rectangleSolid 10 45), -- diente izquierdo
                       translate ( 15) (100) (rectangleSolid 10 45)  -- diente derecho
                      ])
    
    cuchillo :: Picture
    cuchillo =
      color grisClaro
            (pictures [translate 0 (-25) (rectangleSolid 30 200),    -- mango
                       polygon [ (-15,  75),
                                 ( -5, 105),
                                 ( 15, 125),
                                 ( 15,  75) ]                        -- hoja
                      ])
    
    marron, grisClaro, gris :: Color
    marron    = dark orange
    grisClaro = dark white
    gris      = dark grisClaro
    

| Inicial | Temas | Manuales | Ejercicios | Exámenes | Documentación

José A. Alonso Jiménez

Sevilla, 07 de abril del 2024

Licencia: Creative Commons.