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.
Sólo consideraremos el primer aspecto.
> cabal update
> cabal install gloss
type Point = (Float, Float)
type Path = [Point]
data Picture = Line Path
| Polygon Path
| Text String
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)]
> runhaskell lineas.hs
(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.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)]
> runhaskell poligono.hs
import Graphics.Gloss
main :: IO ()
main = display (InWindow "Dibujo" (800,300) (20,20)) white texto
texto :: Picture
texto = Text "Figura"
> runhaskell texto.hs
data Picture = ...
| Pictures [Picture]
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)]
> runhaskell dosCuadrados.hs
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
Translate 0 200 (Rotate 20 (Scale 0.5 0.3 algo))
$
. Por ejemplo,Translate 0 200 $ Rotate 20 $ Scale 0.5 0.3 algo
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
data Picture = ...
| Color Color Picture
Color
es otro tipo de dato algebraicodata 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
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, ...]
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
(circle r)
es un círculo de radio r. Por ejemplocircle 100
genera
(circleSolid r)
es un círculo sólido de radio r. Por ejemplocircleSolid 100
genera
(thickCircle r g)
es la corona circular de radio r y grosor r. Por ejemplothickCircle 100 30
genera
(arc x y r)
es el arco de radio r entre los ángulos (en grados) x e y. Por ejemploarc 0 90 100
genera
(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
(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
(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 ejemplosectorWire 0 90 100
genera
(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
(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,ghci> 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
(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
(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,ghci> 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
(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
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] ]
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]]
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]]
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]]
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]]
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]]
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]]
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]]
El programa para dibujar la siguiente parábola ():
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)
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
]
import Graphics.Gloss
main :: IO ()
main = display (InWindow "Dibujo" (500,500) (20,20)) white dibujo
dibujo :: Picture
dibujo = plato_con_comida
plato_con_comida =
pictures [ mesa,
plato,
comida,
translate ( 200) 0 tenedor,
translate (-200) 0 cuchillo ]
mesa = color marron (rectangleSolid 500 500)
plato =
pictures [ color gris (circleSolid 175),
color grisClaro (circleSolid 150) ]
comida =
pictures [ translate (-50) ( 50) (rotate 45 zanahoria),
translate (-20) (-40) (rotate 20 brocoli),
translate ( 60) (-30) (rotate (-10) brocoli) ]
zanahoria =
color orange
(polygon [(-5,-40),(-20,40),(20,40),(5,-40) ])
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 =
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 =
color grisClaro
(pictures [translate 0 (-25) (rectangleSolid 30 200), -- mango
polygon [ (-15, 75),
( -5, 105),
( 15, 125),
( 15, 75) ] -- hoja
])
-- Algunos colores usados en el dibujo:
marron = dark orange
grisClaro = dark white
gris = dark grisClaro