Next: Example2, Previous: Interface, Up: Modulos

### 6.2 Exemplo 1: Módulo Externo Simples

Essa seção fornece um módulo externo extremamente simples que mostra uma malha oscilando. Para experimentar esse exemplo, faça uma cópia do arquivo `example1.c` (esse arquivo é distribuído com Geomview no subdiretio `doc`) em seu diretório e compile `example1.c` com o comando

         cc -o example1 example1.c -lm

A seguir coloque a linha

         (emodule-define "Example 1" "./example1")

em um arquivo chamado `.geomview` no seu diretório atual. A seguir chame o Geomview; É importante que você compile o programa exemplo, crie o arquivo `.geomview` e chame o Geomview a partir do mesmo diretório. Você pode ver "Example 1" no navegador de módulos (Modules) do painel principal (Main) do Geomview; clique sobre essa entrada no navegador para iniciar o módulo. Uma superfície deve aparecer na sua janela de câmera e deve estar oscilando. Você pode parar o módulo clicando sobre a linha "[1] Example 1" no navegador de módulos (Modules).

         /*
          * example1.c: oscillating mesh
          *
          * This example module is distributed with the Geomview manual.
          * If you are not reading this in the manual, see the "External
          * Modules" chapter of the manual for more details.
          *
          * This module creates an oscillating mesh.
          */

         #include <math.h>
         #include <stdio.h>

         /* F is the function that we plot
          */
         float F(x,y,t)
              float x,y,t;
         {
           float r = sqrt(x*x+y*y);
           return(sin(r + t)*sqrt(r));
         }

         main(argc, argv)
              char **argv;
         {
           int xdim, ydim;
           float xmin, xmax, ymin, ymax, dx, dy, t, dt;

           xmin = ymin = -5;             /* Set x and y            */
           xmax = ymax = 5;              /*    plot ranges         */
           xdim = ydim = 24;             /* Set x and y resolution */
           dt = 0.1;                     /* Time increment is 0.1  */

           /* Geomview setup.  We begin by sending the command
            *            (geometry example { : foo})
            * to Geomview.  This tells Geomview to create a geom called
            * "example" which is an instance of the handle "foo".
            */
           printf("(geometry example { : foo })\n");
           fflush(stdout);

           /* Loop until killed.
            */
           for (t=0; ; t+=dt) {
             UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
           }
         }

         /* UpdateMesh sends one mesh iteration to Geomview.  This consists of
          * a command of the form
          *    (read geometry { define foo
          *       MESH
          *       ...
          *    })
          * where ... is the actual data of the mesh.  This command tells
          * Geomview to make the value of the handle "foo" be the specified
          * mesh.
          */
         UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
              float xmin, xmax, ymin, ymax, t;
              int xdim, ydim;
         {
           int i,j;
           float x,y, dx,dy;

           dx = (xmax-xmin)/(xdim-1);
           dy = (ymax-ymin)/(ydim-1);

           printf("(read geometry { define foo \n");
           printf("MESH\n");
           printf("%1d %1d\n", xdim, ydim);
           for (j=0, y = ymin; j<ydim; ++j, y += dy) {
             for (i=0, x = xmin; i<xdim; ++i, x += dx) {
               printf("%f %f %f\t", x, y, F(x,y,t));
             }
             printf("\n");
           }
           printf("})\n");
           fflush(stdout);
         }

O módulo inicia-se definindo uma função `F(x,y,t)` que especifica uma superfície va-riando com o tempo. O propósito do módulo é animar essa superfície com o passar do tempo.

O programa principal começa definindo algumas variáveis que especificam os parâmetros com os quais a função é para ser mostrada.

O próximo pedaço de código no programa principal envia a seguinte linha para a saída padrão

         (geometry example { : foo })

