computação gráfica - pluzzardi.w.pwpluzzardi.w.pw/compgraf.pdf · 4 1. introdução à...

57
1 Computação Gráfica por Prof. Dr. Paulo Roberto Gomes Luzzardi facebook: Paulo Roberto Gomes Luzzardi e-mail: [email protected] dropbox: https://www.dropbox.com/sh/kea9kr4j2qttnjg/4xXvw0pvxX?m Versão 2.04 Pelotas, 18 de abril de 2013

Upload: truongmien

Post on 08-Nov-2018

235 views

Category:

Documents


1 download

TRANSCRIPT

1

Computação Gráfica

por

Prof. Dr. Paulo Roberto Gomes Luzzardi

facebook: Paulo Roberto Gomes Luzzardi e-mail: [email protected]

dropbox: https://www.dropbox.com/sh/kea9kr4j2qttnjg/4xXvw0pvxX?m

Versão 2.04

Pelotas, 18 de abril de 2013

2

Programa 1. Introdução a Computação Gráfica Interativa 1.1 Introdução geral à Computação Gráfica e a Disciplina 1.1.1 Definições 1.1.2 Aplicações da Computação Gráfica 1.1.3 Dificuldades 1.2 Dispositivos Gráficos 1.2.1 Entrada 1.2.2 Saída 1.2.3 Armazenamento 1.3 Sistemas Gráficos Interativos Bidimensionais 2. Transformações Bi-dimensionais 2.1 Dispositivos de Visualização 2.1.1 Resolução (Pixel) 2.1.2 Placas Gráficas 2.1.3 Sistema de Referência do Dispositivo de Visualização 2.1.4 Pacote Gráfico 2.2 Transformações Geométricas 2.2.1 Sistemas de Coordenadas 2.2.1.1 Cartesiano 2.2.1.2 Polar 2.2.2 Escala 2.2.3 Translação 2.2.4 Rotação 2.2.5 Espelhamento 2.2.6 Cisalhamento 2.3 Transformações de Coordenadas (Mudança de Eixos) 2.4 Visualização Bidimensional 2.4.1 Coordenadas de Universo 2.4.2 Coordenadas de Dispositivo 2.4.3 Coordenadas de Objeto 2.4.4 Janela de Seleção 2.4.5 Recorte 2.5 Estruturas de Dados para Representação de Primitivas Geométricas 3. Traçado de Curvas 4. Preenchimento de Polígonos 5. Modelagem Bi-dimensional 3.1 Marcar Elemento 3.2 Mover Elementos 3.3 Selecionar Elementos 3.4 Copiar Elementos 3.5 Dividir Elementos

3

4

1. Introdução à Computação Gráfica Interativa 1.1 Introdução Geral à Computação Gráfica 1.1.1 Definições "A Computação Gráfica é a área da Ciência da Computação que estuda a geração, manipulação e interpretação de imagens gerando métodos e técnicas para transformar dados numéricos em imagens, permitindo auxílio ao desenvolvimento de trabalhos que exijam efeitos visuais". "A Computação Gráfica é um ramo particular da Informática, no qual, o computador é utilizado para a criação e manipulação de imagens com a interferência do operador". Pode-se classificar a Computação Gráfica de dois modos:

Figura 1: Classificação da Computação Gráfica

Síntese de Imagens: É como as imagens são geradas (por exemplo, digitalização de imagens, imagens de Satélites, imagens de Radar, imagens geradas através de dados numéricos, imagens geradas através de equipamentos elétricos ou eletrônicos, entre outros).

Análise de Imagens: Toda análise feita em uma imagem. Processamento de Imagens: Toda modificação feita em uma imagem. Um computador, uma imagem e um operador são os elementos essenciais para a Computação Gráfica Interativa. No processo de criação de imagens, em um Sistema de Computação Gráfica dinâmico e interativo, são necessários cinco características que facilitem a manipulação por parte do operador:

l Conteúdo da imagem; l Disposição dos elementos que compõem a imagem; l Tamanho da imagem e/ou dos elementos que compõem a imagem; l Formato da imagem; l Cores ou tons de uma cor no caso de imagens monocromáticas.

Um Sistema Gráfico possui três partes principais: 1) Equipamento 2) Programas 3) Documentação Equipamento Básico 1) Unidade de Processamento (Microprocessador) 2) Memória (Interna – RAM e Externa - Disco) 3) Periféricos de Entrada 4) Periféricos de Saída

5

Programas Fundamentais: 1) Sistema Operacional: Controla a máquina e seus periféricos. 2) Linguagem de Programação: Permite a criação de ferramentas gráficas para síntese (geração), análise e processamento das imagens. Estilos Gráficos 1) Gráficos de Caracteres ou de Mosaico Existe um conjunto de caracteres gráficos fornecidos pela máquina (Tabela ASCII). Muito limitado, próprio para construção de gráficos simples, videotexto e imagens para jogos. http://www.asciitable.com 2) Gráficos Caligráficos Os desenhos são formados por linhas. Muito utilizados para gráficos no papel, para produzir desenhos complexos. Não é próprio para preenchimento de áreas coloridas, realismo ou sombreados (caracteres presentes na tabela ASCII para desenhar retângulos, por exemplos). 3) Gráficos de Pixel São formados por pontos muito próximos. Permite desenhar linhas e áreas de diversas cores. Um problema é a resolução da máquina, pois as linhas diagonais tem forma de escada.

Figura 2: Resolução de tela Primitivas Gráficas Conjunto específico de instruções de desenhos (comandos) que permitem plotar pontos, linhas, retângulos, círculos, arcos, etc. 1.1.2 Aplicações da Computação Gráfica 1.1.2.1 Animação Quadro à quadro: A montagem da animação é feita imagem por imagem. Por exemplo, para a televisão, são necessários de 24 a 30 quadros por segundo sendo que cada imagem é mostrada duas vezes para evitar um efeito em que a tela fica branca a cada troca de imagem. Tempo Real: É feita através de um roteiro. Dentro do qual, as cenas são montadas a partir de uma cena inicial e uma final, o computador se encarrega de criar as cenas intermediárias exibindo-as em tempo real. 1.1.2.2 Editores Gráficos Desenho: São utilizados para criação de imagens, slides, cenários, desenhos, etc. Texto: São utilizados para a criação de caracteres de várias formas (caracteres especiais), tipos e tamanhos.

6

1.1.2.3 Desenho Auxiliado por Computador Nada mais é do que um Editor Gráfico poderoso que armazena todas as informações dos objetos que estão sendo criados. CAD (Computer-Aided Drafting) 1.1.2.4 Projeto e Desenho Auxiliado por Computador Nada mais é do que um CAD que além de manter as informações de todos os objetos, armazena também, as medidas reais de todos os objetos. CADD (Computer-Aided Design and Drafting) 1.1.2.5 Produção Auxiliada por Computador O Computador se encarrega da fabricação da peça que foi projetada no CAD. Há uma máquina escrava ligada ao computador, a qual recebe todas as informações necessárias a fabricação (Por exemplo: fábricas de automóveis). CAM (Computer-Aided Manufacturing) 1.1.2.6 Processamento de Imagens É muito utilizado em Meteorologia e mapeamento feito pelo Exército. 1.1.2.7 Montagem de Cenários (Geração de Efeitos Visuais Especiais)

l Cores; l Transparência (Simulação de Vidro); l Reflexão (Fontes de Luz); l Sombra; l Textura do material; l Remoção de linhas e faces ocultas; l Fractais.

