M.P.I - 1998/99 - Trabalho Prático Nr. 2
[ DI/UM ]

Introdução

Este trabalho deve ser realizado por grupos com um máximo de três alunos. O trabalho deve ser entregue até ao dia 27 de Novembro na recepção do Departamento de Informática e nele deve constar a listagem do código escrito assim como um pequeno relatório.

Objectivos

Neste trabalho prático pretende-se que os alunos não só continuem a sua aprendizagem da linguagem HASKELL , mas também se habituem a integrar módulos descritos nessa linguagem com outros módulos e/ou aplicações externas.

No presente caso vai ser realizada a interligação HASKELL -XFIG. O XFIG é uma aplicação gráfica popular entre os utilizadores de sistemas UNIX e que vamos utilizar como visualizador de uma linguagem simples, a 2 dimensões, que definiremos em HASKELL .

Pressione aqui para obter um pacote de programas desenvolvido pela equipa docente para facilitar a realização do trabalho. Recomenda-se a leitura daqueles que vão escritos em HASKELL .

Enunciado

Pretende-se neste trabalho definir uma linguagem gráfica ``brinquedo'' a duas dimensões (2D) capaz de especificar e desenhar agregações de caixas que contêm informação textual. Vamos designar essa linguagem por L2D e vamos defini-la como um tipo em HASKELL :

type L2D = X Caixa Tipo
onde X é a estrutura de dados
data X a b = Unid a | Comp b (X a b) (X a b)
Repare-se que esta estrutura de dados generaliza a que foi assunto do trabalho prático Nr.1 . Em ambos os casos temos árvores binárias. Mas neste caso as folhas deixam de ser vazias e passam a conter informação do tipo a. Em LD2 este parâmetro é instanciado com o tipo Caixa:
type Caixa = ((Int,Int),(Texto,Cor))
onde
type Texto = String
data Cor = Vermelha | Azul | Verde | Amarela
Assim, cada caixa de texto é especificada pela sua largura, altura, o seu texto e a sua côr. (Pode relacionar Caixa com as caixas de texto usadas nos jornais ou com 'frames' da linguagem HTML usada na Internet.) Por exemplo,
((1200,2000),("Caixa azul",Azul))
designa a caixa
(1200,2000)
(0,0)  
O que a linguagem LD2 faz é agregar tais caixas tipográficas umas com as outras segundo padrões especificados por vários ``tipos'', a saber,
data Tipo = V | Vd | Ve | H | Ht | Hb
com o seguinte significado:
V
- agregação vertical alinhada ao centro
Vd
- agregação vertical justificada à direita
Ve
- agregação vertical justificada à esquerda
H
- agregação horizontal alinhada ao centro
Hb
- agregação horizontal alinhada pela base
Ht
- agregação horizontal alinhada pelo topo

Como LD2 instancia o parâmetro b de X com Tipo, é fácil de ver que cada ``frase'' da linguagem LD2 é representada por uma árvore binária em que cada nó indica qual o tipo de agregação a aplicar às suas duas sub-árvores.

Vamos dar um exemplo: a frase

ex2=(Comp Ht  (Unid ((1000,2000),("A",Azul)))
              (Unid ((300,600),("B",Verde))))
deverá corresponder à imagem

E poderá ir tão longe quando a linguagem o permite... Por exemplo, pense na estrutura da frase que representa o 'layout' seguinte:

Ponto 1

É importante notar que cada ``caixa'' não dispõe informação relativa ao seu posicionamento final na figura. De facto, é a posição relativa que deve ocupar face às restantes caixas que irá determinar a sua posição final. Este é um dos objectivos deste trabalho: calcular o posicionamento absoluto de cada uma das caixas por forma a respeitar as restrições impostas pelas diversas agregações . Para isso vamos considerar um novo tipo de dados que comporta a informação de todas as caixas devidamente posicionadas (i.e. com a informação adicional da origem onde a caixa deve ser colocada).

data Fig = Fig Ponto [Obj]

type Obj = (Ponto,Caixa)