Isso diz ao Geomview para criar um geom chamado `example` que é uma instância do manipulador `foo`. Manipuladores são uma parte do formato de arquivo OOGL que permite a você nomear uma peça do objeto geométrico cujo valor pode ser especificado em seu lugar (e nesse caso atualizado muitas vezes); para maiores informações sobre manipuladores, veja Formatos dos Arquivos da OOGL. Nesse caso, `example` é o título através do qual o usuário irá ver o objeto no navegador de objeto do Geomview, e `foo` é o nome interno do manipulador para o qual o objeto aponta.

Nós então fazemos `fflush(stdout)` para garantir que Geomview receba esse comando imediatamente. Em geral, uma vez que pipes podem ser colocados em uma área de memória temporária de armazenamento, um módulo externo deve fazer isso sempre que esse módulo externo tenha que garantir que Geomview tenha atualmente recebido tudo que tenha sido mostrado na saída.

A última coisa no programa principal é um ciclo infinito que circula através de chamadas ao procedimento `UpdateMesh` com incremento dos valores de `t`. `UpdateMesh` envia ao Geomview um comando da forma

         (read geometry { define foo
         MESH
         24 24
         ...
         })

onde `...` é uma longa lista de números. Esse comando diz ao Geomview fazer os valores do manipulador `foo` ser a malha especificada. Tão breve quanto Geomview receba esse comando, o geom sendo mostrado muda para refletir o novo objeto geométrico.

A malha é fornecida no formato de uma OOGL MESH. Esse formato começa com a palavra chave `MESH`. A seguir temos dois números que fornecem as dimensões x e y da malha; nesse caso elas são ambas 24. Essa linha é seguida por 24 linhas, cada linha contendo 24 trios de números. Cada um desses trios representa um ponto sobre superfície. Então finalmente existe uma linha com "`})`" nesse formato que termina o "`{`" que iniciou a declaração `define` e o "`(`" que iniciou o comando. Para mais detalhes sobre o formato de dados MESH, veja MESH.

Esse módulo pode ser escrito sem o uso de manipuladores escrevendo comandos da forma

         (geometry example {
         MESH
         24 24
         ...
         })

Nesse primeiro tempo Geomview recebe um comando e dessa forma pode criar um geom chamado `example` com os dados fornecidos da `MESH`. Subsequentemente comandos `(geometry example ...)` podem fazer com que Geomview substitua a geometria do geom `example` com os novos dados da `MESH`. Se realizado dessa forma pode não ser necessário enviar o comando inicial `(geometry example { : foo })` como dito acima. A técnica do manipulador é útil, todavia, porque essa técnica pode ser usada em situações mais gerais onde um manipulador representa somente parte de um complexo geom, permitindo a um módulo externo substituir somente aquela parte sem ter que retransmitir o geom completo. Para mais informações sobre manipuladores, veja GCL. Veja Referencias. Veja `(hdefine ...)`. Veja `(read ...)`.

O módulo entra em ciclos através de chamadas a `UpdateMesh` que fornece como saída comandos da forma acima um após o outro tão rápido quanto possível. O ciclo continua indefinidamente; o módulo irá terminar quando o usuário fizer isso clicando sobre sua linha de instância no navegador de módulos (Modules), ou em caso contrário quando Geomview for encerrado.

Algumas vezes quando você encerra o módulo clicando sobre sua entrada de instância no navegador de módulos (Modules), Geomview irá encerrá-lo enquanto o módulo está no meio de um comando ao Geomview. Geomview irá então receber somente uma peça de um comando e irá mostrar uma crítica mas inofensiva mensagem de erro sobre isso. uando um módulo tiver um painel de interface com o usuário o usuário pode usar um botão "Quit" para fornecer uma forma mais elegante para o usuário encerrar o módulo. Veja o exemplo seguinte.

Você pode usar esse módulo em uma janela de shell sem o Geomview para ver os comando que o módulo mostra como saída. Você irá ter que encerrá-lo com `ctrl-C` para que ele pare.