1.1.2.8 Simulação Gráfica (Testes) É muito utilizado para testes, por exemplo, aviação, corrida espacial, fenômenos físicos, circuitos eletrônicos, efeitos visuais e fenômenos de várias espécies. 1.1.2.9 Sistemas Operacionais Gráficos Hoje muitos computadores ("Apple", "WorkStations", PC's, PS/2, dentre outros) utilizam janelas, ícones, caixas de diálogo, janelas de erros para facilitar o uso pelo usuário do Sistema Operacional do equipamento. 1.1.3 Dificuldades 1) Hardware (Equipamento) 2) Software (Programas) 3) Peopleware (Pessoas Treinadas) 1.2 Dispositivos Gráficos Configuração Básica de um Sistema Gráfico Interativo:

l Operador l Dispositivos de Entrada l Computador (processador central) l Monitor l Processador Gráfico l Dispositivos de Saída l Programa Aplicativo l Banco de Dados

7

Processador Gráfico É a parte da arquitetura do hardware responsável pela integração do gerenciamento simultâneo da tela e dos recursos gráficos. Elementos do Sistema Processador Gráfico

l Múltiplos planos de bits de memória, que armazenam a imagem gerada em forma digital, muitas vezes denominadas mapa de bits (bitmaps);

l Circuitos de varredura seqüencial, que traduzem esse mapa digital para sua visualização física na tela; l Circuitos que permitem manusear e modificar esse mapa.

1.2.1 Entrada Os dispositivos de entrada visam estabelecer o meio de comunicação físico que permite ao operador manipular as imagens e interagir com o programa aplicativos.

l Caneta de Luz (Caneta Ótica) l Rato (mouse) l Joystick, trackballs e Thumbweels l Touchpanels e Touchpads l Superfícies Sensíveis (Telas Sensitivas) l Botões (Dial Controlador) l Teclas e Comutadores de Funções l Mesas Digitalizadoras l Scanners e seguidores de Linhas l Atuadores de Voz Humana l Teclado l Digitalizadores de Vídeo

1.2.2 Saída Os dispositivos de saída visam facilitar e melhorar a comunicação humana, auxiliando o homem na distribuição ordenada e eficiente das informações. VÍDEO:

l Dispositivos de Tubo de Raios Catódicos (CRT) l Displays por Tubos de Armazenamento Direto de Imagem l Visores de Refresh l Visores de Vídeo l Visores de Plasma

PAPEL:

l Copiadores de Imagem l Impressoras Eletrográficas l Impressoras Gráficas l Impressoras de Vetor l Gravadores de Microfilme l Traçadores Gráficos l Traçadores Eletrostáticos l Impressoras Matriciais l Impressoras de Jato de Tinta l Impressoras a Laser l Impressoras Térmicas l Registradores l Projetores Eletrônicos

1.2.3 Armazenamento

l Winchester l Disk Drives l Fita Streamer l CD-ROM

8

2. Transformações Bi-dimensionais 2.1 Dispositivos de Visualização 2.1.1 Resolução (Pixel) Resolução: É a quantidade de pontos em que a tela gráfica pode ser dividida. Pixel: (Picture Element), ou seja, o menor ponto gráfico. 2.1.2 Placas Gráficas MDA: Monochrome Display Adapter CGA: Color Graphics Adapter EGA: Enhanced Graphics Adapter VGA: Video Graphics Array Com exceção da MDA, as demais placas gráficas podem funcionar em dois modos básicos: Modo Texto: Utilizado para exibir texto, dividido em linhas e colunas Modo Gráfico: Utilizado para exibir texto e gráfico, dividida em uma malha de pontos (pixels) MDA: Texto 80 x 25 CGA: Texto 40 x 25 16 cores 80 x 25 16 cores Gráfico 320 x 200 4 cores 640 x 200 2 cores EGA: Texto 40 x 25 16 cores 80 x 25 16 cores Gráfico 320 x 200 16 cores 640 x 200 16 cores 640 x 350 16 cores VGA: Texto 40 x 25 16 cores 80 x 25 16 cores Gráfico 320 x 200 256 cores 320 x 200 16 cores 640 x 200 16 cores 640 x 350 16 cores 640 x 480 16 cores 2.1.3 Sistema de Referência do Dispositivo de Visualização

Figura 3: Sistema de referência do dispositivo de visualização (monitor)

9

2.1.4 Pacote Gráfico (Linguagem de Programação C) As principais funções gráficas do pacote do Turbo C++ 1.01 são: Veja exemplos de programas em: http://infovis.ucpel.tche.br/luzzardi Clique em (Publicações … Livros Publicados … TurboC.doc ou TurboC.pdf) Função: initgraph (&placa, &modo, path); Protótipo: void initgraph(int *placa, int *modo, char *path); Utilidade: Inicializa tela gráfica, ou seja, sai o modo texto. Variáveis: placa é o tipo de placa gráfica (CGA, EGA, VGA) ou DETECT para detectar a placa. Função: closegraph (); Protótipo: void closegraph(void); Utilidade: Finaliza a tela gráfica. Função: putpixel (x, y, cor); Protótipo: void putpixel(int x, int y, int cor); Utilidade: Plota um pixel na posição (x, y) com a cor especificada. Função: line (xi, yi, xf, yf); Protótipo: void line (int xi, int yi, int xf, int yf); Utilidade: Plota uma linha entre dois vértices (V1 - xi, yi) e V2 (xf, yf) pontos. Função: rectangle (xi, yi, xf, yf); Protótipo: void rectangle (int xi, int yi, int xf, int yf); Utilidade: Plota um retângulo através da diagonal (xi, yi) e (xf, yf) Função: circle (x, y, raio); Protótipo: void circle (int x, int y, int raio); Utilidade: Plota um círculo com centro (x, y) e raio. Função: arc (x, y, angulo_inicial, angulo_final, raio); Protótipo: void arc (int x, int y, int angulo_inicial, int angulo_final, int raio); Utilidade: Plota um arco aberto. Função: drawpoly (número_de_vértices, lista_de_vértices); Protótipo: void drawpoly (int número_de_vértices, int lista_de_vértices[]); Utilidade: Plota um polígono com n vértices Função: setcolor (cor); Protótipo: void setcolor (int cor); Utilidade: Trocar a cor da frente (foreground), Função: setbkcolor (cor); Protótipo: int setbkcolor (int cor); Utilidade: Trocar a cor de fundo (background). Função: getcolor (); Protótipo: int getcolor (void); Utilidade: Retorna a cor da frente (foreground corrente). Função: getbkcolor (); Protótipo: int getbkcolor (void); Utilidade: Retorna a cor de fundo (background corrente). Função: settextstyle (estilo,direção,tamanho); Protótipo: settextstyle (int estilo, int direção, int tamanho); Utilidade: Mudar o estilo, direção e tamanho do texto. Função: outtextxy (x, y, texto); Protótipo: void outtextxy (int x, int y, char *texto);

10

Utilidade: Imprime texto na tela gráfica na posição (x,y). Função: setfillstyle (estilo, cor); Protótipo: void setfillstyle (int estilo, int cor); Utilidade: Altera o estilo de preenchimento. Função: bar (xi, yi, xf, yf); Protótipo: void bar (int xi, int yi, int xf, int yf); Utilidade: Desenha um retângulo preenchido. Função: fillpoly (número_de_vértices, lista_de_vértices); Protótipo: void fillpoly (int número_de_vértices, int lista_de_vértices[]); Utilidade: Desenha um polígono preenchido. Função: floodfill (x, y, cor_da_borda); Protótipo: void floodfill (int x, int y, int cor_da_borda); Utilidade: Preenche (pinta) uma área fechada. Função: setviewport (xi, yi, xf, yf, recorte); Protótipo: void setviewport (int xi, int yi, int xf, int yf, int recorte); Utilidade: Define uma janela ativa. Função: clearviewport (); Protótipo: void clearviewport (void); Utilidade: Limpa a janela ativa. Função: getimage (xi, yi, xf, yf, ponteiro); Protótipo: void getimage (int xi, int yi, int xf, int yf, void *ponteiro); Utilidade: Salva em memória uma área Função: putimage (xi, yi, ponteiro, modo); Protótipo: void putimage (int xi, int yi, void *ponteiro, int modo); Utilidade: Recupera da memória uma área salva. Função: imagesize (xi, yi, xf, yf); Protótipo: long int imagesize (int xi, int yi, int xf, int yf); Utilidade: Calcula o número de bytes de uma janela. Função: getpixel (x, y); Protótipo: int getpixel (int x, int y); Utilidade: Retorna a cor do pixel na tela. 2.2 Transformações Geométricas 2.2.1 Sistemas de Coordenadas 2.2.1.1 Cartesiano (2D) Sistema representa um ponto P com duas coordenadas (x, y).

Figura 4: Sistema Cartesiano Dois eixos, duas dimensões 2D – (x, y). Três eixos, três dimensões 3D – (x, y, z).

11

Figura 5: Representação do Envelope Observação: (0, 0) ponto de referência do objeto 2.2.2.2 Polar Sistema representa um ponto P pelo seu raio e ângulo.

Figura 6: Sistema representado por raio e ângulo

Figura 7: Fórmulas para cálculo de ângulos e coordenadas

12

Envelope Retângulo ou círculo que engloba todo o objeto. Finalidade: Facilitar o apontamento de objetos complexos Como verificar se o mouse está dentro do envelope ou não: Envelope Retangular:

Figura 8: Coordenadas de um envelope retangular

if (xmouse >= xi && xmouse <= xf && ymouse >= yi && ymouse <= yf) dentro(); else fora(); Envelope Circular:

Figura 9: Envelope Circular

dist = sqrt(pow(xmouse – xc, 2) + pow(ymouse – yc, 2)); // cálculo da distância entre dois pontos

if (dist <= raio) dentro(); else fora(); Descrição de Objetos Retilíneos (2D) Coordenadas Absolutas Objeto descrito em relação a origem.

Figura 10: Coordenada Absolutas

13

Como representar Objetos Os objetos podem ser representados por: vértices e arestas. Vértice: Ponto representado por duas coordenadas V(x, y). Aresta: Linha interligando dois vértices A(v1, v2). Sentido de Representação dos Vértices e Arestas

l Horário ou Anti-horário

Figura 11: Tabela de vértices Como representar esta tabela: struct Tabela { int x; int y; } ver[número_vértices];

Figura 12: Tabela de arestas Como representar esta tabela: struct Tabela { int V1; int V2; } are[número_arestas]; Coordenadas Relativas O ponto P' tem como origem o ponto P.

14

Figura 13: Coordenadas relativas Vantagem: Cálculo mais fácil para movimentar o objeto, pois todos os vértices estão relacionados ao ponto P. Desvantagem: Plotar apenas partes do objeto, pois os vértices são dependentes, ou seja, os vértices tem de ser percorridos sequencialmente. Equação Geral da Reta

Figura 14: Equação geral da reta

Figura 15: Exemplo de equação geral da reta

15

Pontos: P1 (1, 1) e P2 (5, 3) x1 = 1 x2 = 5 y1 = 1 y2 = 3 Aplicando nas equações: A = 3 - 1 = 2 B = -(5 - 1) = -4 C = -(1 . 2 + 1 . -4) = 2 Aplicando na equação geral da reta: 2x - 4y + 2 = 0 dividindo-se por 2 x - 2y + 1 = 0 equação da reta que passa pelos pontos P1(1,1) e P2(5,3)

Figura 16: Exemplo de cálculo Sendo os pontos P3 e P4 sobre a reta P1 e P2. Como no Computador não podemos representar retas infinitas, usa-se a equação paramétrica da reta, para limitar uma reta entre dois pontos. Equação Paramétrica da Reta x = x1 + t . (x2 - x1) y = y1 + t . (y2 - y1) Onde: t encontra-se entre 0 e 1 Exemplo: P1 (1, 1) e P2 (5, 3) t = 0 t = 1 x = 1 + 4t x = 1 x = 5 y = 1 + 2t y = 1 y = 3 Para t = ½ x = 3 e y = 2, ou seja, ponto P3(3,2)

Isolando-se t nas equações anteriores:

16

Podemos verificar se o Ponto P4 (9,5) está dentro ou fora da reta P1 e P2:

Como t é maior que 1, o Ponto P4(9,5) está fora dos limites P1 e P2. 2.2.2 Transformação de Pontos São operações possíveis de realizar e que permitem alterar a posição de pontos de forma que estes sofram as seguintes operações: escala, espelhamento (reflexão), cisalhamento (shear), rotação e translação.

Figura 17: Pontos de uma reta P' = P .t t é a Matriz de Transformação Onde: 2.2.2.1 Escala A idéia da operação de escala é aumentar ou diminuir o tamanho de um objeto (zooming). B = C = 0 Logo:

17

Se A = 1 Se A != 1 e D != 1

2.2.2.2 Reflexão (Espelhamento) A idéia da operação de reflexão é o de inverter os pontos de um objeto em torno do eixo x ou y, de forma que o objeto (ou pontos) sofram um espelhamento. B = C = 0 Se A = -1 e D = 1

Se A = 1 e D = -1

18

Se A = -1 e D = -1

2.2.2.3 Shear (Cisalhamento) A idéia da operação de shear é o “quebrar” os pontos de um objeto em torno do eixo x ou y, de forma que o objeto (ou pontos) sofram um cisalhamento, ou seja, ocorre uma deformação em um eixo em relação ao outro eixo. A = D = 1 e C = 0 P' = P . t

Figura 18: Exemplo de shear

Figura 19: Shear 2.2.2.4 Rotação A idéia da operação de rotação é o “virar” (ou rotacionar) os pontos de um objeto em torno do eixo x ou y. P' = P . t

19

Figura 20: Fórmulas para cálculo da Rotação

Figura 21: Ponto P rotacionado

Figura 22: Fórmulas para cálculo da Rotação

20

2.2.2.5 Translação A idéia da operação de translação é o “deslocar” os pontos de um objeto sobre o eixo x ou y.

Figura 23: Translação de um ponto

M = 0 e L = 2

Exemplo das Transformações Geométricas:

Figura 24: Grade de coordenadas Escala

A = D = 2

Figura 25: Aumento na grade de coordenadas

Reflexão (Espelhamento)

Reflexão em "y"

21

Figura 26: Grade contendo coordenadas negativas

Shear (Cisalhamento)

Cisalhamento em "y" Logo, se B = 1, teremos:

Figura 27: Grade contendo os pontos que sofreram cisalhamento

Rotação

22

Figura 28: Grade contendo os pontos (originais, 90 e 180 graus) que sofreram rotação A - Objeto Original B - Rotação de 90 graus C - Rotação de 180 graus Translação

L = M = 5

Figura 29: Grade contendo os pontos que sofreram uma translação

2.3 Transformações de Coordenadas (Mudança de Eixos)

Figura 30: Objeto que sofrerá transformações geométricas

23

x' = 5 + x y' = 4 + y

Figura 31: Tabelas com as coordenadas do objeto

Figura 32: Mudança de coordenadas

x' = 5 + x y' = 5 - y

Figura 33: Cálculo das coordenadas

2.4 Visualização Bidimensional 2.4.1 Coordenadas de Universo Utilizadas para definir objetos e elementos do mundo real.

24

Figura 34: Coordenadas de Universo

2.4.2 Coordenadas de Dispositivo

Figura 35: Coordenadas de Dispositivo

Resolução: Número de pixels (ponto gráfico) no dispositivo, depende do tipo de placa (CGA, EGA, VGA, outra) (a resolução acima é: 640 x 480 - VGA: Alta Resolução)

2.4.3 Coordenadas de Objeto

Figura 36: Coordenadas de Objeto

2.4.4 Janela de Seleção Janela responsável pela transferência (Mapping) para a ViewPort. Transferência de um ponto da Janela de Seleção (Window) para a Porta de Visão (ViewPort).

25

Figura 37: Coordenadas da Janela de Seleção

Exemplo: Janela de Seleção igual ao Universo

Universo (Janela de Seleção)

Figura 38: Universo (Janela de Seleção)

26

Figura 39: Vieport

Figura 40: Vértices e arestas Programa exemplo (Mapeamento): // mapeamento.c #include <stdio.h> #include <conio.h> #include <graphics.h> #define VER 10 #define ARE 10 struct { int x; int y; } ver[VER] = {{3,2},{3,7},{6,7},{6,6},{4,6},{4,5},{5,5},{5,4},{4,4},{4,2}}; struct { int v1; int v2; } are[ARE] = {{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,0}}; #define wesq 0.0 #define wdir 8.0 #define walto 8.0 #define wbaixo 0.0 #define vesq 0.0 #define vdir 639.0 #define valto 0.0 #define vbaixo 479.0 void main(void) { int placa, modo; float xescala, yescala; int xi, yi, xf, yf; int i; placa = VGA; modo = VGAHI; initgraph(&placa, &modo, ""); xescala = (vdir - vesq) / (wdir - wesq); yescala = (vbaixo - valto) / (walto - wbaixo); for (i = 0;i < ARE;i++) { xi = (int) vesq + (ver[are[i].v1].x - wesq) * xescala; yi = (int) (ver[are[i].v1].y - wbaixo) * yescala; xf = (int) vesq + (ver[are[i].v2].x - wesq) * xescala; yf = (int) (ver[are[i].v2].y - wbaixo) * yescala; line(xi,vbaixo - yi,xf,vbaixo - yf);

27

} getch(); closegraph(); } Programa exemplo (ESCALA): // escala.c #include <stdio.h> #include <conio.h> #include <graphics.h> #define VER 10 #define ARE 10 struct { int x; int y; } ver[VER] = {{3,2},{3,7},{6,7},{6,6},{4,6},{4,5},{5,5},{5,4},{4,4},{4,2}}; struct { int v1; int v2; } are[ARE] = {{0,1},{1,2},{2,3}{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,0}}; #define wesq 0.0 #define wdir 8.0 #define walto 8.0 #define wbaixo 0.0 #define vesq 0.0 #define vdir 639.0 #define valto 0.0 #define vbaixo 479.0 void main(void) { int placa, modo; float xescala, yescala; int xi, yi, xf, yf; int i; float a, d, j; placa = VGA; modo = VGAHI; initgraph(&placa, &modo,""); xescala = (vdir - vesq) / (wdir - wesq); yescala = (vbaixo - valto) / (walto - wbaixo); j = 1.0; do { clearviewport(); a = (float) 1/j; d = (float) 1/j; for (i = 0;i < ARE;i++) { xi = (int) vesq+((ver[are[i].v1].x*a)-wesq)*xescala; yi = (int) valto+((ver[are[i].v1].y*d)-wbaixo)*yescala; xf = (int) vesq+((ver[are[i].v2].x*a)-wesq)*xescala; yf = (int) valto+((ver[are[i].v2].y*d)-wbaixo)*yescala; line(xi,vbaixo - yi,xf,vbaixo - yf); } j += 0.1; } while (j <= 10.0); getch(); closegraph(); } Programa exemplo (SHEAR): // shear.c #include <stdio.h> #include <conio.h> #include <math.h> #include <graphics.h> #define VER 10