A informação mais relevante deste tipo é a referente à lista de ``caixas posicinadas'' (tipo [Obj]). Regista-se aí a origem da caixa que, com a informação da sua altura e comprimento, permite definir todos os seus pontos (consideramos as caixas sempre paralelas aos eixos). O primeiro argumento do constructor (com tipo Ponto) regista a ``bounding box'' de todas as caixas contidas na lista (quando realizar as funções pretendidas reconhecerá o interesse desse argumento).

Ponto 2

Um segundo problema neste projecto é descobrir como visualizar a informação gráfica calculada por desenho . Duas alternativas parecem legítimas nesta fase:

1.
utilizar uma biblioteca gráfica que permita definir as funções de visualização necessárias;
2.
utilizar uma ferramenta disponível que esteja preparada para efectuar a representação pretendida.

Neste trabalho será adoptada a segunda solução (deixa-se a primeira como sugestão para valorização). Propomo-nos então a usar o XFIG , uma ferramenta de edição gráfica 2D popular entre os sistemas UNIX .

A utilização de uma ferramenta externa pressupõe algum trabalho de ``interligação'': o XFIG opera sobre formatos próprios e devemos adaptar a nossa informação para se enquadrar nesse formato. É fornecido um módulo em HASKELL que realiza grande parte dessa tarefa. Nesse módulo são definidos tipos que suportam a informação contida num documento XFIG e definem-se estes como instâncias das classes Show e Read, de tal forma que a representação textual desses tipos coincide com o formato dos ficheiros utilizados por essa ferramenta.

Deve, então, utilizar as funções:

defaultXFigDoc :: [Object] -> XFigDoc

geraXFcaixa :: Ponto -> Ponto -> Cor -> Object

geraXFtexto :: Ponto -> String -> Object

onde XFigDoc é o tipo de dados para interligação com o XFIG e Object é o tipo de dados dos objectos do XFIG . A função de geração do texto centra-o no ponto dado.

Comentário: o XFIG utiliza um sistema de coordenadas com a origem no canto superior direito. Para utilizarmos nas nossas estruturas de dados as coordenadas mais usuais (origem no canto inferior esquerdo) devemos fazer o ajuste na invocação dessas funções. Sugere-se que numa primeira fase se adoptem as coordenadas ``à la XFIG '' e, como valorização, se considere a adaptação para coordenadas standard.

Ponto 3

Este trabalho irá utilizar intensivamente funções de Entrada/Saída dado que deverá produzir ficheiros que possam ser interpretados por programas externos. Vamos por isso utilizar os mecanismos próprios do HASKELL para 'I/O', i.e. a mónada IO . Já referimos que a geração dos ficheiros no formato XFIG se reduz à escrita da representação textual da estrutura de dados apropriada. De facto, no módulo fornecido encontra-se a definição

writeXFigFile :: XFigDoc -> String -> IO ()
writeXFigFile fig f = writeFile f (show fig)

No programa final constará por certo uma invocação a esta função, e.g. deveremos ter alguma coisa que se assemelhe a:

main :: IO ()
main = do
         -- tudo que o programa deve fazer
         -- ...
         writeXFigFile (--*XFigDoc*--) (--*Nome ficheiro*--)
         -- etc.

Dá-se total liberdade no que se refere à restante operacionalidade do trabalho, por exemplo quanto à interacção com o utilizador; se o programa opera sempre sobre determinados dados de exemplo ou se se permite ao utilizador interferir nesse processo; etc. Evidentemente que a valorização do trabalho considerará esses pontos.

Ponto 4

Os utilizadores do sistema operativo MS-WINDOWS dispoem de um problema adicional: o XFIG é popular no ``mundo UNIX '' mas não se encontra normalmente disponível nos sistemas WINDOWS. Para tornear essa dificuldade fornece-se um applet que permite visualizar o desenho num cliente WWW (e.g. MS-EXPLORER ou NETSCAPE). Para isso deve-se utilizar a função de 'I/O' que cria um ficheiro com formato adequado:

writeXFigHtmlFile :: XFigDoc -> String -> IO()


Voltar à página principal de MP-I .
Outras disciplinas leccionadas pelo DIUM

Jose Nuno Oliveira
11/12/1998