




                               CAPTULO 12       
            
                                 GRFICOS    
            
            
            
            12.1. INICIANDO O MODO GRFICO DO VDEO 
            
                 Todos os  programas-exemplo anteriores  usavam o  vdeo
            apenas para  escrever  textos  ou  alguns  caracteres  ASCII
            especiais. Dizemos  que o  vdeo estava  no modo texto de 25
            linhas e  80 colunas.  Para se  construir grficos,  o vdeo
            precisa estar  no modo  grfico, que  consiste em um aumento
            considervel do  nmero de  linhas e  colunas.  Esse  nmero
            varia de  acordo com o tipo de vdeo. Para o tipo CGA, temos
            no modo  grfico 640  colunas,  numeradas  de  0  a  639  da
            esquerda para  a direita, e 200 linhas, numeradas de 0 a 199
            de cima  para baixo.  Dizemos que  (coluna,  linha)  so  as
            coordenadas de um ponto na tela em modo grfico.
            
            Exemplo: No  modo grfico  do vdeo  CGA, temos as seguintes
            coordenadas para  os pontos  indicados com  um sinal  de "+"
            abaixo:
            
                  (0, 0)             (320, 0)             (639, 0)
                    +--------------------+--------------------+
                    |                    |                    |
                    |                    |                    |
                    |                    |                    |
                    |                    |                    |
                    | (0, 100)           |                    |
                    +--------------------+ (320, 100)         |
                    |                                         |
                    |                                         |
                    |                                         |
                    |                                         |
                    |                                         |
                    +-----------------------------------------+
                  (0, 199)                                (639, 199)
            
                 Todos os comandos e constantes grficas do Pascal esto
            na unidade  padro GRAPH.  Os nmeros  639 e 199 mencionados
            acima so  os valores  de duas  funes  dessa  unidade,  as
            funes  GetMaxX  e  GetMaxY,  respectivamente.  Os  valores
            dessas funes  dependem do tipo de vdeo. Com isso, podemos
            elaborar programas  que so  bem executados em qualquer tipo
            de vdeo.  Se usssemos  639 e  199, o programa s seria bem
            executado em vdeos CGA ou assemelhados.
                 Para mudar  do  modo  texto  para  o  modo  grfico,  
            necessrio que  seja executado  um comando  INITGRAPH,  cuja
            sintaxe :
            
                 InitGraph(dg, mg, path) ---> DG  e MG so variveis  do
                             tipo  integer que  correspondem ao  tipo de

                                       - 178 -





                             vdeo ("driver" grfico) e ao modo grfico.
                             PATH   uma  varivel  ou constante do tipo
                             string que indica o diretrio onde esto os
                             arquivos .BGI (CGA.BGI, EGAVGA.BGI, etc.).
            
                 A unidade  GRAPH possui  uma constante  chamada DETECT,
            que, ao  ter seu  valor atribudo  ao primeiro  parmetro de
            InitGraph (o  DG anterior), detecta qual o tipo de vdeo que
            est sendo  usado. Se o string PATH for vazio ( = ''), ento
            os .BGI sero procurados no diretrio atual.
            
            Exemplo: VAR
                       dg, mg: integer;
                     ...
                     dg := DETECT;
                     INITGRAPH(dg, mg, 'C:\GRAFICOS');
                     if GRAPHRESULT < 0 then
                       Writeln('ERRO: O modo grafico nao foi possivel');
                     ...
            
                 O fragmento  acima, coloca  o vdeo  em modo grfico se
            sua execuo  for bem  sucedida.   necessrio que o arquivo
            .BGI associado  ao tipo  do vdeo  usado esteja  gravado  em
            C:\GRAFICOS. Para cada vdeo,  necessrio apenas um arquivo
            .BGI especfico.  Se a  operao  de  mudana  para  o  modo
            grfico  for  bem  sucedida,  ento  a  funo  pr-definida
            GRAPHRESULT tem  valor  nulo;  caso  contrrio,  GRAPHRESULT
            assume um valor negativo.
                 Vamos escrever  o fragmento  acima sob  a forma  de  um
            procedimento, grav-lo  em disco sob o nome de GRAF.INC. Va-
            mos supor que os arquivos .BGI esto em C:\LINGUAGE\PASCAL.
            
            PROCEDURE IniciaModoGrafico;
            
            VAR
              DriverGrafico, ModoGrafico: integer;
            
            BEGIN
              DriverGrafico := Detect;
              InitGraph(DriverGrafico,ModoGrafico,'C:\LINGUAGE\PASCAL');
              if (GraphResult < 0) then
              begin
                Writeln('ERRO na mudana para o modo grafico.');
                Halt
              end
            END;
            
                 Uma vez iniciado com sucesso o modo grfico do vdeo, 
            possvel se  construir telas  grficas. Para encerrar o modo
            grfico e voltar ao modo texto, temos duas opes:
                 (1) usar o comando CLOSEGRAPH;
                 (2) usar RESTORECRTMODE.
                 A diferena  entre CloseGraph e RestoreCrtMode  que na
            segunda opo,   possvel  se voltar  ao modo grfico sem a

                                       - 179 -





            necessidade de  se  executar  InitGraph;  basta  se  usar  o
            comando SETGRAPHMODE, cuja sintaxe 
                                SetGraphMode(n)
            onde n  um inteiro que corresponde ao modo grfico. Uma boa
            opo para  n   n = GETGRAPHMODE. GetGraphMode  uma funo
            pr-definida que  retorna um  inteiro correspondente ao modo
            grfico. Se  for usado um CloseGraph, ento a nica forma de
            voltar ao modo grfico novamente  usando um InitGraph.
            
            Exemplo: No  fragmento a  seguir, o  modo grfico do vdeo 
            usado alternadamente com o modo texto.
            
            ...
            {$I Graf.Inc}
            ...
            IniciaModoGrafico; (* Inicia o modo grfico *)
            ...
               (* Construes de telas em modo grfico *)
            ...
            RestoreCrtMode; (* De volta ao modo texto *)
            ...
               (* Construes de telas em modo texto *)
            ...
            SetGraphMode(GetGraphMode); (* De volta ao modo grfico *)
            ...
               (* Construes de telas em modo grfico *)
            ...
            CloseGraph; (* Encerra o modo grfico *)
            ...
               (* Construes de telas em modo texto *)
            ...
            
                 Muitos dos  comandos  da  unidade  Graph  referem-se  
            construo de figuras geomtricas. Entre eles, destacamos os
            seguintes:
            
                 LINE(x1, y1, x2, y2) ---> Desenha uma reta ligando os
                                           pontos (x1, y1) e (x2, y2).
            
                 CIRCLE(x, y, r) ---> Desenha a circunferncia de
                                      centro  (x, y)  e  raio  r.
            
                 RECTANGLE(x1, y1, x2, y2) ---> Retngulo cujos vrtices
                                                superior esquerdo  e in-
                                                ferior    direito    so
                                                (x1, y1)   e   (x2, y2),
                                                respectivamente.
            
                 ELLIPSE(x, y, t1, t2, a, b) ---> Parte   da  elipse  de
                                      centro (x, y) e raios horizontal e
                                      vertical, respectivamente iguais a
                                      a e b, compreendida entre os ngu-
                                      los t1 e t2 (em graus, medidos com
                                      relao ao centro da elipse).

                                       - 180 -





            
            Exemplo: O  programa a seguir desenha uma circunferncia, um
            quadrado e uma elipse, todos com centro no centro da tela.
            
            PROGRAM Circunferencia_Quadrado_Elipse;
            
            USES
              Graph, Crt;
            
            {$i graf.inc}
            
            VAR
              a, b: integer;
            
            BEGIN
              IniciaModoGrafico;
              a := GetMaxX div 2; (* Coordenadas do centro *)
              b := GetMaxY div 2; (* da tela               *)
            
              CIRCLE(a, b, 150);
              RECTANGLE(a - 80, b - 40, a + 80, b + 40);
              ELLIPSE(a, b, 0, 360, 120, 20);
            
              Delay(5000); (* Pausa de 5 segundos *)
              CloseGraph
            END.
            
            Exemplo: No presente exemplo, usamos um FOR para construir
            vrias circunferncias de centro no centro da tela e raios
            iguais a 10, 20, ..., 200.
            
            PROGRAM Circunferencias_concentricas;
            
            USES
              Graph, Crt;
            
            {$I Graf.Inc}
            
            VAR
              i: word;
            
            BEGIN
              IniciaModoGrafico;
            
              for i := 1 to 20 do
                CIRCLE(GetMaxX div 2, GetMaxY div 2, 10*i);
            
              repeat until KeyPressed; (* Pausa *)
              CloseGraph
            END.
            
            Exemplo: O deslocamento de retas na tela muitas vezes tem um
            efeito visual  muito bonito.  Para se conseguir isso, usamos
            um lao  FOR, REPEAT  ou WHILE  para fazer um parmetro TETA

                                       - 181 -





            variar de  um valor  inicial at  um valor  final. Para cada
            valor de TETA, desenhamos uma reta.
            
            (* ====================================================== *)
            (*                        RETAS.PAS                       *)
            (* ====================================================== *)
            
            PROGRAM Deslocamento_de_retas;
            
            USES
              Graph, Crt;
            
            {$I GRAF.INC}
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE Desenho1;
            
            VAR
              teta: real;
              x1, x2, y1, y2: integer;
            
            BEGIN
              ClearDevice; (* Limpa a tela *)
              teta := 0;
              repeat
                x1 := Round(GetMaxX/2 + Cos(teta)*(GetMaxX/6));
                y1 := Round(GetMaxY/2 + Cos(teta)*(GetMaxY/2));
                x2 := Round(GetMaxX/2 + Sin(teta)*(GetMaxX/3));
                y2 := Round(GetMaxY/2 - Sin(teta)*(GetMaxY/4));
                Line (x1, y1, x2, y2);
                teta := teta + Pi/45;
              until teta > 2*Pi;
            END;
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE Desenho2;
            
            VAR
              teta, fi, omega: real;
              x1, x2, x3, y1, y2, y3: integer;
            
            BEGIN
              ClearDevice; (* Limpa a tela *)
              teta := 0;
              repeat
                fi := teta + 2*Pi/3;
                omega := teta + 4*Pi/3;
                x1 := Round(GetMaxX/2 + Cos(teta)*(GetMaxX/3.5));
                y1 := Round(GetMaxY/2 + Sin(teta)*(GetMaxY/2));
                x2 := Round(GetMaxX/2 + Cos(fi)*(GetMaxX/3.5));
                y2 := Round(GetMaxY/2 + Sin(fi)*(GetMaxY/2));
                x3 := Round(GetMaxX/2 + Cos(omega)*(GetMaxX/3.5));

                                       - 182 -





                y3 := Round(GetMaxY/2 + Sin(omega)*(GetMaxY/2));
                Line (x1, y2, x2, y1);
                Line (x2, y3, x3, y2);
                Line (x3, y1, x1, y3);
                teta := teta + Pi/45;
              until teta > 2*Pi/3;
            END;
            
            (* ------------------------------------------------------ *)
            
            BEGIN
              IniciaModoGrafico;
              Desenho1;
              Delay(2000);             (* Pausa de 2 segundos    *)
              Desenho2;
              repeat until KeyPressed; (* Espera ser pressionada *)
                                       (* uma tecla              *)
              CloseGraph;              (* Encerra o modo grafico *)
            END.
            
            
                 No modo  grfico, os comandos usados em modo texto para
            limpar tela,  mudar cores,  GoToXY, ...,  no funcionam.  No
            entanto, a  unidade  Graph  tem  comandos  equivalentes  que
            executam essas funes:
            
                 ClearDevice    ---> Limpa a tela no modo grfico
                 SetColor(X)    ---> Define a cor do texto X
                 SetBkColor(Y)  ---> Define a cor de fundo Y
            
                 Alm das  cores, podemos  definir tambm o tipo de reta
            que queremos  que desenhe  a figura:  se  uma  reta  slida,
            pontilhada, fina,  grossa, etc.  As figuras tambm podem ser
            preenchidas com caracteres que podem ser escolhidos: pontos,
            barras, barras invertidas, traos cruzados, etc.
            
              SetLineStyle(estilo, padro, largura) ---> Define o estilo
                                com  o  qual  sero desenhadas as retas.
                                ESTILO, PADRO e LARGURA  so  variveis
                                do tipo word. ESTILO pode variar  de 1 a
                                4, dependendo  da  reta  ser  slida  ou
                                pontilhada. Se estilo for 4, ento pode-
                                se definir um  PADRO  para o desenho da
                                reta. A LARGURA pode ser 1 (normal) ou 3
                                (larga).
            
                 SETCOLOR, SETBKCOLOR  e SETLINESTYLE  afetam  todas  as
            construes feitas aps sua execuo, tanto de retas como de
            circunferncias ou de qualquer outra figura.
            
              SetFillStyle(padro, cor) ---> Define o  padro  que  ser
                                    usado para preencher regies. PADRO
                                    pode ser  um inteiro de 0 a 12 e COR
                                    pode variar de 0 a 15.

                                       - 183 -





            
              FloodFill(X, Y, cor) ---> Preenche  a  regio que contm o
                               ponto (X, Y) e fronteira de COR fornecida
                               como terceiro parmetro.
            
            Exemplo:  Neste  exemplo,  desenhamos  um  retngulo  e  uma
            circunferncia em linhas grossas e preenchemos com um padro
            determinado.
            
            PROGRAM Preenchendo_figuras;
            
            USES
             Graph, Crt;
            
            {$I GRAF.INC}
            
            BEGIN
              IniciaModoGrafico;
            
              SetColor(4); (* Ajusta a cor dos pixeis em 4 (vermelho) *)
            
              SetLineStyle(0, 0, 3); (* Linha solida (primeiro para-
                                        metro = 0) e grossa (tercei-
                                        ro parametro = 3)            *)
            
              Rectangle(0, 0, 300, 90);        (* Desenho das figuras *)
              Circle(500, 150, 110);           (* desejadas           *)
            
              SetFillStyle(10, 7); (* Ajusta o padrao de preenchimento
                                      em 10 e a cor em 7 (cinza)      *)
              FloodFill(5, 5, 7); (* Preenche a partir do ponto (5,5) *)
            
              SetFillStyle(8, 7);  (* Ajusta o padrao de preenchimento
                                      em 8 e a cor em 7               *)
              FloodFill(505, 155, 7); (* Preenche a partir do ponto
                                         (505, 155)                   *)
            
              repeat until KeyPressed;      (* Espera ser pressionada *)
                                            (* qualquer tecla         *)
              CloseGraph
            END.
            
            12.2. TEXTOS EM MODO GRFICO            
            
                 Os comandos  de sada como Write, Writeln, GoToXY, ...,
            no funcionam em modo grfico. A unidade Graph fornece todos
            os comandos  necessrios para  a edio  de textos  em  modo
            grfico. O  comando anlogo  ao  GoToXY    o  MOVETO,  cuja
            sintaxe :
            
                 MoveTo(X, Y) ---> Direciona a sada na tela em modo
                                   grfico para o ponto (X, Y).
            
            

                                       - 184 -





                 OutText(texto) ---> Mostra na tela em modo grfico o
                                     string TEXTO
            
                 OutTextXY(X, Y, texto)  ---> Uma  combinao  dos  dois
                            comandos anteriores: mostra na tela o string
                            TEXTO na posio (X, Y).
            
                 O tipo  de letra  impresso em  modo  grfico  pode  ser
            ajustado atravs do comando SETTEXTSTYLE.
            
              SetTextStyle(letra, direo, tamanho) ---> Ajusta  o tipo
                     de letra, direo e tamanho do texto impresso  por
                     OUTTEXT e OUTTEXTXY. Os parmetros so inteiros do
                     tipo word. LETRA pode ser 0, 1, 2, 3 ou 4 que cor-
                     respondem,  respectivamente,  aos tipos  de  letra
                     padro, "triplex", pequeno, "sans serif" e gtico.
                     DIREO pode ser 0 ou 1, correspondendo  respecti-
                     vamente s direes horizontal e vertical.
            
                 Podem ser  usados como  parmetros de  SetTextStyle  as
            seguintes constantes:
            
                      DefaultFont   = 0;  (* Tipos  de letra *)
                      TriplexFont   = 1;  (* em modo grfico *)
                      SmallFont     = 2;
                      SansSerifFont = 3;
                      GothicFont    = 4;
            
                      HorizDir     = 0;  (* Direo horizontal *)
                      VertDir      = 1;  (* Direo vertical   *)
            
                 A sada  de um  texto pode  ser ajustada  com relao 
            posio atual  do cursor  na tela.  Com  relao    direo
            horizontal,     possvel  o   texto  ser   centralizado  ou
            justificado   esquerda ou   direita. Com relao  direo
            vertical o  texto pode ser centralizado, justificado no topo
            ou justificado  no fundo.  Por exemplo, o P desenhado abaixo
            representa a posio do cursor na tela:
            
                                          P
             -----------------------------+----------------------------
             |TEXTO CENTRALIZADO HORIZONTALMENTE E JUSTIFICADO NO TOPO|
            
            
                |TEXTO JUSTIFICADO  DIREITA E JUSTIFICADO NO FUNDO|
                ---------------------------------------------------+ P
            
                 SetTextJustify(hor, ver) ---> Ajusta  a  sada do texto
                             em torno da posio atual do  cursor. HOR e
                             VER so inteiros que variam de 0 a 2.
            
                 No lugar  de 0,  1, 2,  podem ser  usadas as  seguintes
            constantes:
            

                                       - 185 -





                CenterText = 1;  (* Centraliza texto, direo vertical
                                    ou horizontal *)
                LeftText   = 0;  (* Ajusta  esquerda *)
                RightText  = 2;  (* Ajusta  direita  *)
                BottomText = 0;  (* Justifica com relao ao fundo *)
                TopText    = 2;  (* Justifica com relao ao topo *)
            
            Exemplo: Neste exemplo, escrevemos "Turbo Pascal" na tela em
            diferentes tamanhos, direes e tipos de letra.
            
            PROGRAM Letras;
            
            (* ===================================================== *)
            (*           TIPOS DE LETRAS DO TURBO PASCAL             *)
            (* ===================================================== *)
            
            USES
              Crt, Graph;
            
            {$I GRAF.INC}
            
            CONST
              mens: string = 'Turbo Pascal';
            
            BEGIN
              IniciaModoGrafico;
              ClearDevice;
            
              SetTextStyle(DefaultFont, HorizDir, 1);
              OutTextXY(1, 5, mens);
              OutTextXY(200, 50, 'Tipo padrao');
            
              SetTextStyle(TriplexFont, HorizDir, 1);
              OutTextXY(130, 5, mens);
              OutTextXY(200, 70, 'Tipo "triplex"');
            
              SetTextStyle(SmallFont, HorizDir, 3);
              OutTextXY(300, 5, mens);
              OutTextXY(200, 110, 'Tipo pequeno');
            
              SetTextStyle(SansSerifFont, HorizDir, 1);
              OutTextXY(360, 5, mens);
              OutTextXY(200, 130, 'Tipo "sans serif"');
            
              SetTextStyle(GothicFont, HorizDir, 1);
              OutTextXY(500, 5, mens);
              OutTextXY(200, 160, 'Tipo gotico');
            
              SetTextStyle(TriplexFont, HorizDir, 1);
              OutTextXY(450, 50, 'Tam 1');
              SetTextStyle(TriplexFont, HorizDir, 2);
              OutTextXY(450, 70, 'Tam 2');
              SetTextStyle(TriplexFont, HorizDir, 3);
              OutTextXY(450, 90, 'Tam 3');

                                       - 186 -





              SetTextStyle(TriplexFont, HorizDir, 4);
              OutTextXY(450, 110, 'Tam 4');
              SetTextStyle(TriplexFont, HorizDir, 5);
              OutTextXY(450, 140, 'Tam 5');
            
              SetTextJustify(CenterText, BottomText);
              SetTextStyle(GothicFont, VertDir, 3);
              OutTextXY(5, 180, mens);
            
              SetTextStyle(TriplexFont, VertDir, 3);
              OutTextXY(35, 180, mens);
            
              SetTextStyle(SmallFont, VertDir, 7);
              OutTextXY(70, 180, mens);
            
              repeat until KeyPressed;
              CloseGraph;
            END.
            
            Exemplo: O  programa a  seguir mostra  na tela  uma  moldura
            formada por  dois retngulos. O espao entre os retngulos 
            preenchido com  um  determinado  padro  de  caracteres.  No
            centro da  tela,  mostrado em letras gticas de tamanho 8 o
            ttulo da  tela, que  deve ser  fornecido ao  programa  como
            parmetro.  Compile  em  disco  este  programa  com  o  nome
            TELAINI.EXE.
            
            PROGRAM Tela_Inicial;
            
            USES
              Crt, Graph;
            
            {$I GRAF.INC}
            
            PROCEDURE TelaInicial(titulo: string);
            
            BEGIN
              ClearDevice;  (* Limpa a tela *)
            
              SetTextStyle(GothicFont, HorizDir, 8);    (* Ajustes do *)
              SetTextJustify(CenterText, CenterText);   (* texto      *)
              SetFillStyle(11, 4);   (* Caracteres para preenchimento *)
              SetLineStyle(0, 0, 3); (* Tipo de reta                  *)
            
              Rectangle(0, 0, GetMaxX, GetMaxY);
              Rectangle(60, 30, GetMaxX - 60, GetMaxY - 30);
            
              FloodFill(3, 3, 15); (* Preenche a partir do ponto (3, 3)
                                      com o padrao 15 *)
              OutTextXY(320, 100, titulo);
            END;
            
            BEGIN
              if (ParamCount = 0) then

                                       - 187 -





              begin
                Writeln(#7, 'Forma de usar: TELAINI titulo');
                Halt
              end;
              IniciaModoGrafico;
              TelaInicial(ParamStr(1));
              repeat until KeyPressed; (* Pausa *)
              CloseGraph       (* Encerra o modo grafico *)
            END.
            
                 Executando este  programa com  o parmetro  "Graficos",
            vemos uma tela como a da figura 1 a seguir.
            
            12.3. GRFICOS DE FUNES y = f(x)      
            
                 Suponhamos que  o plano  cartesiano desenhado  a seguir
            esteja sobreposto  ao desenho  da tela e que est marcado um
            mesmo ponto P, tanto no plano cartesiano como na tela. Vamos
            descobrir que  relaes existem entre as coordenadas de P no
            plano e as coordenadas de P na tela.
            
            
                                  PLANO CARTESIANO
                  y2 +-----------------------------------------+
                     |                                         |
                     |                                         |
                     |                                         |
                     |                                         |
                     |                                         |
                   y +------------------+ P                    |
                     |                  |                      |
                     |                  |                      |
                     |                  |                      |
                     |                  |                      |
                     |                  |                      |
                  y1 +------------------+----------------------+
                     x1                 x                     x2
            
            
                     0                  A                  GetMaxX
                   0 +------------------+----------------------+
                     |                  |                      |
                     |                  |                      |
                     |                  |                      |
                     |                  |                      |
                     |                  |                      |
                   B +------------------+ P                    |
                     |                                         |
                     |                                         |
                     |                                         |
                     |                                         |
                     |                                         |
             GetMaxY +-----------------------------------------+
                              TELA EM MODO GRFICO

                                       - 188 -




                 Os segmentos  [x1, x]  e [x1, x2] no plano devem ter os
            mesmos comprimentos que [0, A] e [0, GetMaxX] na tela. Logo,
            devemos ter:
                               x - x1              A
                             -----------  =  -----------
                               x2 - x1         GetMaxX
            
            de onde temos as seguintes relaes entre x e A:
            
                                   (x2 - x1)*A
                            x =  ---------------  +  x1              [1]
                                     GetMaxX
            
                                    (x - x1)*GetMaxX
                            A  =  --------------------               [2]
                                        x2 - x1
            
                 Os segmentos  [y, y2]  e [y1, y2] tm os mesmos compri-
            mentos que [0, B] e [0, GetMaxY]. Portanto,
            
                               y2 - y            B
                             ----------- =  -----------
                               y2 - y1        GetMaxY
            
            de onde temos as seguintes relaes:
            
                                         B*(y2 - y1)
                           y =  y2  -  ---------------               [3]
                                           GetMaxY
            
                                   (y2 - y)*GetMaxY
                           B  =  --------------------                [4]
                                      (y2 - y1)
            
                 Conhecidas as coordenadas (x, y) de um ponto P no plano
            cartesiano, usando  as equaes  [1]  -  [4]  acima  podemos
            calcular as coordenadas (A, B) na tela e vice-versa.
            
                  y2 +---------+-------------------------------+
                     |       e ^                               |
                     |       i |                               |
                     |       x |                               |
                     |       o |                               |
                     |       - |                               |
                     |       y |                               |
                   0 +---------+------------------------------>+
                     |         |            eixo-x             |
                     |         |                               |
                     |         |                               |
                     |         |                               |
                  y1 +---------+-------------------------------+
                     x1        0                              x2

                                       - 190 -





            
                 O  eixo-x  no  nosso  limitado  plano  cartesiano    o
            segmento de  reta que  liga os pontos (x1, 0) e (x2, 0), e o
            eixo-y  o segmento ligando os pontos (0, y1) e (0, y2).
            
                 Usando as  equaes [2]  e [4]  anteriores,  temos  que
            esses pontos  na tela correspondem a (0, ex), (GetMaxX, ex),
            (ey, GetMaxY) e (ey, 0), onde
            
                                         GetMaxY*y2
                           ex = Round( -------------- )
                                           y2 - y1
            
                                        GetMaxX*x1
                           ey = Round( ------------- )
                                          x1 - x2
            
                 A funo  ROUND usada  acima    necessria  porque  as
            coordenadas de pontos na tela devem ser inteiras. Poderamos
            tambm ter usado a funo TRUNC.
            
            Observao: Para  cada vdeo,  as funes  GetMaxX e GetMaxY
            funcionam como se fossem constantes.
            
            Exemplo:  Usaremos  algumas  das  equaes  anteriores  para
            desenhar a  parte do  grfico de uma funo y = f(x) contida
            no retngulo  [x1, x2]  x [y1,  y2]. Seguiremos as seguintes
            etapas na construo do grfico:
            
                 (1) Colocamos  a tela  em modo  grfico e desenhamos os
            eixos coordenados com os comandos LINE(0, ex, GetMaxX, ex) e
            LINE (ey,  0, ey,  GetMaxY), onde  ex e  ey so  os  valores
            calculados anteriormente;
                 (2) Atribumos   varivel  inteira A (que representa a
            primeira coordenada do ponto na tela) o valor inicial 0;
                 (3) Para  cada valor de A, calculamos o "x" corresponde
            no plano cartesiano.
                 (4) Calculamos  o valor  y da funo f no ponto x, isto
            , calculamos y = f(x), e usamos a equao [4] anterior para
            calcular qual a segunda coordenada B do ponto na tela;
                 (5) Marcamos  o ponto (A, B) na tela. Para isso, usamos
            o comando PUTPIXEL cuja sintaxe :
            
                 PutPixel(X, Y, cor) ---> Marca na tela o ponto (X, Y)
                                          com COR determinada.
            
                 (6) Incrementamos  A  de  Delta  unidades.  Se  aps  o
            acrscimo de  Delta, A   ficar  menor  do  que  ou  igual  a
            GetMaxX, ento  voltamos ao  passo (3);  caso  contrrio,  a
            construo do grfico est encerrada.
            
                 Os  passos  (1)-(6)  acima  podem  ser  codificados  no
            seguinte programa.  Os valores  de delta,  x1,  x2,  y1,  y2

                                       - 191 -





            poderiam ser  fornecidos atravs de comandos de leitura como
            o Readln.
            
            PROGRAM Grafico_plano;
            
            (* Constroi o grafico da funcao y = f(x), marcando
               na  tela  GetMaxX/Delta  pontos  isolados       *)
            
            USES
              Crt, Graph;
            
            {$I GRAF.INC}
            
            FUNCTION f(x: real): real;      (* Definicao da  funcao f *)
            begin                           (* cujo  grafico  vai ser *)
              f := Abs(x*x - 5*Abs(x) + 6)  (* construdo             *)
            end;
            
            VAR
              x, y, x1, x2, y1, y2: real;
              A, B, delta, ex, ey: integer;
              aux1, aux2: string;
            
            BEGIN
              x1 := -5; x2 := 5;    (* Variacao do x              *)
              y1 := -1; y2 := 10;   (* Variacao do y              *)
              delta := 2;           (* Quanto maior o delta, mais *)
                                    (* rapida e mais  grosseira a *)
                                    (* construcao do grafico      *)
              IniciaModoGrafico;
            
              ex := Round(GetMaxY*y2/(y2 - y1));
              ey := Round(GetMaxX*x1/(x1 - x2));
              Line(0, ex, GetMaxX, ex);       (* Desenha o eixo x *)
              Line(ey, 0, ey, GetMaxY);       (* Desenha o eixo y *)
            
              A := 0;                    (* Construcao do grafico *)
              repeat
                x := x1 + (x2 - x1)*A/GetMaxX;
                y := f(x);
                B := Round(GetMaxY*(y2 - y)/(y2 - y1));
                PutPixel(A, B, 7); (* Marca na tela o ponto (A, B) *)
                A := A + delta;
              until A > GetMaxX;
            
              repeat until KeyPressed; (* Pausa *)
              CloseGraph;     (* Encerra o modo grafico *)
            END.
            
            
            Exemplo: O  atual  programa-exemplo    um  melhoramento  do
            anterior. Definimos um procedimento DesenhaGrafico que faz o
            equivalente ao que o programa anterior fazia.

                                       - 192 -





                 Os comandos  para impresso  de textos  em modo grfico
            no imprimem  valores numricos. Por isso, vamos transformar
            os valores  de x1,  y1, x2, y2 em strings para mostr-los na
            tela atravs  de um OutTextXY. O procedimento que transforma
            valores numricos em strings  o STR:
            
                 STR(val:m:n, s) ---> Converte o valor numrico  VAL no
                                      string S, usando um campo de lar-
                                      gura M com N casas decimais.  Por
                                      exemplo, STR(Pi:4:2, x)  o mesmo
                                      que x := '3.14'.
            
                 Usaremos tambm o caracter ASCII #243 que corresponde a
            um sinal de menor ou igual.
                 Ao invs  de marcarmos cada ponto isoladamente, como no
            programa  anterior,   vamos  lig-los  atravs  de  pequenos
            segmentos de  reta. Poderamos usar um comando LINE no lugar
            do PUTPIXEL  anterior, mas  fica mais  fcil ligar os pontos
            usando-se um LINETO, cuja sintaxe :
            
                 LineTo(X, Y) ---> Desenha um segmento de reta ligando o
                                   ponto (X, Y) ao ponto que corresponde
                                    posio atual do cursor na tela.
            
                 Se a  variao do  x for simtrica, ou seja, se x1 e x2
            tiverem o  mesmo mdulo,  ento ser mostrado na tela um "y"
            na parte  superior da  tela e junto do eixo-y. Se a variao
            do y  for simtrica (|y1| = |y2|), ser mostrado um "x" logo
            abaixo do eixo-x e  direita da tela.
                 A diretiva  de compilao  {$F+}   necessria para  se
            poder passar  uma funo  como parmetro para o procedimento
            DesenhaGrafico.
            
            
            PROGRAM Grafico_plano; (* Versao 2 *)
            
            (* ====================================================== *)
            (*             GRAFICO DE UMA FUNCAO y = f(x)             *)
            (* ====================================================== *)
            
            USES
              Crt, Graph;
            
            {$F+}
            
            {$I GRAF.INC}
            
            TYPE
              funcao = function(x: real): real;
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE DesenhaGrafico(f: funcao; delta: byte;
                                                  x1, x2, y1, y2: real);

                                       - 193 -





            
            VAR
              A, B, ex, ey: integer;
              x, y: real;
              aux1, aux2, mens: string;
            
            BEGIN
              Str(x1:5:2, aux1);         (* Mostra na tela a variacao *)
              Str(x2:5:2, aux2);         (* do x e do y               *)
              mens := aux1 + ' ' + #243 + ' x '+ #243 + ' ' + aux2;
              OutTextXY(1, 1, mens);
              Str(y1:5:2, aux1);
              Str(y2:5:2, aux2);
              mens := aux1 + ' ' + #243 + ' y '+ #243 + ' ' + aux2;
              OutTextXY(1, 10, mens);
            
              ex := Round(GetMaxY*y2/(y2 - y1));
              ey := Round(GetMaxX*x1/(x1 - x2));
            
              Line(0, ex, GetMaxX, ex);  (* Desenha o eixo x *)
              if Abs(y1) = Abs(y2) then
                OutTextXY(GetMaxX - 10, GetMaxY div 2 + 2, 'x');
            
              Line(ey, 0, ey, GetMaxY);  (* Desenha o eixo y *)
              if Abs(x1) = Abs(x2) then
                OutTextXY(GetMaxX div 2 + 12, 0, 'y');
            
              A := 0;               (* Construcao do grafico *)
              repeat
                x := x1 + (x2 - x1)*A/GetMaxX;
                y := f(x);
                B := Trunc(GetMaxY*(y2 - y)/(y2 - y1));
                if (A = 0) then MoveTo(A, B) else LineTo(A, B);
                A := A + delta;
              until A > GetMaxX;
            END;
            
            (* ------------------------------------------------------ *)
            
            FUNCTION f(x: real): real;
            begin
              f := sin(x) + sin(3*x)/3 + sin(5*x)/5 + sin(7*x)/7
            end;
            
            BEGIN
              IniciaModoGrafico;
              DesenhaGrafico(f, 2, -7, 7, -2, 2);
              repeat until KeyPressed;
              CloseGraph
            END.
            
                 Antes da  execuo do  programa acima,   necessrio se
            digitar no  "prompt" do  DOS  o  comando  GRAFTABL.  Isso  
            necessrio porque foi usado no programa um caracter ASCII de

                                       - 194 -





            ordinal maior  do que  127, que s aparecer na tela em modo
            grfico aps a execuo do GRAFTABL (= "tabela grafica").
                 A figura  2   uma impresso  da tela  gerada por  esse
            programa.
                 Como exerccio,  complemente o  programa acima  com  um
            procedimento MOSTRA_FUNCAO  que admita  um parmetro do tipo
            string  e   que  imprima  esse  parmetro  na  tela  aps  a
            construo do  grfico, mostrando  que funo est associada
            aquele grfico (Ex.: Mostra_funcao('y = Cos(x)')).
            
            12.4. EQUAES PARAMTRICAS E COORDENADAS POLARES   
            
                 Vamos usar  o seguinte  algoritmo para  a construo do
            grfico definido  pelas  equaes  paramtricas  x  =  f(t),
            y = g(t):
            
                 (1) Colocamos  a tela  em modo  grfico e desenhamos os
            eixos coordenados;
                 (2) Atribumos ao parmetro t o valor inicial;
                 (3) Calculamos os valores de x = f(t) e y = g(t);
                 (4) Usamos  as  equaes  [2]  e  [4]  anteriores  para
            calcular as coordenadas (A, B) do ponto na tela;
                 (5) Marcamos  o  ponto  (A,  B)  ou,  equivalentemente,
            desenhamos a reta ligando (A, B)  posio atual do cursor;
                 (6) Incrementamos o parmetro t de Delta unidades; se o
            novo valor  de t for menor do que ou igual ao valor final do
            parmetro, ento  voltamos ao  passo (3); em caso contrrio,
            encerramos a construo do grfico.
            
            Exemplo: Podemos  usar o  algoritmo acima  para construir  o
            seguinte programa, que  semelhante ao anterior.
            
            
            PROGRAM Eq_Parametricas;
            
            (* ====================================================== *)
            (*             GRAFICO DE x = f(t), y = g(t)              *)
            (* ====================================================== *)
            
            USES
              Crt, Graph;
            
            {$F+}
            
            {$I GRAF.INC}
            
            TYPE
              funcao = function(x: real): real;
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE EqParametricas(f, g: funcao; delta,
                                          x1, x2, y1, y2, t1, t2: real);
            

                                       - 195 -





            VAR
              A, B, ex, ey: integer;
              t, x, y: real;
              aux1, aux2, mens: string;
            
            BEGIN
            
              Str(x1:5:2, aux1);         (* Mostra na tela a variacao *)
              Str(x2:5:2, aux2);         (* do x, y e do t            *)
              mens := aux1 + ' ' + #243 + ' x '+ #243 + ' ' + aux2;
              OutTextXY(1, 1, mens);
              Str(y1:5:2, aux1);
              Str(y2:5:2, aux2);
              mens := aux1 + ' ' + #243 + ' y '+ #243 + ' ' + aux2;
              OutTextXY(1, 10, mens);
              Str(t1:5:2, aux1);
              Str(t2:5:2, aux2);
              mens := aux1 + ' ' + #243 + ' t ' + #243 + ' ' + aux2;
              OutTextXY(1, 19, mens);
            
              ex := Round(GetMaxY*y2/(y2 - y1));
              ey := Round(GetMaxX*x1/(x1 - x2));
            
              Line(0, ex, GetMaxX, ex);  (* Desenha o eixo x *)
              if Abs(y1) = Abs(y2) then
                OutTextXY(GetMaxX - 10, GetMaxY div 2 + 2, 'x');
            
              Line(ey, 0, ey, GetMaxY);  (* Desenha o eixo y *)
              if Abs(x1) = Abs(x2) then
                OutTextXY(GetMaxX div 2 + 12, 0, 'y');
            
              t := t1;              (* Construcao do grafico *)
              repeat
                x := f(t);
                A := Round((x - x1)*GetMaxX/(x2 - x1));
                y := g(t);
                B := Round(GetMaxY*(y2 - y)/(y2 - y1));
                if (t = t1) then MoveTo(A, B) else LineTo(A, B);
                t := t + delta;
              until t > t2;
            END;
            
            (* ------------------------------------------------------ *)
            
            FUNCTION f(t: real): real;
            begin
              f := sin(3*t)
            end;
            
            FUNCTION g(t: real): real;
            begin
              g := sin(4*t)
            end;
            

                                       - 196 -





            BEGIN
              IniciaModoGrafico;
              EqParametricas(f, g, 0.02, -3, 3, -1.5, 1.5, 0, 6.29);
              repeat until KeyPressed;
              CloseGraph
            END.
            
                 Ao ser  executado este  programa, temos uma tela como a
            da figura 3.
            
            
                 Trs famlias  interessantes de  curvas  descritas  por
            equaes paramtricas so:
            
                 (1) As curvas x = Sin(a*t), y = Sin(b*t)
                 (2) As hipociclides
                       x = (a - b)*Cos(t) + k*Cos((a - b)*t/b)
                       y = (a - b)*Sin(t) - k*Sin((a - b)*t/b)
                 (3) As epiciclides
                       x = (a + b)*Cos(t) - k*Cos((a + b)*t/b)
                       y = (a + b)*Sin(t) - k*Sin((a + b)*t/b)
            
                 Nas equaes  (1), (2)  e (3)  anteriores, a, b e k so
            constantes reais quaisquer.
            
            Exemplo: Um  grfico em coordenadas polares r = f(teta) pode
            ser pensado  como  sendo  um  caso  particular  de  equaes
            paramtricas, bastando  para isso  tomar o teta como sendo o
            parmetro: x  = f(teta)*Cos(teta),  y = f(teta)*Sin(teta). O
            programa  a  seguir    apenas  uma  adaptao  do  programa
            anterior.
            
            
            PROGRAM Coord_Polares;
            
            (* ====================================================== *)
            (*             GRAFICO EM COORDENADAS POLARES             *)
            (* ====================================================== *)
            
            USES
              Crt, Graph;
            
            {$F+}
            
            {$I GRAF.INC}
            
            TYPE
              funcao = function(x: real): real;
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE CoordPolares(f: funcao; delta,
                                                x1, x2, y1, y2: real);
            

                                       - 197 -





            VAR
              A, B, ex, ey: integer;
              teta, x, y, teta1, teta2: real;
              aux1, aux2, mens: string;
            
            BEGIN
              teta1 := 0; teta2 := 2*Pi; (* Valores inicial e final *)
                                         (* de teta                 *)
            
              Str(x1:5:2, aux1);         (* Mostra na tela a variacao *)
              Str(x2:5:2, aux2);         (* do x e do y               *)
              mens := aux1 + ' ' + #243 + ' x '+ #243 + ' ' + aux2;
              OutTextXY(1, 1, mens);
              Str(y1:5:2, aux1);
              Str(y2:5:2, aux2);
              mens := aux1 + ' ' + #243 + ' y '+ #243 + ' ' + aux2;
              OutTextXY(1, 10, mens);
            
              ex := Round(GetMaxY*y2/(y2 - y1));
              ey := Round(GetMaxX*x1/(x1 - x2));
            
              Line(0, ex, GetMaxX, ex);  (* Desenha o eixo x *)
              if Abs(y1) = Abs(y2) then
                OutTextXY(GetMaxX - 10, GetMaxY div 2 + 2, 'x');
            
              Line(ey, 0, ey, GetMaxY);  (* Desenha o eixo y *)
              if Abs(x1) = Abs(x2) then
                OutTextXY(GetMaxX div 2 + 12, 0, 'y');
            
              teta := teta1;        (* Construcao do grafico *)
              repeat
                x := f(teta)*Cos(teta);
                A := Round((x - x1)*GetMaxX/(x2 - x1));
                y := f(teta)*Sin(teta);
                B := Round(GetMaxY*(y2 - y)/(y2 - y1));
                if (teta = teta1) then
                  MoveTo(A, B)
                else
                  LineTo(A, B);
                teta := teta + delta;
              until teta > teta2;
            END;
            
            (* ------------------------------------------------------ *)
            
            FUNCTION f(teta: real): real;
            begin
              f := 1 + Cos(teta)
            end;
            
            BEGIN
              IniciaModoGrafico;
              CoordPolares(f, 0.03, -4, 4, -2, 2);
              repeat until KeyPressed;

                                       - 198 -





              CloseGraph
            END.
            
            
                 Uma famlia de curvas em coordenadas polares que tm um
            grfico   interessante       a    famlia   dos    rosceos
            r = Sin(n*teta), onde n  um inteiro qualquer.
            
            
            12.4. CAPTURANDO E RESTAURANDO IMAGENS 
            
                 Uma tela  grfica ou  qualquer regio  retangular  dela
            pode ser  capturada (salva)  em uma matriz numrica. Uma vez
            capturada a imagem, pode-se mostr-la em outra parte da tela
            uma ou vrias vezes ou grav-la em disco.
                 A  matriz   usada  para  capturar  a  imagem  deve  ser
            suficientemente  grande  para  caber  toda  a  imagem.  Para
            capturar uma  imagem contida  em uma  regio  retangular  de
            medidas 10  x 10,  a matriz  deve ter  tamanho mnimo  de 26
            bytes; para  uma regio  retangular de  100 x  100, a matriz
            deve ter  pelo menos  1306 bytes  e para  capturar uma  tela
            inteira, a matriz deve ter pelo menos 16006 elementos.
                 Para se  descobrir o  tamanho necessrio para a matriz,
            podemos usar  a funo  IMAGESIZE, que  retorna um  valor do
            tipo word:
            
                 ImageSize(A, B, X, Y) --->  Retorna  o  nmero de bytes
                                     necessrios para armazenar a regio
                                     retangular cujos vrtices  superior
                                     esquerdo  e  inferior  direito  so
                                     (A, B) e (X, Y), respectivamente.
            
                 Para capturar  uma imagem  situada na regio retangular
            cujos vrtices  superior esquerdo  e  inferior  direito  so
            (x1, y1) e (x2, y2), basta usar o comando
            
                            GETIMAGE(x1, y1, x2, y2, M)
            
            onde M  a matriz que vai guardar a imagem capturada.
                 Para restaurar  na posio  (X, Y)  da tela  uma imagem
            salva em uma matriz M, basta usar
            
                            PUTIMAGE(X, Y, M, modo)
            
            onde MODO   um  inteiro de  0 a  4, que corresponde ao modo
            como a  imagem ser  mostrada (se  ela deve  apagar  ou  no
            outras imagens que j estejam na tela, etc.)
            
            Exemplo: O  fragmento  a  seguir,  salva  uma  tela  grfica
            inteira em uma matriz MAT para restaur-la posteriormente:
            
                 VAR
                   mat: array [1..16006] of byte;
            

                                       - 199 -





                   ...
                   GetImage(0, 0, 639, 199, mat); (* Captura a ima- *)
                   ...                            (* gem em MAT     *)
                   PutImage(0, 0, mat, 0);        (* Restaura MAT   *)
                   ...
            
                 No lugar  de  usar  matrizes,  poderamos  usar  outras
            estruturas, como  por exemplo  um apontador para o incio da
            parte da memria onde a tela vai ser salva.
            
            Exemplo: No  programa a  seguir, uma  imagem   salva em uma
            matriz M  para ser  mostrada depois vrias vezes em posies
            aleatrias da tela.
            
            PROGRAM Capturando_e_restaurando_uma_imagem;
            
            USES
              Crt, Graph;
            
            {$I Graf.Inc}
            
            VAR
              M: array[1..4000] of byte;
              i: word;
            
            BEGIN
              IniciaModoGrafico;
            
              (* Gera a imagem que vai ser salva na matriz M *)
              for i := 1 to 10 do
                Rectangle(50 - 5*i, 25 - 2*i, 50 + 5*i, 25 + 2*i);
            
              (* Salva a imagem na matriz M *)
              GetImage(0, 0, 100, 100, M);
            
              ClearDevice; (* Limpa a tela *)
            
              (* Mostra repetidamente a imagem salva na matriz M
                 em uma posicao aleatoria *)
              repeat
                PutImage(Random(640), Random(200), M, 1);
                Delay(500) (* Pausa de 1/2 segundo *)
              until KeyPressed;
            
              CloseGraph
            END.
            
            
                 EPLOGO: Vimos  uma parte  muito pequena do conjunto de
            79 procedimentos e funes da unidade GRAPH. Essa biblioteca
            de rotinas  grficas mereceria  ser mais explorada. O Pascal
            traz entre  seus vrios  programas-exemplo, dois dedicados 
            unidade GRAPH:  o ARTY.PAS  e o  BGIDEMO.PAS.  Vale  a  pena
            estudar ou executar esses programas pelo menos uma vez.

                                       - 200 -