28

#define ARE 10 struct { int x; int y; } ver[VER] = {{3,2},{3,7},{6,7},{6,6},{4,6},{4,5},{5,5},{5,4},{4,4},{4,2}}; struct { int v1; int v2; } are[ARE] = {{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,0}}; #define wesq 0.0 #define wdir 8.0 #define walto 8.0 #define wbaixo 0.0 #define vesq 0.0 #define vdir 639.0 #define valto 0.0 #define vbaixo 479.0 void main(void) { int placa, modo; float xescala, yescala; int xi, yi, xf, yf; int i; float b; placa = VGA; modo = VGAHI; initgraph(&placa, &modo, ""); xescala = (vdir - vesq) / (wdir - wesq); yescala = (vbaixo - valto) / (walto - wbaixo); b = 0.0; do { for (i = 0;i < ARE;i++) { xi = (int) vesq + (ver[are[i].v1].x - wesq) * xescala; yi = (int) valto + (ver[are[i].v1].y - wbaixo)* yescala; xf = (int) vesq + (ver[are[i].v2].x - wesq) * xescala; yf = (int) valto + (ver[are[i].v2].y - wbaixo) * yescala; xi = xi + yi * b; xf = xf + yf * b; line(xi, vbaixo – yi, xf, vbaixo - yf); } clearviewport(); b += 0.05; } while (b <= 5.0); closegraph(); } Programa exemplo (ROTAÇÃO): // rotacao.c #include <stdio.h> #include <conio.h> #include <math.h> #include <graphics.h> #define PI 3.1415926535897932385 #define VER 10 #define ARE 10 struct { int x; int y; } ver[VER] = {{0,0},{0,5},{3,5},{3,4},{1,4},{1,3},{2,3},{2,2},{1,2},{1,0}}; struct { int v1; int v2; } are[ARE] = {{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,0}}; #define wesq -8.0 #define wdir 8.0 #define walto 8.0

29

#define wbaixo -8.0 #define vesq 0.0 #define vdir 639.0 #define valto 0.0 #define vbaixo 479.0 void main(void) { int placa, modo; float xescala, yescala; int xi, yi, xf, yf; float COS, SEN, angulo, rad; int i; placa = VGA; modo = VGAHI; initgraph(&placa, &modo, ""); xescala = (vdir - vesq) / (wdir - wesq); yescala = (vbaixo - valto) / (walto - wbaixo); angulo = 0.0; do { rad = angulo * PI / 180.0; COS = cos(rad); SEN = sin(rad); for (i = 0;i < ARE;i++) { xi = (int) vesq + ((ver[are[i].v1].x * COS - ver[are[i].v1].y * SEN) - wesq) * xescala; yi = (int) valto + ((ver[are[i].v1].x * SEN + ver[are[i].v1].y * COS) - wbaixo) * yescala; xf = (int) vesq + ((ver[are[i].v2].x * COS - ver[are[i].v2].y * SEN) - wesq) * xescala; yf = (int) valto + ((ver[are[i].v2].x * SEN + ver[are[i].v2].y * COS) - wbaixo) * yescala; line(xi, vbaixo – yi, xf, vbaixo - yf); } angulo += 15.0; if (angulo >= 360.0) angulo = 0.0; clearviewport(); } while (!kbhit()); closegraph(); } Programa exemplo (TRANSLAÇÃO): // translacao.c #include <stdio.h> #include <conio.h> #include <math.h> #include <graphics.h> #define VER 10 #define ARE 10 struct { int x; int y; } ver[VER] = {{0,0},{0,5},{3,5},{3,4},{1,4},{1,3},{2,3},{2,2},{1,2},{1,0}}; struct { int v1; int v2; } are[ARE] = {{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,0}}; #define wesq 0.0 #define wdir 16.0 #define walto 16.0 #define wbaixo 0.0 #define vesq 0.0 #define vdir 639.0 #define valto 0.0 #define vbaixo 479.0 void main(void) { int placa, modo; float xescala, yescala; int xi, yi, xf, yf; int i, l, m;

30

placa = VGA; modo = VGAHI; initgraph(&placa, &modo, ""); xescala = (vdir - vesq) / (wdir - wesq); yescala = (vbaixo - valto) / (walto - wbaixo); l = 0; m = 0; do { for (i = 0;i < ARE;i++) { xi = (int) vesq + (ver[are[i].v1].x - wesq) * xescala; yi = (int) valto + (ver[are[i].v1].y - wbaixo) * yescala; xf = (int) vesq + (ver[are[i].v2].x - wesq) * xescala; yf = (int) valto + (ver[are[i].v2].y - wbaixo) * yescala; xi = xi + l; yi = yi + m; xf = xf + l; yf = yf + m; line(xi, vbaixo – yi, xf, vbaixo - yf); } clearviewport(); l += 5; m += 1; } while (l <= 500); closegraph(); } Figuras Geométricas Círculo X' = Xc + R.Cos A Y' = Yc + R.Sen A Sendo: ângulo varia de 0 à 360 Elipse X' = Xc + Rx.Cos A Y' = Yc + Ry.Sen A Fórmula para conversão de graus para radianos:

Programa exemplo (CÍRCULO): // circulo.c #include <stdio.h> #include <conio.h> #include <math.h> #include <graphics.h> #define PI 3.1415 void main(void) { int placa, modo; int xi, yi, xf, yf; int xc, yc, raio; float angulo, rad; int ax, ay; float aspecto; placa = VGA; modo = VGAHI;

31

initgraph(&placa, &modo, ""); xc = 319; yc = 239; raio = 100; angulo = 0.0; rad = angulo * PI / 180; getaspectratio(&ax, &ay); aspecto = (float) ax / ay; xi = xc + (int) raio * cos(rad); yi = yc + (int) raio * sin(rad) * aspecto; do { angulo = angulo + 5; rad = angulo * PI / 180; xf = xc + (int) raio * cos(rad); yf = yc + (int) raio * sin(rad) * aspecto; line(xi,yi,xf,yf); xi = xf; yi = yf; } while (angulo < 360); getch(); closegraph(); } Programa exemplo (ELIPSE): // elipse.c #include <stdio.h> #include <conio.h> #include <math.h> #include <graphics.h> #define PI 3.1415 void main(void) { int placa, modo; int xi, yi, xf, yf; int xc, yc, raio_x, raio_y; float angulo, rad; int ax, ay; float aspecto; placa = VGA; modo = VGAHI; initgraph(&placa, &modo, ""); xc = 319; yc = 239; raio_x = 100; raio_y = 20; angulo = 0.0; rad = angulo * PI / 180; getaspectratio(&ax, &ay); aspecto = (float) ax / ay; xi = xc + (int) raio_x * cos(rad); yi = yc + (int) raio_y * sin(rad) * aspecto; do { angulo = angulo + 5; rad = angulo * PI / 180; xf = xc + (int) raio_x * cos(rad); yf = yc + (int) raio_y * sin(rad) * aspecto; line(xi, yi, xf, yf); xi = xf; yi = yf; } while (angulo < 360); getch(); closegraph(); } Curvas Aqui veremos algumas formas de traçar curvas.

32

Figura 41: Curva que passa por três pontos conhecidos

Figura 42: Pontos fora da curva definem a curva

Pontos fora da curva definem a curva n: Número de Pontos n-1: Grau do Polinómio Equação da Curva passando por 3 (três) pontos

n = 3, logo, o grau do polinómio é 2

Equação da Curva passando por 4 (quatro) pontos

n = 4, logo, o grau do polinómio é 3 Exemplo: Aplica-se os pontos (0,0), (2,5) e (8,6) e tem-se um sistema de equações; resolvendo o sistema obtém-se a equação da curva, ou seja, y em função de x. 3 pontos, polinómio do 2 grau

Figura 43: Representação de uma curva que passa por três pontos

Ponto (0,0):

33

x = 0 y = 0 Logo:

Ponto (2,5): x = 2 y = 5 5 = K3 . 4 + K2 . 2 + 0

Ponto (8, 6): x = 8 y = 6 6 = K3 . 64 + K2 . 8

Substituindo-se K2, temos:

Figura 44: Equação da curva que passa por quatro pontos

Equação da Curva que passa pelos pontos (0,0), (2,5) e (8,6) Observação: K1 é igual à 0 (ZERO), pois a curva passa pela origem 4 pontos, polinómio do 3 grau

34

Figura 45: Exemplo de pontos para geração de curva que passa por quatro pontos

Entre os pontos (2,5) e (8,6) a curva pode ter uma inclinação muito grande, por causa disto deve-se colocar mais um ponto (5,6.2) para atenuar a curva, ou seja, a equação possui quatro pontos e grau 3. Um outro problema é a maneira que a curva termina no ponto (8,6), imagine se quizermos uma reta ligada ao ponto (8,6) ou outra curva. Isto é resolvido se for conhecido a inclinação das linhas nos pontos críticos. Ou seja, para dois pontos um polinómio do 3 grau (um grau a mais), se conhecermos um ponto intermediário (3 pontos) teremos um polinómio do 4 grau.

Se Y1 = Y2 -> Inclinação Zero (Linha Horizontal) X2 = X1 -> Inclinação Infinita (Linha Vertical)

Figura 46: Uso da inclinação das linhas nos pontos críticos

Inclinação = Tan ALFA = 3 ALFA = ArcTan 3

35

Para calcular os coeficientes K1 à K5 deve-se levar em consideração as inclinações. Programa exemplo (CURVAS): // curvas.c #include <stdio.h> #include <conio.h> #include <math.h> #include <ctype.h> #include <string.h> #include <process.h> #include <stdlib.h> #include <graphics.h> #define UP 72 #define DOWN 80 #define LEFT 75 #define RIGHT 77 #define ENTER 13 #define ESC 27 #define F1 59 #define F2 60 #define N 4 struct { int x; int y; } p[N]; void cursor(int x, int y, int liga); void posicao(int x, int y, int p); void imprime_posicao(void); void apagar(void); void marca_pontos(int n); int XMAX,YMAX; int cor_texto, cor_numero, cor_ponto, cor_cursor; void main(void) { int placa, modo; char PLACA, MODO; int px, py, n; float x1, x2, x3; int i, j, k; float a[N][N], m[N][N], x[N], y[N]; int xt, yt, passo; char tecla, ch; int xinic, xfim; clrscr(); printf("Placa: [C]ga, [E]ga ou [V]ga ?"); do { PLACA = toupper(getch()); } while (!strchr("CEV",PLACA)); switch (PLACA) { case 'C': placa = CGA; break; case 'E': placa = EGA; break; case 'V': placa = VGA; break; } clrscr(); printf("Modo: [A]lta ou [M]edia ?"); do { MODO = toupper(getch()); } while (!strchr("AM",MODO)); if (MODO == 'M')

36

switch (placa) { case CGA: modo = CGAC0; // 4 cores XMAX = 319; YMAX = 199; cor_texto = 1; cor_numero = 2; cor_ponto = 3; cor_cursor = 1; break; case EGA: modo = EGALO; // 16 cores XMAX = 639; YMAX = 199; cor_texto = 1; cor_numero = 2; cor_ponto = 3; cor_cursor = 4; break; case VGA: modo = VGALO; // 16 cores XMAX = 639; YMAX = 199; cor_texto = 1; cor_numero = 2; cor_ponto = 3; cor_cursor = 4; break; } else switch (placa) { case CGA: modo = CGAHI; // 2 cores XMAX = 639; YMAX = 199; cor_texto = 1; cor_numero = 1; cor_ponto = 1; cor_cursor = 1; break; case EGA: modo = EGAHI; // 16 cores XMAX = 639; YMAX = 349; cor_texto = 1; cor_numero = 2; cor_ponto = 3; cor_cursor = 4; break; case VGA: modo = VGAHI; // 16 cores XMAX = 639; YMAX = 479; cor_texto = 1; cor_numero = 2; cor_ponto = 3; cor_cursor = 4; break; } initgraph(&placa, &modo, ""); setgraphmode(modo); n = N - 1; passo = 10; xt = 10; yt = 10; do { i = 0; imprime_posicao(); do { posicao(xt, yt, passo); cursor(xt, yt, cor_cursor); tecla = getch(); if (tecla == ESC) { closegraph(); exit(0); } if (tecla == ENTER) { p[i].x = xt; p[i].y = yt; marca_pontos(i);

37

i++; } if (tecla == 0) { tecla = getch(); cursor(xt, yt, 0); marca_pontos(i-1); switch (tecla) { case UP: yt -= passo; if (yt < 0) yt = YMAX; break; case DOWN: yt += passo; if (yt > YMAX) yt = 0; break; case LEFT: xt -= passo; if (xt < 0) xt = XMAX; break; case RIGHT: xt += passo; if (xt > XMAX) xt = 0; break; case F1: passo += 1; if (passo > 999) passo = 999; break; case F2: passo -= 1; if (passo < 1) passo = 1; break; } } } while (i <= n); xinic = XMAX; xfim = 0; for (i = 0; i <= n; i++) { a[i][0] = (float) pow(p[i].x,3); a[i][1] = (float) pow(p[i].x,2); a[i][2] = (float) p[i].x; a[i][3] = 1; y[i] = (float) p[i].y; if (p[i].x < xinic) xinic = p[i].x; if (p[i].x > xfim) xfim = p[i].x; } for (k = 0; k <= n-1; k++) for (i = k+1; i <= n; i++) { m[i][k] = (float) -(a[i][k] / a[k][k]); for (j = k+1;j <= n;j++) a[i][j] = (float) a[i][j] + m[i][k] * a[k][j]; y[i] = (float) y[i] + m[i][k] * y[k]; } x[n] = (float) y[n] / a[n][n]; for (k = n-1; k >= 0; k--) { x[k] = y[k]; for (i = k+1; i <= n; i++) x[k] = (float) x[k] - a[k][i] * x[i]; x[k] = (float) x[k] / a[k][k]; } px = xinic; do { x3 = (float) x[0] * pow(px,3); x2 = (float) x[1] * pow(px,2); x1 = (float) x[2] * px; py = abs((int) x3 + x2 + x1 + x[n]); if (py >= 0 && py <= YMAX) putpixel(px, py, 3); px += 1; } while (px < xfim); outtextxy(200, YMAX-14, "Limpar [S]im ou [N]ao ?"); do {

38

ch = toupper(getch()); } while (!strchr("SN",ch)); setfillstyle(SOLID_FILL,0); bar(200, YMAX-14, XMAX, YMAX); if (ch == 'S') { setviewport(0, 0, XMAX, YMAX,1); clearviewport(); } } while (1); } // -------------------------- cursor void cursor(int x, int y, int liga) { setcolor(liga); line(x-5, y, x+5, y); line(x, y-5, x, y+5); } // -------------------------- posicao void posicao(int x, int y, int p) { char sx[5], sy[5], sp[5]; itoa(x, sx, 10); itoa(y, sy, 10); itoa(p, sp, 10); apagar(); setcolor(cor_numero); outtextxy(20, YMAX-14, sx); outtextxy(70, YMAX-14, sy); outtextxy(140, YMAX-14, sp); } // -------------------------- imprime_posicao void imprime_posicao(void) { setcolor(cor_texto); settextstyle(SMALL_FONT, HORIZ_DIR, 4); outtextxy(0, YMAX-14, "x: "); outtextxy(50, YMAX-14, "y: "); outtextxy(100, YMAX-14, "Passo: "); } // -------------------------- apagar void apagar(void) { setfillstyle(SOLID_FILL, 0); bar(20, YMAX-14, 40, YMAX); bar(70, YMAX-14, 90, YMAX); bar(140, YMAX-14, 160, YMAX); } // -------------------------- marca_pontos void marca_pontos(int n) { int i; setcolor(cor_ponto); for (i = 0; i <= n; i++) { line(p[i].x-5, p[i].y-5, p[i].x+5, p[i].y+5); line(p[i].x+5, p[i].y-5, p[i].x-5, p[i].y+5); } }

39

2.4.5 Recorte Transferência da janela de seleção ("Window") para a janela de exibição ("ViewPort").

Figura 47: Exemplo de mapeamento com recorte

Casos possíveis:

Figura 48: Exemplo de casos possíveis que podem acorrer para recorte

a) Os dois pontos extremos estão dentro da janela de seleção. b) Os dois pontos extremos estão fora da janela de seleção. c) Um ponto dentro e outro fora. O algorítmo deve verificar: 1) Se a linha é completamente visível. 2) Se a linha é parcialmente visível. 3) Se a linha é completamente invisível. 1) Incluir a linha. 2) Determinar a intersecção da linha com a janela.

3) Ignorar a linha.

40

Figura 49: Quadrantes possíveis

Figura 50: Codificação dos Quadrantes

se (X1code == 0 && Y1code == 0 && X2code == 0 && Y2code == 0) vértices_visíveis(); senão se (X1code * X2code == 1 || Y1code * Y2code == 1) vértices_invisíveis(); senão vértices_parcialmente_visíveis(); Programa exemplo (RECORTE): // Programa: recorte.c // Programador: Paulo Roberto Gomes Luzzardi // Disciplina: Computação Gráfica // Data: 05/05/2007 // Função: Mapeamento e recorte na janela de seleção #include <stdio.h> #include <conio.h> #include <math.h> #include <stdlib.h> #include <string.h> #include <graphics.h> #define VER 23 #define ARE 23 #define TRUE !0 #define FALSE 0 #define ENTER 13 #define ESC 27 #define UP 72 #define DOWN 80 #define LEFT 75 #define RIGHT 77

41

#define F1 59 #define F2 60 #define CTRLUP 141 #define CTRLDOWN 145 #define CTRLLEFT 115 #define CTRLRIGHT 116 struct { float x; float y; } ver[VER] = { {2.0, 1.0},{12.0,1.0},{12.0,4.0},{2.0,4.0},{6.0,1.0},{8.0,1.0}, {8.0, 3.0},{6.0,3.0},{9.0,2.0},{11.0,2.0},{11.0,3.0},{9.0,3.0}, {3.0, 2.0},{5.0,2.0},{5.0,3.0},{3.0,3.0},{1.0,4.0},{ 13.0,4.0}, {7.0,7.0},{9.0,6.0},{10.0,5.5},{10.0,7.0},{9.0,7.0}}; struct { int v1; int v2; } are[ARE] = { {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{8,9},{9,10}, {10,11},{11,8},{12,13},{13,14},{14,15},{15,12},{16,17}, {17,18},{18,16},{19,20},{20,21},{21,22},{22,19}}; float wesq = 0.0, wdir = 14.0, walto = 8.0, wbaixo = 0.0; float js_esq = 3.5, js_dir = 7.0, js_alto = 3.5, js_baixo = 1.5; float vesq = 1.0, vdir = 318.0, valto = 1.0, vbaixo = 478.0; float uesq = 320.0, udir = 639.0, ualto = 99.0, ubaixo = 479; float xlim, ylim, xdesloc, ydesloc, xc, yc; int tipo; // ------------------------------------- codigo_corte void codigo_corte(float xw, float yw, int *xcode, int *ycode) { if (xw <= js_esq) *xcode = -1; else if (xw > js_esq && xw < js_dir) *xcode = 0; else if (xw >= js_dir) *xcode = 1; if (yw <= js_baixo) *ycode = -1; else if (yw > js_baixo && yw < js_alto) *ycode = 0; else if (yw >= js_alto) *ycode = 1; } // ------------------------------------------- recorte_linha void recorte_linha(float *xi, float *yi, float *xf, float *yf, int *vis) {

42

float razao; int x1code,y1code,x2code,y2code; float xni,yni,xnf,ynf; float xtemp,ytemp; codigo_corte(*xi,*yi,&x1code,&y1code); codigo_corte(*xf,*yf,&x2code,&y2code); if (x1code * x2code == 1 || y1code * y2code == 1) *vis = 0; else { *vis = 1; xni = *xi - xdesloc; yni = *yi - ydesloc; xnf = *xf - xdesloc; ynf = *yf - ydesloc; if (x1code != 0) { xtemp = xlim * x1code; razao = (xtemp - xni) / (xnf - xni); yni = yni + (ynf - yni) * razao; xni = xtemp; codigo_corte(xni+xdesloc,yni+ydesloc,&x1code,&y1code); } if (y1code != 0) { ytemp = ylim * y1code; razao = (ytemp - yni) / (ynf - yni); xni = xni + (xnf - xni) * razao; yni = ytemp; } if (x2code != 0) { xtemp = xlim * x2code; razao = (xtemp - xni) / (xnf - xni); ynf = yni + (ynf - yni) * razao; xnf = xtemp; codigo_corte(xnf+xdesloc,ynf+ydesloc,&x2code,&y2code); } if (y2code != 0) { ytemp = ylim * y2code; razao = (ytemp - yni) / (ynf - yni); xnf = xni + (xnf - xni) * razao; ynf = ytemp; } *xi = xni + xdesloc; *yi = yni + ydesloc; *xf = xnf + xdesloc; *yf = ynf + ydesloc; } } // --------------------------------------- main void main(void) { int placa, modo; float xescala, yescala; int i; int tecla; int xvi, yvi, xvf, yvf; float xwi, ywi, xwf, ywf;

43

int vis; float passo; char *sxi, *syi, *sxf, *syf, spasso[4], *stipo, *temp = "x"; int dec, sign; int xit, yit, xft, yft, passot, tipot; placa = VGA; modo = VGAHI; initgraph(&placa,&modo,"c:\\tcpp\\bgi"); // -------------------------------------------- Viewport do { xvi = (int) vesq - 1.0; yvi = (int) valto - 1.0; xvf = (int) vdir + 1.0; yvf = (int) vbaixo + 1.0; rectangle(xvi,yvi,xvf,yvf); // ---------------------------------- Mapeamento do Universo setwritemode(COPY_PUT); xvi = (int) uesq; yvi = (int) ualto; xvf = (int) udir; yvf = (int) ubaixo; rectangle(xvi-1,yvi-2,xvf-2,yvf); xescala = fabs((udir - uesq) / (wdir - wesq)); yescala = fabs((ubaixo - ualto) / (walto - wbaixo)); setcolor(LIGHTBLUE); for (i = 0;i < ARE;i++) { xvi = (int) uesq + (ver[are[i].v1].x - wesq) * xescala; yvi = (int) ubaixo-(ver[are[i].v1].y - wbaixo) * yescala; xvf = (int) uesq+(ver[are[i].v2].x - wesq) * xescala; yvf = (int) ubaixo-(ver[are[i].v2].y - wbaixo) * yescala; line(xvi,yvi,xvf,yvf); } // ------------------------------------ Janela de Selecao setcolor(WHITE); xescala = fabs((udir - uesq) / (wdir - wesq)); yescala = fabs((ubaixo - ualto) / (walto - wbaixo)); passo = 0.1; tipo = 1; settextstyle(SMALL_FONT, HORIZ_DIR,4); outtextxy(340,0,"xi: "); outtextxy(340,10,"yi: "); outtextxy(340,20,"xf: "); outtextxy(340,30,"yf: "); outtextxy(340,40,"Passo: "); outtextxy(340,50,"Tipo: "); outtextxy(450,10,"[ENTER] - Visualiza"); outtextxy(450,40,"[+] Aumenta Passo"); outtextxy(450,50,"[-] Diminui Passo"); outtextxy(340,70,"F1 - Aumenta Janela"); outtextxy(340,80,"F2 - Diminui Janela"); xit = (int) uesq + (js_esq - wesq) * xescala; yit = (int) vbaixo - (js_baixo - wbaixo) * yescala; xft = (int) uesq + (js_dir - wesq) * xescala; yft = (int) vbaixo - (js_alto - wbaixo) * yescala; passot = passo; tipot = tipo; setcolor(YELLOW); setfillstyle(SOLID_FILL,0); sxi = ecvt(xvi,3,&dec,&sign); outtextxy(360,0,sxi); syi = ecvt(yvi,3,&dec,&sign);

44

outtextxy(360,10,syi); sxf = ecvt(xvf,3,&dec,&sign); outtextxy(360,20,sxf); syf = ecvt(yvf,3,&dec,&sign); outtextxy(360,30,syf); temp = ecvt(passo,1,&dec,&sign); strcpy(spasso,"0."); strcat(spasso,temp); outtextxy(380,40,spasso); stipo = ecvt(tipo,1,&dec,&sign); outtextxy(370,50,stipo); do { xvi = (int) uesq + (js_esq - wesq) * xescala; yvi = (int) vbaixo - (js_baixo - wbaixo) * yescala; xvf = (int) uesq + (js_dir - wesq) * xescala; yvf = (int) vbaixo - (js_alto - wbaixo) * yescala; setcolor(YELLOW); if (xit != xvi) { bar(360,0,400,9); sxi = ecvt(xvi,3,&dec,&sign); outtextxy(360,0,sxi); xit = xvi; } if (yit != yvi) { bar(360,10,400,19); syi = ecvt(yvi,3,&dec,&sign); outtextxy(360,10,syi); yit = yvi; } if (xft != xvf) { bar(360,20,400,29); sxf = ecvt(xvf,3,&dec,&sign); outtextxy(360,20,sxf); xft = xvf; } if (yft != yvf) { bar(360,30,400,39); syf = ecvt(yvf,3,&dec,&sign); outtextxy(360,30,syf); yft = yvf; } if (passot != passo) { bar(380,40,420,49); temp = ecvt(passo,1,&dec,&sign); strcpy(spasso,"0."); strcat(spasso,temp); outtextxy(380,40,spasso); passot = passo; } if (tipot != tipo) { bar(370,50,420,59); stipo = ecvt(tipo,1,&dec,&sign); outtextxy(370,50,stipo); tipot = tipo; } setwritemode(XOR_PUT); setlinestyle(CENTER_LINE,0,NORM_WIDTH);

45

setcolor(LIGHTRED); rectangle(xvi,yvi,xvf,yvf); tecla = getch(); rectangle(xvi,yvi,xvf,yvf); setcolor(WHITE); setwritemode(COPY_PUT); switch (tecla) { case '+': passo += 0.1; if (passo > 0.9) passo = 0.9; break; case '-': passo -= 0.1; if (passo < 0.1) passo = 0.1; break; } if (tecla == 0) { tecla = getch(); switch (tecla) { case CTRLUP: if (tipo == 1) js_alto += passo; else js_alto -= passo; break; case CTRLDOWN: if (tipo == 1) js_baixo -= passo; else js_baixo += passo; break; case CTRLLEFT: if (tipo == 1) js_esq -= passo; else js_esq += passo; break; case CTRLRIGHT: if (tipo == 1) js_dir += passo; else js_dir -= passo; break; case F1: tipo = 1; // aumenta break; case F2: tipo = 2; // diminui break; case UP: if (js_alto + passo < walto) { js_alto += passo; js_baixo += passo; } break; case DOWN: if (js_baixo + passo - 0.1> wbaixo) { js_alto -= passo; js_baixo -= passo; } break; case LEFT: if (js_esq + passo - 0.2 > wesq) { js_esq -= passo; js_dir -= passo; }

46

break; case RIGHT: if (js_dir + passo < wdir) { js_esq += passo; js_dir += passo; } break; } } } while (tecla != ENTER && tecla != ESC && tecla != UP && tecla != DOWN && tecla != LEFT && tecla != RIGHT); // ------------- Mapeamento do conteudo da Janela de Selecao if (tecla != ESC) { setviewport(vesq,valto,vdir,vbaixo,TRUE); clearviewport(); setviewport(0,0,639,479,TRUE); setlinestyle(SOLID_LINE,0,NORM_WIDTH); setwritemode(COPY_PUT); xescala = fabs((vdir - vesq) / (js_dir - js_esq)); yescala = fabs((vbaixo - valto) / (js_baixo - js_alto)); xdesloc = (js_dir + js_esq) / 2.0; ydesloc = (js_alto + js_baixo) / 2.0; xlim = js_dir - xdesloc; ylim = js_alto - ydesloc; setcolor(LIGHTBLUE); for (i = 0;i < ARE;i++) { xwi = ver[are[i].v1].x; ywi = ver[are[i].v1].y; xwf = ver[are[i].v2].x; ywf = ver[are[i].v2].y; recorte_linha(&xwi,&ywi,&xwf,&ywf,&vis); if (vis) { xvi = (int) vesq + (xwi - js_esq) * xescala; yvi = (int) vbaixo - (ywi - js_baixo) * yescala; xvf = (int) vesq + (xwf - js_esq) * xescala; yvf = (int) vbaixo - (ywf - js_baixo) * yescala; line(xvi,yvi,xvf,yvf); } } setcolor(WHITE); } } while (tecla != ESC); closegraph(); }

47

2.5 Estrutura de Dados para Representação de

Primitivas Geométricas

Figura 51: Objetos que serão visualizados

Lista de Vértices

Figura 52: Lista de vértices

Lista de Arestas

Figura 53: Lista de arestas

Lista de Objetos

48

Figura 54: Lista de objetos

3. Modelagem Bi-dimensional (Operações a nível de usuário) 3.1 Marcar Elemento (Apontamento) Posição do Cursor: (Cx, Cy) Problema: Cursor "dentro" ou "fora" do objeto?

Figura 55: Representação do cursor dentro ou fora de um objeto

Distância de um Ponto a Reta:

Figura 56: Representação de um ponto à uma reta

Observação: Verificar primeiro o "envelope" (Cursor: dentro ou fora) Equação da Reta:

Distância:

49

A = Y2 - Y1 B = -(X2 - X1) = X1 - X2 C = -(X1.A + Y1.B)

Exemplo: X1 = 1 X2 = 5 X = 3 Y1 = 1 Y2 = 3 Y = 1 ..... d = + X1 = 1 X2 = 5 X = 1 Y1 = 1 Y2 = 3 Y = 3 ..... d = - Conclusão: Programa exemplo (CURSOR): // Programa: cursor.c // Disciplina: Computação Gráfica // Programador: Paulo Roberto Gomes Luzzardi // Data: 05/05/2007 // Função do programa: Verifica se o cursor está DENTRO ou FORA do objeto apontado #include <stdio.h> #include <conio.h> #include <math.h> #include <ctype.h> #include <string.h> #include <process.h> #include <stdlib.h> #include <graphics.h> #define UP 72 #define DOWN 80 #define LEFT 75 #define RIGHT 77 #define ENTER 13 #define ESC 27 #define F1 59

50

#define F2 60 #define TRUE !0 #define FALSE 0 struct VERTICE { float x; float y; } *ver; struct ARESTA { int v1; int v2; } *are; struct OBJETO { int ver_inic, ver_fim; int are_inic, are_fim; float env_xi, env_yi, env_xf, env_yf; } *obj; int VER, ARE, OBJ; float wesq, wdir, walto, wbaixo; float xlim, ylim, xdesloc, ydesloc, xc, yc; int tipo; int XMAX, YMAX; int cor_texto, cor_numero, cor_cursor, cor_objeto, cor_apontado; float vesq, vdir, valto, vbaixo; // ------------------------------------------------- cursor void cursor(int x, int y) { setcolor(cor_cursor); setwritemode(XOR_PUT); line(x-5, y, x+5, y); line(x, y-5, x, y+5); setwritemode(COPY_PUT); } // ------------------------------------------ apagar void apagar(void) { setfillstyle(SOLID_FILL,0); bar(30, YMAX-14, 45, YMAX - 1); bar(70, YMAX-14, 90, YMAX - 1); bar(140, YMAX-14, 160, YMAX - 1); } // ---------------------------------------------------- posicao void posicao(int x, int y, int p) { char sx[5], sy[5], sp[5]; itoa(x, sx, 10); itoa(y, sy, 10); itoa(p, sp, 10);

51

apagar(); setcolor(cor_numero); outtextxy(30, YMAX-14, sx); outtextxy(70, YMAX-14, sy); outtextxy(140, YMAX-14, sp); } // ---------------------------------------- imprime_posicao void imprime_posicao(void) { setcolor(cor_texto); settextstyle(SMALL_FONT, HORIZ_DIR, 4); outtextxy(10, YMAX-14, "x: "); outtextxy(50, YMAX-14, "y: "); outtextxy(100, YMAX-14, "Passo: "); outtextxy(200, YMAX-14, "ESC - Sair"); } // ---------------------------------------------------- carrega void carrega() { FILE *fp1,*fp2,*fp3; char arquivo[20], vertice[40], aresta[40], objeto[40]; int i; do { clrscr(); printf("Arquivo: "); scanf("%s", arquivo); strcpy(vertice, arquivo); strcat(vertice, ".ver"); printf("Arquivo Vertices: %s\n", vertice); fp1 = fopen(vertice, "rb"); if (fp1 == NULL) { printf("ERRO: Arquivo [%s] Inexistente\n", vertice); getch(); } else { fscanf(fp1,"%d",&VER); printf("Numero de Vertices: %d\n", VER); ver=(struct VERTICE *) malloc(VER*sizeof(struct VERTICE)); fscanf(fp1,"%f %f %f %f",&wesq,&wdir,&walto,&wbaixo); printf("wesq = %.1f\n", wesq); printf("wdir = %.1f\n", wdir); printf("walto = %.1f\n", walto); printf("wbaixo = %.1f\n", wbaixo); if (fp1 == NULL) { printf("ERRO: Falta de Memoria\n"); getch(); exit(0); } else {

52

i = 0; do { fscanf(fp1,"%f %f",&ver[i].x,&ver[i].y); printf("[%d] x: %.1f - y: %.1f\n", i, ver[i].x, ver[i].y); i++; } while (i < VER); fclose(fp1); strcpy(aresta,arquivo); strcat(aresta,".are"); printf("Arquivo Arestas: %s\n", aresta); fp2 = fopen(aresta,"rb"); if (fp2 == NULL) { printf("ERRO: Arquivo [%s] Inexistente\n",aresta); getch(); } else { fscanf(fp2,"%d",&ARE); printf("Numero de Arestas: %d\n", ARE); are=(struct ARESTA *) malloc(ARE*sizeof(struct ARESTA)); if (are == NULL) { printf("ERRO: Falta de MemÛria\n"); getch(); exit(0); } else { i = 0; do { fscanf(fp2,"%d %d",&are[i].v1,&are[i].v2); printf("[%d] v1: %d - v2: %d\n", i, are[i].v1, are[i].v2); i++; } while (i < ARE); fclose(fp2); strcpy(objeto,arquivo); strcat(objeto,".obt"); printf("Arquivo Objetos: %s\n", objeto); fp3 = fopen(objeto,"rb"); if (fp3 == NULL) { printf("ERRO: Arquivo [%s] Inexistente\n",objeto); getch(); } else { fscanf(fp3,"%d",&OBJ); printf("Numero de Objetos: %d\n", OBJ); obj = (struct OBJETO *) malloc(OBJ * sizeof(struct OBJETO)); if (obj == NULL) { printf("ERRO: Falta de MemÛria\n"); getch(); exit(0); } else {

53

i = 0; do { fscanf(fp3,"%d %d %d %d %f %f %f %f", &obj[i].ver_inic,&obj[i].ver_fim, &obj[i].are_inic,&obj[i].are_fim, &obj[i].env_xi,&obj[i].env_yi, &obj[i].env_xf,&obj[i].env_yf); printf("Vertice inicial = %d\n", obj[i].ver_inic); printf("Vertice final = %d\n", obj[i].ver_fim); printf("Aresta inicial = %d\n", obj[i].are_inic); printf("Aresta final = %d\n", obj[i].are_fim); printf("Envelope (xi): %1.f\n",obj[i].env_xi); printf("Envelope (yi): %1.f\n",obj[i].env_yi); printf("Envelope (xf): %1.f\n",obj[i].env_xf); printf("Envelope (xf): %1.f\n",obj[i].env_xf); i++; } while (i < OBJ); fclose(fp3); } } } } } } } while (fp1 == NULL && fp2 == NULL); delay(500); } // --------------------------------------------------- testa_envelope int testa_envelope(int x, int y, int n) { float xescala,yescala; int xi,yi,xf,yf; xescala = fabs((vdir - vesq) / (wdir - wesq)); yescala = fabs((vbaixo - valto) / (walto - wbaixo)); xi = (int) vesq + (obj[n].env_xi - wesq) * xescala; yf = (int) vbaixo - (obj[n].env_yi - wbaixo) * yescala; xf = (int) vesq + (obj[n].env_xf - wesq) * xescala; yi = (int) vbaixo - (obj[n].env_yf - wbaixo) * yescala; if (x >= xi && x <= xf) if (y >= yi && y <= yf) return(TRUE); return(FALSE); } // ----------------------------------------- main void main(void) { int placa = VGA, modo = VGAHI; int i, j; int X1, Y1, X2, Y2; float A, B, C, d; int xt, yt, passo; char tecla; int xvi, yvi, xvf, yvf;

54

float xescala, yescala; int ok, visivel; clrscr(); XMAX = 639; YMAX = 479; cor_texto = WHITE; cor_numero = RED; cor_cursor = RED; cor_objeto = GREEN; cor_apontado = CYAN; vesq = 0.0; valto = 0.0; vdir = 639.0; vbaixo = 479.0; carrega(); initgraph(&placa, &modo,"c:\\tcpp\\bgi"); setgraphmode(modo); // -------------------------------------------- Viewport xvi = (int) vesq; yvi = (int) valto; xvf = (int) vdir; yvf = (int) vbaixo; rectangle(xvi, yvi, xvf, yvf); // ----------------------------------- Mapeamento do Universo setwritemode(COPY_PUT); xescala = fabs((vdir - vesq) / (wdir - wesq)); yescala = fabs((vbaixo - valto) / (walto - wbaixo)); setcolor(cor_objeto); for (i = 0;i < ARE;i++) { xvi = (int) vesq + (ver[are[i].v1].x - wesq) * xescala; yvi = (int) vbaixo - (ver[are[i].v1].y - wbaixo) * yescala; xvf = (int) vesq + (ver[are[i].v2].x - wesq) * xescala; yvf = (int) vbaixo - (ver[are[i].v2].y - wbaixo) * yescala; line(xvi, yvi, xvf, yvf); } passo = 10; xt = 10; yt = 10; do { i = 0; imprime_posicao(); do { posicao(xt, yt, passo); cursor(xt, yt); tecla = getch(); if (tecla == ESC) { closegraph(); exit(0); } if (tecla == ENTER) { cursor(xt, yt); xescala = fabs((vdir - vesq) / (wdir - wesq)); yescala = fabs((vbaixo - valto) / (walto - wbaixo)); for (i = 0;i < OBJ;i++)

55

{ ok = testa_envelope(xt, yt, i); if (ok) { visivel = TRUE; for (j = obj[i].are_inic;j <= obj[i].are_fim;j++) { X1 = vesq+(ver[are[j].v1].x-wesq) * xescala; Y1 = vbaixo-(ver[are[j].v1].y-wbaixo)*yescala; X2 = vesq+(ver[are[j].v2].x-wesq)*xescala; Y2 = vbaixo-(ver[are[j].v2].y-wbaixo)*yescala; A = Y2 - Y1; B = X1 - X2; C = -(X1 * A + Y1 * B); d = A * xt + B * yt + C; if (d < 0) // antihorario { visivel = FALSE; break; } } if (visivel) { setfillstyle(SOLID_FILL, cor_apontado); floodfill(xt, yt, cor_objeto); cor_apontado++; if (cor_apontado > 16) cor_apontado = CYAN; } break; } } } if (tecla == 0) { tecla = getch(); cursor(xt, yt); switch (tecla) { case UP: yt -= passo; if (yt < 0) yt = YMAX; break; case DOWN: yt += passo; if (yt > YMAX) yt = 0; break; case LEFT: xt -= passo; if (xt < 0) xt = XMAX; break; case RIGHT: xt += passo; if (xt > XMAX) xt = 0; break; case F1: passo += 1; if (passo > 999) passo = 999;

56

break; case F2: passo -= 1; if (passo < 1) passo = 1; break; } } } while (tecla != ESC); } while (tecla != ESC); closegraph(); } Arquivo: mundo.ver 21 // número de vértices 0.0 27.0 18.0 0.0 // coordenadas do universo 2.0 2.0 6.0 2.0 4.0 5.0 14.0 3.0 17.0 3.0 17.0 12.0 14.0 12.0 23.0 3.0 26.0 7.0 20.0 7.0 21.0 14.0 21.0 15.0 14.0 15.0 14.0 14.0 9.0 7.0 11.0 9.0 9.0 11.0 7.0 9.0 5.0 11.0 5.0 17.0 1.0 14.0 Arquivo: mundo.are 21 // número de arestas 0 1 1 2 2 0 3 4 4 5 5 6 6 3 7 8 8 9 9 7 10 11 11 12 12 13 13 10 14 15 15 16 16 17 17 14 18 19 19 20 20 18

57

Arquivo: mundo.obt 6 // número de objetos 0 2 0 2 2.0 2.0 6.0 5.0 // lista de vértices e arestas 3 6 3 6 14.0 3.0 17.0 12.0 // é o envelope 7 9 7 9 20.0 3.0 26.0 7.0 10 13 10 13 14.0 14.0 21.0 15.0 14 17 14 17 7.0 7.0 11.0 11.0 18 20 18 20 1.0 11.0 5.0 17.0