144
1

Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

Embed Size (px)

Citation preview

Page 1: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

1

Page 2: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

2

Capítulo I – Introdução a Linguagem C++ ____________________________________ 31. ESTRUTURA BÁSICA DE UM PROGRAMA EM C++ __________________________ 3

1.1 - Primeiro Programa______________________________________________________________ 31.2 - Variáveis _____________________________________________________________________ 4

1.2.1 - Constantes ________________________________________________________________ 41.3 - Operadores____________________________________________________________________ 51.4 - Comentários___________________________________________________________________ 61.5 - Fluxo de Controle ______________________________________________________________ 7

1.5.1 - Comando if () {} _______________________________________________________ 71.5.2 - Comando for( ; ; ) {} _________________________________________________ 81.5.3 - Comando while() {} e do { } while();______________________________ 111.5.4 - Comando break e continue ______________________________________________ 14

1.6 - Funções _____________________________________________________________________ 151.6.1 – Referência _______________________________________________________________ 17

2 - VETORES E MATRIZES__________________________________________________ 192.1 - Vetores______________________________________________________________________ 19

2.1.1 - Declaração _______________________________________________________________ 192.1.2 – Exemplo: Método de Ordenação______________________________________________ 20

2.2 - Matrizes _____________________________________________________________________ 213 - PONTEIROS ____________________________________________________________ 22

3.1 - Introdução ___________________________________________________________________ 223.2 – Principais Aplicações de Ponteiros________________________________________________ 223.3 – Armazenando o Endereço das Variáveis ___________________________________________ 223.4 – Acessando o conteúdo de um endereço ____________________________________________ 233.5 – Ponteiros com Vetores _________________________________________________________ 243.6 – Alocação de Vetores Dinamicamente______________________________________________ 253.7 – Alocação de Matrizes Dinamicamente _____________________________________________ 26

4 – OBJETOS E CLASSES ___________________________________________________ 274.1 – Membros da Classe____________________________________________________________ 274.2 – Construtores _________________________________________________________________ 284.3 – Controle de Acesso aos Campos e Funções _________________________________________ 30

4.3.1 - Seção Pública_____________________________________________________________ 304.3.2 - Seção Privada_____________________________________________________________ 30Exemplo 1: ____________________________________________________________________ 30Exemplo 2: ____________________________________________________________________ 30

4.3 – Funções Membros_____________________________________________________________ 314.3.1 - Introdução _______________________________________________________________ 314.3.2 – Acesso as variáveis da classe ________________________________________________ 314.3.4 – Exemplo de uma Classe Vetor _______________________________________________ 35

Page 3: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

3

Capítulo I – Introdução a Linguagem C++ C++ é uma linguagem de programação orientada a objeto desenvolvida por Bjarne Stroustrup.

1. ESTRUTURA BÁSICA DE UM PROGRAMA EM C++ Em C++ os programas são escritos utilizando-se classes. Inicialmente vamos aprender os comandos básicos do C++ e na seção 3 discutiremos o funcionamento das classes e a orientação a objeto.

1.1 - Primeiro Programa Como primeiro exemplo, consideremos o programa modelo do software Eclipse: Hello.cpp //==================================================================== // Name : Hello.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //==================================================================== #include <iostream> using namespace std; int main() { cout << "Hello World!!!" << endl; // prints Hello World!!! return 0; }

Os programas em C++ sempre iniciam pela função main() (o termo função será explicado depois), Seguindo o nome da função seguem as chaves {} que delimitam o início e o fim da função. Neste exemplo o cout e return são os dois únicos comandos da função main(). O comando cout imprime mensagens na tela padrão e como será visto mais tarde, também imprime o conteúdo de variáveis. Observe que após todo comando dentro de uma função segue um ponto e vírgula ( ; ). O comando return indica o fim da função e neste exemplo que o valor 0 é retornado como resultado da execução da função main. Os caracteres em branco são invisíveis para o compilador. Assim o programa acima também poderia ser (O cometário precisa ser retirado para que funcione): #include <iostream> using namespace std; int main() { cout << "Hello World!!!" << endl; return 0; }

Page 4: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

4

1.2 - Variáveis O programa a seguir exibe como é feita a declaração de algumas variáveis e sua utilização. Variáveis.cpp #include <iostream> using namespace std; int main() { int n = 1; float a = 2.3e10f; double b = 34.5e200; cout << "n = " << n << " a = " << a << " b = " << b << endl; } As primeiras linhas declaram as variáveis e os tipos:

int n; Tipo da variável Nome da variável

Em seguda atribuimos o valor 1 para a variável: n = 1; O C++ tem diferentes tipos de variáveis. Os tipos básicos são: boolean 1-bit (TRUE ou FALSE)

char 8-bit inteiro(signed) (-128 a 127)

short 16-bit inteiro(signed) (–32.768 a 32.767) int 64-bit inteiro(signed)(-2.147.483.648 a 2.147.483 .647)

float 32-bit floating-point (10e-38 a 10e38)

double 64-bit floating point (10e-308 a 10e308)

unsigned Retira o sinal e portanto troca a variação de valores, por exemplo: unsigned char varia de 0 a 255

1.2.1 - Constantes Uma constante é um valor constante que é definido no programa de forma que não será alterado durante toda a execução. Para declararmos uma constante utilizamos o prefixo const, como no exemplo: Variaveis.cpp #include <iostream> int main() { const int a = 1; etc… }

Page 5: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

5

1.3 - Operadores Os operadores aritméticos sobre as variáveis são os seguintes: + Soma

- Subtração * Multiplicação / Divisão % Resto da divisão

A operação de incremento de uma unidade tem também um formato reduzido, ou seja, o comando: i = i + 1; é freqüentemente representado por: i++; Da mesma forma i = i-1; pode ser escrito como i--; Como exemplo dos operadores, o programa abaixo calcula as raízes reais de um polinômio de segundo grau: Raizes.cpp #include <iostream> #include <cmath> int main() { double a, b, c; double x1, x2; a = 1; b = -5; c = 6; x1 = (-b + sqrt(b * b - 4* a * c)) / (2 * a); x2 = (-b - sqrt(b * b - 4* a * c)) / (2 * a); std::cout << "x1 = " << x1 << " x2 = " << x2; }

Page 6: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

6

1.4 - Comentários É possível introduzir comentários dentro de um programa em C++. Há dois nos formatos básicos: Formato 1:

/* Comentario pode prosseguir por varias linhas e so termina ao encontar a marca de fim de comentario */

Format 2: // Comentario somente até o final da linha

Observe o exemplo abaixo: #include <iostream> #include <cmath> int main() { /* Soluções reais da equação a*x*x + b*x + c = 0 */ double x1, x2; const double a = 1; // Valores arbitrarios para a, b e c const double b = -5; const double c = 6; x1 = (-b + sqrt(b * b - 4* a * c)) / (2 * a); x2 = (-b - sqrt(b * b - 4* a * c)) / (2 * a); std::cout << "x1 = " << x1 << " x2 = " << x2; }

Page 7: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

7

1.5 - Fluxo de Controle O comando principal de decisão é o if() { }. Os três formatos mais utilizados de laços são: for( ; ;) { } while() {} do { } while();

1.5.1 - Comando if () {} Através deste comando o fluxo do programa pode ser desviado para executar ou não um conjunto de comandos. Considere o exemplo abaixo: ParImpar.cpp #include <iostream> using namespace std; /** Testa se um numero e par ou impar */ int main() { int i, n; cout << "Ëntre com um numero inteiro: "; cin >> n; // Entre com n i = n % 2; if (i == 0) { cout << n << " e um numero par\n"; } else { cout << n << " e um numero impar\n"; } } Neste exemplo a variável i armazena o resto da divisão de n por 2. Caso seja zero, então o programa passa a execução do comando cout << n << " e um numero par\n". Se a condição falha, o comando else indica que o programa deve executar o comando cout << n << " e um numero impar\n". Observe que o else é um comando opcional. Caso você não o inclua, o programa segue para o próximo comando após o if. Os testes utilizam os seguintes operadores relacionais:

< Menor > Maior <= Menor ou igual >= Maior ou igual == Igual != Diferente

&& e ! negação || ou

Page 8: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

8

1.5.2 - Comando for( ; ; ) {} O for é um comando apropriado quando queremos executar um conjunto de operações um número fixo de vezes, como no exemplo da seqüência de fibonacci:

Fibonacci.cpp #include <iostream> #include <cmath> using namespace std; /** Gera a sequencia de Fibonacci */ const int MAX = 10; int main() { int n; int lo = 1; int hi = 1; cout << "1: 1 \n"; for (n = 2; n <= MAX; n++) { cout << n << ": " << hi << endl; hi = lo + hi; lo = hi - lo; } }

O resultado será: 1: 1 2: 1 3: 2 4: 3 5: 5 6: 8 7: 13 8: 21 9: 34 10: 55

Page 9: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

9

O comando for é composto de três argumentos: for( n=0 ; n<= 10 ; n++ ) Expressão de inicialização Expressão de teste Incremento

Expressão de inicialização Inicializa a variável do laço. A inicialização é feita uma única vez quando o laço inicia. Expressão de teste Esta expressão testa (a cada vez que o conjunto de comandos no interior do for finaliza), se o laço deve ser encerrado. Enquanto a expressão for verdadeira o laço é repetido. Para realizar teste utilizamos os operadores relacionais. Expressão de incremento A cada repetição do laço, o terceiro argumento (n++) incrementa a variável n. Exemplo: Métodos numéricos de integração (ponto a esquerda) Como aplicação do comando for o exemplo abaixo ilustra a implementação do método do ponto a esquerda. Podemos utilizar os métodos de integração para obter uma aproximação para a expansão decimal de . Se calcularmos:

obteremos aproximações para . PontoEsquerda.cpp #include <iostream> #include <cmath> using namespace std; /* Integracao Numerica: Ponto a Esquerda */ int main() { int i; int n; double x, dx; double a, b; double soma; cout.precision(20); a = -1; // Extremo inferior do intervalo b = 1; // Extremo superior do intervalo n = 1000; // Numero de particoes soma = 0.0; dx = (b - a) / n;

Page 10: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

10

x = a; for (i = 0; i < n; i++) { soma = soma + 2* sqrt(1 - x * x) * dx; x = x + dx; } cout << "\n Integral = " << soma ; cout << "\n Pi = " << M_PI; cout << "\n Erro = " << (soma - M_PI); } Exemplo: Métodos numéricos de integração (Monte Carlo) Neste método utilizamos um sorteio de pontos em uma certa região. O quociente do número de pontos que são sorteados no interior pelo número total de pontos é uma estimativa para a integral. MonteCarlo.cpp #include <iostream> #include <cstdlib> using namespace std; /* Integracao Numerica: Monte Carlo */ int main() { double x, y, f; int cont = 0; const int points = 500000; srand(1); cout.precision(20); for (int i = 0; i < points; i++) { x = (double)rand()/ RAND_MAX; y = (double)rand()/ RAND_MAX; if ((x * x + y * y - 1) < 0) cont++; } f = 4.0 * cont / points; cout << "Pi = " << f << endl; } Exemplo: Métodos numéricos de integração (Método de Simpson) O método de Simpson refina o método do trapézio [Malta,Pesco,Lopes, Cálculo a uma variável – Vol II]. #include<iostream> #include<cmath> using namespace std; #define PI 3.14159265358979323846264338327950288419716939937510

Page 11: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

11

int main() { int n; double x, dx; double a, b; double soma; cout.precision(20); a = -1; // Extremo inferior do intervalo b = 1; // Extremo superior do intervalo n = 100000; // Numero de particoes soma = 0.0; dx = (b - a) / n; x = a; soma = 2 * sqrt(1 - a * a); for (int i = 1; i < n; i++) { x = x + dx; if (i % 2 == 0) soma = soma + 2 * 2*sqrt(1 - x * x); else soma = soma + 4 * 2*sqrt(1 - x * x); } soma = 2 * sqrt(1 - b * b); soma = soma * dx / 3; cout << "\n Integral = " << soma; cout << "\n Pi = " << PI; cout << "\n Erro = " << (soma - PI); }

1.5.3 - Comando while() {} e do { } while(); Este segundo tipo de laço é adequado para situações onde não sabemos ao certo quantas vezes o laço deve ser repetido. Existem dois formatos: while (“condição”) {

... comandos ...

}

Inicia testando se a condição é verdadeira, e em caso afirmativo, os comando dentro while são executados e ao final, a condição é novamente testada. Enquanto a condição permanecer verdadeira, os comandos no interior do while são repetidos. Observe que se a condição for falsa a primeira vez, em nenhum momento os comandos dentro do laço serão executados. do {

... comandos ...

Page 12: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

12

} while (“condição”);

Inicia executando os comandos e ao final, testa a condição. Se verdadeira, então os comandos são novamente executados. Enquanto a condição permanecer verdadeira, os comandos são repetidos. Observe que os comandos são executados no mínimo uma vez, mesmo que a condição seja falsa na primeira vez, sendo esta a diferença para o formato anterior while() {}. Os exemplos a seguir ilustram aplicações de ambos os casos: Exemplo: Método de Newton O programa abaixo determina as soluções da equação utilizando o método de Newton, ou seja, dada uma condição inicial e um erro máximo, a seqüência abaixo pode convergir para uma das soluções:

#include <iostream> #include <cmath> using namespace std; /* Metodo de Newton */ int main() { double xn, xn_1; double erro; xn = 2; // Condicao inicial erro = 1e-10; // Erro maximo cout.precision(20); do { xn_1 = xn; xn = xn_1 - (xn_1 * xn_1 - 2) / (2 * xn_1); cout << "Solucao parcial = " << xn << endl; } while (fabs(xn - xn_1) > erro); cout << "Solucao obtida = " << xn << endl; cout << "Raiz 2 = " << M_SQRT2 << endl; }

Page 13: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

13

Exemplo: Método da Bisseção O programa abaixo determina as soluções da equação: Para isso utilizaremos o método da bisseção. No método da bisseção procuramos uma solução contida em certo intervalo [a,b] dado. A solução existe desde que a função seja contínua, e o sinal da função troque de um extremo para outro (ou seja f(a) * f(b) < 0). Bissecao.cpp #include <iostream> #include <cmath> using namespace std; int main() { double a,b,c; double fa,fb,fc; const double erro = 0.0000001; cout.precision(20); cout << "Entre com o extremo a: "; cin >> a; cout << "Entre com o extremo b: "; cin >> b; fa = a*a - 2; fb = b*b - 2; if ((fa * fb) > 0) { cout << "Intervalo inicial nao garante existencia de solucao ! \n"; return 0; } while(fabs(a-b) > erro) { c = (a+b)/2.0; fc = c*c - 2.0; if (fa * fc < 0) { b = c; } else { if (fb * fc < 0) a = c; else break; } cout << "Solucao parcial = " << c << endl; } cout << "Solucao obtida = " << c << endl; cout << "Raiz 2 = " << M_SQRT2 << endl; }

Page 14: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

14

1.5.4 - Comando break e continue Estes dois comando servem para auxiliar na interrupção do laço, cumprindo diferentes tarefas: - O comando break; interrompe o laço (Qualquer dos formatos apresentados) e o programa continua no primeiro comando após o laço. Exemplo: Exemplobreak.cpp #include <iostream> using namespace std; int main() { int n = 0; while (n < 10) { cout << "n = " << n << endl; if (n > 3) break; n++; } cout << "Fim do programa \n"; } O resultado deste programa será: n = 0 n = 1 n = 2 n = 3 n = 4 Fim do programa - O comando continue; transfere a execução do programa para o teste do laço, que pode ou não prosseguir, conforme a condição seja verdadeira ou falsa.

Page 15: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

15

1.6 - Funções As funções cumprem como primeiro papel evitar repetições desnecessárias de código. Nos exemplos anteriores foi necessário calcular o valor y = x*x-2 em diversas partes do programa. Se desejássemos trocar a função, seria necessário alterar várias partes do código. Para evitar isso, podemos utilizar uma função como no exemplo abaixo: Bissecao.cpp #include <iostream> #include <cmath> using namespace std; float f(float x) { float y; y = x*x-2; return(y); } int main() { double a,b,c; double fa,fb,fc; const double erro = 0.0000001; cout.precision(20); cout << "Entre com o extremo a: "; cin >> a; cout << "Entre com o extremo b: "; cin >> b; fa = f(a); fb = f(b); if ((fa * fb) > 0) { cout << "Intervalo inicial nao garante existencia de solucao ! \n"; return 0; } while(fabs(a-b) > erro) { c = (a+b)/2.0; fc = f(c); if (fa * fc < 0) b = c; else { if (fb * fc < 0) a = c; else break; } cout << "Solucao parcial = " << c << endl; } cout << "Solucao obtida = " << c << endl; cout << "Raiz 2 = " << M_SQRT2 << endl; }

Page 16: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

16

Vamos examinar alguns detalhes da função introduzida: float f (float

x) Define o tipo que será retornado

Nome da função

Parâmetro de entrada

{ float y; y = x * x - 2;

return(y);

Valor a ser retornado

} Uma observação importante é que as variáveis dentro da função não são conhecidas fora da função e vice-versa. Considere o seguinte programa: Funcao.cpp #include <iostream> using namespace std; int teste(int k) { k = k + 20; cout << "Dentro da funcao k = " << k << endl; return(k); } int main() { int i,j; i = 1; cout << "Fora da funcao i = " << i << endl; j = teste(i); cout << "Fora da funcao i = " << i << endl; cout << "Fora da funcao j = " << j << endl; }

O resultado será: Fora da funcao i = 1 Dentro da funcao k = 21 Fora da funcao i = 1 Fora da funcao j = 21

Page 17: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

17

Observe que o valor da variável i não tem seu conteúdo alterado pela função. Isto ocorre porque quando uma função é chamada durante o programa, o parâmetro de entrada (variável i) tem seu conteúdo copiado para uma nova variável declarada na função (variável k). Observe que a variável i e j não são conhecidas dentro da função teste().

1.6.1 – Referência Muitas vezes gostaríamos que os argumentos de entrada da função pudessem ter seus valores alterados quando a função finalizasse. Para isso utilizamos uma referência para o parâmetro de entrada como ilustra o exemplo abaixo: Referencia.cpp #include <iostream> using namespace std; int teste(int& k) { k = k + 20; cout << "Dentro da funcao k = " << k << endl; return(k); } int main() { int i,j; i = 1; cout << "Fora da funcao i = " << i << endl; j = teste(i); cout << "Fora da funcao i = " << i << endl; cout << "Fora da funcao j = " << j << endl; }

O resultado será: Fora da funcao i = 1 Dentro da funcao k = 21 Fora da funcao i = 21 Fora da funcao j = 21 Quando o parâmetro da função é declarado com o símbolo & antes do nome da variável, então qualquer alteração no corpo da função do parâmetro de entrada, acessa o argumento de entrada utilizado na chamada da função. Nesse caso o parâmetro de entrada é uma referência.

Page 18: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

18

Exemplo: Vamos construir uma função cujo objetivo é permutar os valores de duas variáveis dadas. Não seria possível permutar os dois valores através de uma função como abaixo: Nao_Permuta.cpp /* Este programa NÃO consegue permutar os valores */ #include <iostream> void troca(float x, float y) { float auxiliar; auxiliar = x; x = y; y = auxiliar; } int main() { float x = 1.2f; float y = 56.89f; troca(x,y); std::cout << "x = " << x << " e y = " << y << std::endl; } O resultado deste programa seria: x = 1.2 e y = 56.89 Como visto anteriormente, utilizando referências podemos obter o efeito desejado: Permuta.cpp /* Este programa consegue permutar os valores */ #include <iostream> void troca(float& x, float& y) { float auxiliar; auxiliar = x; x = y; y = auxiliar; } int main() { float x = 1.2f; float y = 56.89f; troca(x,y); std::cout << "x = " << x << " e y = " << y << std::endl; } O uso comum de argumentos do tipo referência ocorre em funções que devem retornar mais de um valor. No exemplo acima, a função retornou dois valores.

Page 19: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

19

2 - VETORES E MATRIZES

2.1 - Vetores Quando você deseja representar uma coleção de dados semelhantes, pode ser muito inconveniente utilizar um nome de variável diferente para cada dado. Para ilustrar vamos considerar o seguinte exemplo: Montar um programa que armazena as notas de 5 alunos e calcula a média obtida pela turma. As notas serão armazenadas em uma variável do tipo float, porém ao invés de criarmos 5 variáveis, utilizamos uma variável do tipo vetor, definida como abaixo: float notas[5]; Exemplo: Notas.cpp #include <iostream> using namespace std; int main() { int i; float media; float soma; float notas[5]; for (i = 0; i < 5; i++) { cout << " Aluno [" << (i+1) << "]:" ; cin >> notas[i]; } soma = 0; for (i = 0; i < 5; i++) soma = soma + notas[i]; media = soma / 5; cout << " A media final é: " << media; }

2.1.1 - Declaração Um vetor é uma coleção de variáveis de certo tipo, alocadas seqüencialmente na memória. Para C++ um declaração de variável vetor do tipo: int n[5]; reserva o espaço de 5 variáveis do tipo inteira, onde cada variável pode ser referenciada conforme abaixo:

Page 20: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

20

n[0] n[1] n[2] n[3] n[4] IMPORTANTE: Observe que a declaração anterior cria cinco variáveis, porém o primeiro elemento é n[0]. A declaração de vetor inicia com o índice 0 e finaliza no índice 4. Se você quer atribuir um valor a um dos componentes do vetor basta referenciá-lo: n[3] = 29; resultando em: 29 n[0] n[1] n[2] n[3] n[4] Assim como é possível atribuir valores a uma variável na mesma linha da declaração, o mesmo pode ser feito para vetores. Observe o exemplo abaixo: int n[5] = {23, 3, -7, 288, 14};

2.1.2 – Exemplo: Método de Ordenação Como exemplo vamos apresentar um programa que ordena uma seqüência de 10 números reais. Ordenação.cpp /* Metodo da Bolha (ordenacao de um vetor) */ #include <iostream> using namespace std; int main() { int i; int flag; float swap; float x[10]; const int n = 10; /* Entrada de Dados */ cout << "Entre com os numeros para ordenacao \n"; for (i = 0; i < n; i++) { cout << "\n numero[" << i << "] = "; cin >> x[i]; } /* Ordena a sequencia de numeros */ flag = 1; while (flag == 1) { flag = 0; for (i = 0; i < (n - 1); i++) { if (x[i] > x[i + 1]) { swap = x[i];

Page 21: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

21

x[i] = x[i + 1]; x[i + 1] = swap; flag = 1; } } } /* Imprime a sequencia de numeros ordenada */ cout << "\n Sequencia ordenada : " << endl; for (i = 0; i < n; i++) cout << x[i] << endl; }

2.2 - Matrizes Para representar uma matriz 3x4 (3 linha e 4 colunas) de números reais utilizamos a seguinte declaração: float A[3][4]; Assim fica reservado um espaço de memória conforme a figura abaixo: A[0][0] A[0][1] A[0][2] A[0][3] A[1][0] A[1][1] A[1][2] A[1][3] A[2][0] A[2][1] A[2][2] A[2][3] Exemplo: Produto de uma matriz por um vetor Vamos montar um programa que multiplica um vetor por uma matriz. /* * * * * * * * * * * * * * * * * * * * * * */ /* Multiplicacao de um vetor por uma matriz */ #include <iostream> using namespace std; int main() { int i, j; float A[3][3] = { { 1.0, 1.5, 2.1 }, { 3.4, 2.2, 9.1 }, {-1.2, -3.4, 0.9 }}; float v[3] = { 2.0, 1.0, 0.5 }; float p[3]; for (i = 0; i < 3; i++) { p[i] = 0; for (j = 0; j < 3; j++) p[i] += A[i][j] * v[j]; } for (i = 0; i < 3; i++) { cout << "\n["; for (j = 0; j < 3; j++) cout << A[i][j] << " "; cout << " ] [ " << v[i] << "]"; } for (i = 0; i < 3; i++)

Page 22: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

22

cout << "\n p["<< i << "] = " << p[i]; }

3 - PONTEIROS

3.1 - Introdução Um ponteiro é uma variável que contém o endereço de memória de outra variável. Todas as variáveis são alocadas em algum espaço de memória do computador. O ponteiro fornece um mecanismo para obter e armazenar este endereço de memória. Considere o exemplo: Ponteiro01.cpp #include <iostream> using namespace std; int main() { int i; cout << "Endereco de i = " << &i << endl; } O endereço da variável é obtido utilizando-se o operador unário & na frente da variável. Assim &i fornece o endereço da variável i.

3.2 – Principais Aplicações de Ponteiros Algumas situações em que os ponteiros são úteis: 1. Para passar vetores e matrizes de forma mais conveniente como argumentos de funções. 2. Para manipular vetores e matrizes de forma mais eficiente. 3. Para manipular estruturas de dados mais complexas, tais como listas e árvores. 4. Na utilização de alocação de memória dinâmica.

3.3 – Armazenando o Endereço das Variáveis Para armazenar o endereço de uma variável (por exemplo &i) em outra variável, é necessário criar um tipo especial de variável denominada apontador. Exemplo: Ponteiro02.cpp #include <iostream> int main() { int i ; int *pi; pi = &i;

Page 23: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

23

std::cout << "Endereco de i = " << &i << " ou " << pi; }

A variável pi é uma variável do tipo ponteiro para inteiro (ou seja, ela recebe o endereço de uma variável do tipo inteiro). Para informar que esta variável é do tipo apontador colocamos um asterisco (*) na frente da variável no momento da sua declaração: int * pi; Tipo de ponteiro

Indica ponteiro

Nome da variável

3.4 – Acessando o conteúdo de um endereço Considere o exemplo anterior em que pi = &i. Além do endereço de i, (já armazenado em pi) podemos também acessar o conteúdo armazenado no endereço de memória. Isto equivale a obter o valor da variável i. Observe o exemplo: Ponteiro03.cpp #include <iostream> using namespace std; int main() { int i, j; int *pi; pi = &i; i = 25; j = *pi + 8; /* equivalente a j = i + 8 */ cout << "Endereco de i = " << pi << endl; cout << "j = " << j << endl; } O operador unário * trata seu operando como um endereço e acessa este endereço para buscar o conteúdo da variável. Observe que o * tem dupla função: 1. Em uma declaração de variável, indica que a variável é do tipo ponteiro. 2. Durante uma atribuição, acessa o conteúdo do endereço armazenado pela variável

ponteiro. No nosso exemplo, para alterar o valor da variável i, temos duas alternativas (totalmente equivalentes) : i = 5; *pi = 5;

Page 24: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

24

3.5 – Ponteiros com Vetores Na linguagem C++, o relacionamento de ponteiros com vetores e matrizes é tão direto que daqui para frente sempre trataremos vetores e matrizes utilizando ponteiros. Qualquer operação que possa ser feita com índices de um vetor pode ser feita através de ponteiros. Vamos acompanhar através do exemplo de ordenação: /* Metodo da Bolha (ordenacao de um vetor) */ #include <iostream> using namespace std; void troca(float& x, float& y) { float auxiliar; auxiliar = x; x = y; y = auxiliar; } void ordena(float *v,int elementos) { // Ordena a sequencia de numeros int flag = 1; while (flag == 1) { flag = 0; for (int i = 0; i < (elementos - 1); i++) { if (v[i] > v[i + 1]) { troca(v[i],v[i+1]); flag = 1; } } } } int main() { float x[10]; const int n = 10; // Entrada de Dados cout << "Entre com os numeros para ordenacao \n"; for (int i = 0; i < n; i++) { cout << "\n numero[" << i << "] = "; cin >> x[i]; } ordena(x,n); // Imprime a sequencia de numeros ordenada cout << "\n Sequencia ordenada : " << endl;

Page 25: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

25

for (int i = 0; i < n; i++) cout << x[i] << endl; } Observe que quando chamamos a função ordena(x,n), utilizamos como argumento a variável x, sem referência a nenhum índice em particular do vetor. A função ordena é declarada como: void ordena(float *v, int elementos) Como o programa sabe que estamos nos referenciando a um vetor e não a uma simples variável ? Na verdade v é uma variável ponteiro para um float. Ela recebe o endereço do primeiro elemento do vetor. Assim é equivalente a chamar a função ordena como:

ordena(&x[0],n); Como os vetores são alocados sequencialmente na memória do computador, então a referência x[5], acessa o sexto conteúdo em sequência na memória. Quando o nome de um vetor é passado para uma função, o que é passado é o endereço do início do vetor.

3.6 – Alocação de Vetores Dinamicamente Uma das restrições do nosso programa de ordenação é que o usuário não pode definir a princípio quantos elementos ele pretende ordenar. Isto ocorre porque precisamos informar na declaração do vetor qual será a sua dimensão. Vamos retirar essa restrição. Para isso utilizaremos um novo comando: new[]. Vamos utilizar um exemplo: #include <iostream> using namespace std; void main() { int i,n; float *v; cout << "Entre com a dimensao do vetor desejada = " << endl; cin >> n; v = new float[n]; cout << "Entre com o vetor = " << endl; for(i=0;i<n;i++) cin >> v[i]; for(i=0;i<n;i++) cout << "v[" << i << "]= " << v[i] << endl;; delete[] v; } Para efetuar a alocação dinâmica observe as etapas do programa: 1. O vetor que será alocado foi declarado como um ponteiro: float *v; 2. O comando new float[n] reserva n espaços de memória, cada um do tamanho de um

float.

Page 26: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

26

3. A função new retorna o endereço do primeiro elemento do vetor. 4. A função delete[] libera o espaço de memória reservado para o vetor.

3.7 – Alocação de Matrizes Dinamicamente Para alocar matrizes observe o exemplo: #include <iostream> using namespace std; void main() { int i,j,n,m; float **A; cout << "Entre com a dimensão da matriz desejada: \n n = "; cin >> n; cout << " m = "; cin >> m; A = new float*[n]; A[0] = new float[n*m]; for(i=1;i<n;i++) A[i] = &A[0][i*m]; for(i=0;i<n;i++) for(j=0;j<m;j++) cin >> A[i][j]; for(i=0;i<n;i++) { cout << endl; for(j=0;j<m;j++) cout << "A["<<i<<"]["<< j << "]= " << A[i][j]; } delete [] A[0]; delete [] A; }

Page 27: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

27

4 – OBJETOS E CLASSES A programação orientada a objeto é uma estratégia de programação onde definimos novos tipos de dados (os objetos) e as operações que faremos sobre esses dados. A definição de um objeto é feita pela noção de classe, que será descrita nesta seção.

4.1 – Membros da Classe Uma classe tem dois tipos principais de componentes:

1. Váriável Membro: correspondem aos dados, representados pelos campos da classe. 2. Função Membro: são funções que operam sobre os campos da classe.

Vamos iniciar com um exemplo, definindo um círculo com duas funções membros e três variáveis membros: Circulo.hpp class Circulo { public: Circulo(); // Funcao membro double area(); // Funcao membro private: double raio; // Variavel membro double centrox,centroy; // Variavel membro }; As funções membros foram declaradas mas não implementadas. Isso será feito em outro módulo: Circulo.cpp #define _USE_MATH_DEFINES #include <math.h> #include "Circulo.hpp" Circulo::Circulo() { raio = 1.0; centrox = 0.0; centroy = 0.0; } double Circulo::area() { return(M_PI * raio * raio); }

Page 28: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

28

O programa abaixo utiliza a classe circulo: main.cpp #include <iostream> #include "Circulo.hpp" using namespace std; int main() { Circulo A; cout << "Area do Circulo = " << A.area(); }

4.2 – Construtores A declaração feita no programa main: Circulo A;

cria o objeto círculo, chamando a função Circulo(). Esta função, em particular, tem propriedades especiais pois é responsável pela criação de um novo objeto e por essa razão é denominada construtor. Um construtor pode ser identificado na definição de uma classe por ser a única função cujo nome coincide exatamente com o nome da classe. Algumas características importantes do construtor:

1) Tem sempre o mesmo nome da classe 2) Pode ou não ter argumentos 3) Não retorna nenhum campo (ou seja, não possui return).

Observe que no nosso exemplo a classe se chama Circulo e portanto o construtor se chama Circulo(...) também. #include <iostream> class Circulo { public: Circulo(); // Construtor double area(); // Funcao membro private: double raio; // Campos double centrox,centroy; } Um construtor, ao contrário de uma função membro usual, não tem um tipo. Por exemplo: a função double area() retorna um double, enquanto o construtor Circulo(), não tem nenhum tipo como prefixo.

Page 29: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

29

O objetivo principal do construtor é garantir que todo objeto criado possa ter seus campos inicializados. Muitas vezes gostaríamos de definir como os campos devem ser iniciados e possivelmente executar alguns comandos específicos na criação do objeto. Neste caso utilizamos os construtores. Uma classe pode ter vários construtores diferentes conforme os parâmetros de entrada. Por exemplo: Circulo.hpp class Circulo { public: Circulo(); // Construtor Circulo(double r,double cx, double cy); // Construtor double area(); // Funcao membro private: double raio; // Campos double centrox,centroy; };

O construtor Circulo(double r,double cx, double cy) permite que se inicialize os campos do objeto conforme os parâmetros de entrada. Circulo.cpp #define _USE_MATH_DEFINES #include <math.h> #include "Circulo.hpp" Circulo::Circulo() { raio = 1.0; centrox = 0.0; centroy = 0.0; } Circulo::Circulo(double r,double cx, double cy) { raio = r; centrox = cx; centroy = cy; } double Circulo::area() { return(M_PI * raio * raio); }

main.cpp #include <iostream> #include "Circulo.hpp" using namespace std; int main() { Circulo A; Circulo B(2.5,1.0,1.0); cout << "Area do Circulo A = " << A.area(); cout << "Area do Circulo B = " << B.area(); }

Page 30: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

30

É possível definir uma classe sem construtores. Nesse caso as variáveis membro são criadas mas não inicializadas. Para alterar os campos será necessário criar funções membro que modifiquem os valores dos campos.

4.3 – Controle de Acesso aos Campos e Funções

4.3.1 - Seção Pública Observe que a primeira parte da classe Circulo inicia com uma seção pública, denotada por “public:”. A lista de itens que segue após essa declaração (funções ou variáveis) ficam disponíveis para acesso. Este elemento define o controle de acesso aos elementos, definindo assim se um dado campo da classe pode ou não ser alterado por outra classe.

4.3.2 - Seção Privada Os elementos definidos na seção private somente são acessíveis pela própria classe. Utilizamos private quando queremos que os campos não sejam alterados exceto pelas funções da classe.

Exemplo 1: Se os campos da classe Círculo fossem definidas como públicas, então no main, poderíamos acessar as variáveis do objeto e alterá-lo. Veja o exemplo: Circulo.hpp class Circulo { public: Circulo(); // Construtor double area(); // Funcao membro double raio; // Campos double centrox,centroy; }; main.cpp #include <iostream> #include "Circulo.hpp" using namespace std; int main() { Circulo A; A.raio = 2; A.centrox = 0.2; cout << "Area do Circulo A = " << A.area() << endl; }

Exemplo 2: Os elementos da seção private não podem ser acessados fora da classe. Assim o exemplo abaixo causaria erros de compilação nas linhas indicadas: Circulo.hpp

Page 31: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

31

class Circulo { public: Circulo(); // Construtor double area(); // Funcao membro private: double raio; // Campos double centrox,centroy; }; main.cpp #include <iostream> #include "Circulo.hpp" using namespace std; int main() { Circulo A; A.raio = 2; // ERRO NA COMPILAÇÃO ! A.centrox = 0.2; // ERRO NA COMPILAÇÃO ! cout << "Raio do Circulo A = " << A.raio << endl; // ERRO ! cout << "Area do Circulo A = " << A.area() << endl; } Neste caso, para alterar as variáveis da classe precisamos definir funções na classe que façam essa tarefa.

4.3 – Funções Membros

4.3.1 - Introdução Uma função membro da classe é uma rotina (código) que atua sobre o objeto, como por exemplo, alterando seus campos, respondendo propriedades sobre o objeto, etc. No nosso exemplo, implementamos um método que responde a área do objeto círculo.

4.3.2 – Acesso as variáveis da classe Podemos definir funções que alteram ou exibem as variáveis da classe. Circulo.hpp class Circulo { public: Circulo(); // Construtor void translacao(double x,double y); double get_centrox(); double get_centroy(); double area(); // Funcao membro private: double raio; // Campos double centrox,centroy; };

Page 32: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

32

Circulo.cpp #define _USE_MATH_DEFINES #include <math.h> #include "Circulo.hpp" Circulo::Circulo() { raio = 1.0; centrox = 0.0; centroy = 0.0; } void Circulo::translacao(double x,double y) { centrox += x; centroy += y; } double Circulo::get_centrox() { return(centrox); } double Circulo::get_centroy() { return(centroy); } double Circulo::area() { return(M_PI * raio * raio); }

main.cpp #include <iostream> #include "Circulo.hpp" using namespace std; int main() { Circulo A; A.translacao(2,3); cout << "Centro do Circulo A = (" << A.get_centrox() << "," << A.get_centroy() << ")" << endl; cout << "Area do Circulo A = " << A.area() << endl; }

Page 33: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

33

4.3.3 – Exemplo de uma Classe para Representar Números Racionais O exemplo abaixo ilustra a implementação de uma classe que represente um número racional por seu numerador e denominador inteiro. Racional.hpp class Racional { private: int p,q; void simplifica(); public: Racional(int a = 0,int b = 1) { p = a; q = b; simplifica(); }; Racional(Racional &R) { p = R.p; q = R.q; }; Racional soma(const Racional& p); Racional subtrai(const Racional& q); Racional multiplica(const Racional &n); void show(); };

Racional.cpp #include "Racional.h" #include <math.h> #include <iostream> using namespace std; void Racional::simplifica() { int r; int b = p; int a = q; do { r = b % a; b = a; a = r; } while(r != 0); p = p / b; q = q / b; } Racional Racional::soma(const Racional& z) { Racional s; s.p = z.p * q + z.q * p; s.q = z.q * q; s.simplifica(); return(s); } Racional Racional::subtrai(const Racional& z) { Racional dif;

Page 34: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

34

dif.p = z.q * p - z.p * q; dif.q = z.q * q; dif.simplifica(); return(dif); } Racional Racional::multiplica(const Racional& z) { Racional s; s.p = z.p * p; s.q = z.q * q; s.simplifica(); return(s); } void Racional::show() { if (q == 1) cout << p; else if ( q == -1) cout << -p; else cout << p << "/" << q; }

main.cpp #include "Racional.h" #include <iostream> using namespace std; int main() { for(int i = 1;i<8;i++) { Racional x(i,i+2); Racional u(i+1,i); x.show(); cout << " + "; u.show(); cout << " = "; (x.soma(u)).show(); cout << endl; x.show(); cout << " - "; u.show(); cout << " = "; (x.subtrai(u)).show(); cout << endl; x.show(); cout << " . "; u.show(); cout << " = "; (x.multiplica(u)).show(); cout << endl; } }

Page 35: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

35

4.3.4 – Exemplo de uma Classe Vetor O exemplo abaixo ilustra a implementação de uma classe vetor de double. Vetor.hpp class Vetor { double *v ; // Os primeiros campos sao private int dim; public: Vetor(int n); // Construtor Vetor(Vetor& W); // Construtor ~Vetor(); // Destruidor void set(int i,double x); // Funcoes de acesso e modificadores double get(int i); int get_dim(); }; Vetor.cpp #include "Vetor.h" Vetor::Vetor(int n) { dim = n; v = new double[n]; } Vetor::Vetor(Vetor& C) { dim = C.get_dim(); v = new double[dim]; for(int j=0;j<dim;j++) v[j] = C.get(j); } Vetor::~Vetor() { delete [] v; } void Vetor::set(int i,double x) { if ((i >= 0) && (i<dim)) v[i] = x; } double Vetor::get(int i) {

if ((i >= 0) && (i<dim)) return (v[i]);

else return 0; } int Vetor::get_dim() { return(dim); }

Page 36: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

36

main.cpp #include <iostream> using namespace std; #include "Vetor.h" int main() { int i,n; cout << "Entre com a dimensão do vetor: = "; cin >> n; Vetor A(n); cout << "Entre com os elementos do vetor" << endl; for(i=0;i<n;i++) { double x; cout << "V[" << i << "]="; cin >> x; A.set(i,x); } for(i=0;i<n;i++) cout << " A["<<i<<"]= " << A.get(i) << endl; } Soma de vetores Existem diferentes formas de se implementar a soma de dois objetos. No caso de vetores, vamos considerar como um primeiro exemplo somar dois vetores u e v resultando em um novo vetor soma. A operação de soma sera implementada como uma função da classe Vetor. Vetor.h class Vetor { double *v ; // Os primeiros campos sao private int dim; public: Vetor(int n); // Construtor Vetor(Vetor& W); // Construtor ~Vetor(); // Destruidor void set(int i,double x); // Funcoes de acesso e modificadores double get(int i); int get_dim(); Vetor soma(Vetor b); };

Page 37: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

37

Vetor.cpp #include "Vetor.h" . . . Vetor Vetor::soma(Vetor b) { if (dim != b.dim) return 0; Vetor soma(dim); for(int i = 0; i < dim; i++) soma.v[i] = v[i] + b.v[i]; return soma; } main.cpp #include <iostream> using namespace std; #include "Vetor.h" int main() { int i,n; cout << "Entre com a dimensão do vetor: = "; cin >> n; Vetor A(n); Vetor B(n); cout << "Entre com os elementos do vetor" << endl; for(i=0;i<n;i++) { double x; cout << "v[" << i << "]="; cin >> x; A.set(i,x); cout << "w[" << i << "]="; cin >> x; B.set(i,x); } Vetor C = A.soma(B); for(i=0;i<n;i++) cout << " v["<<i<<"]= " << A.get(i) << endl; for(i=0;i<n;i++) cout << " w["<<i<<"]= " << B.get(i) << endl; for(i=0;i<n;i++) cout << " soma["<<i<<"]= " << C.get(i) << endl; }

Page 38: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

38

Sobrecarga de Operadores Em C++ podemos redefinir operadores que permitem realizar operações entre objetos. Um exemplo é somar vetores usando o símbolo “+”. Outro exemplo na classe Vetor seria definir um operador [ ] para acessarmos o elemento v[i] (substituindo o comando A.get(i) e A.set(i)). Vetor.h class Vetor { double *v ; // Os primeiros campos sao private int dim; public: Vetor(int n); // Construtor Vetor(Vetor& W); // Construtor ~Vetor(); // Destruidor double& operator[] (int i); // Funcoes de acesso e modificadores int get_dim(); }; Vetor.cpp #include "Vetor.h" Vetor::Vetor(int n) { dim = n; v = new double[n]; } Vetor::Vetor(Vetor& C) { dim = C.get_dim(); v = new double[dim]; for(int j=0;j<dim;j++) v[j] = C[j]; } Vetor::~Vetor() { delete [] v; } double& Vetor::operator[](int i) { if ((i < 0) || (i >= dim)) { std::cout << "Indice fora de dimensao \n"; exit(0); } return v[i]; } int Vetor::get_dim() { return(dim); }

Page 39: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

39

main.cpp #include <iostream> using namespace std; #include "Vetor.h" int main() { int i,n; cout << "Entre com a dimensão do vetor: = "; cin >> n; Vetor A(n); cout << "Entre com os elementos do vetor" << endl; for(i=0;i<n;i++) { double x; cout << "V[" << i << "]="; cin >> x; A[i] = x; } for(i=0;i<n;i++) cout << " A["<<i<<"]= " << A[i] << endl; } A classe racional poderia ser reimplementada da seguinte forma: Racional.h #include <iostream> using namespace std; class Racional { private: int p,q; void simplifica(); public: Racional(int a = 0,int b = 1) { p = a; q = b; simplifica(); }; Racional(Racional &R) { p = R.p; q = R.q; }; Racional operator+(const Racional& n); Racional operator*(const Racional& n); Racional operator-(const Racional& n); friend ostream& operator<<(ostream& out, const Racional& r); friend bool operator==(const Racional& r,const Racional& s); }; Racional.cpp #include "Racional.h" Racional Racional::operator-(const Racional& z) { Racional dif; dif.p = z.q * p - z.p * q;

Page 40: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

40

dif.q = z.q * q; dif.simplifica(); return(dif); } ostream& operator<<(ostream& out, const Racional& r) { if (r.q == 1) out << r.p; else if ( r.q == -1) out << -r.p; else out << r.p << "/" << r.q; return(out); } void Racional::simplifica() { int r; int b = p; int a = q; do { r = b % a; b = a; a = r; } while(r != 0); p = p / b; q = q / b; } Racional Racional::operator+(const Racional& z) { Racional s; s.p = z.p * q + z.q * p; s.q = z.q * q; s.simplifica(); return(s); } Racional Racional::operator*(const Racional& z) { Racional s; s.p = z.p * p; s.q = z.q * q; s.simplifica(); return(s); }

Page 41: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

41

bool operator== (const Racional& r,const Racional& s) { return(r.p * s.q == r.q * s.p); } main.cpp #include "Racional.h" int main() { Racional a(6,3); Racional b(3,4); Racional c = a + b; cout << c; for(int i = 1;i<10;i++) { Racional x(i,i+2); Racional u(i+1,i); cout << x << " + " << u << " = " << x + u << endl; cout << x << " * " << u << " = " << x * u << endl; cout << x << " - " << u << " = " << x - u << endl; if (x == b) cout << "Igual" << endl; } }

Page 42: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

1

Page 43: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

2

1. PONTOS E RETAS NO OPENGL ......................................................................................... 3

1.1 – Sistemas Gráficos ............................................................................................................................3 1.2 – Cores .......................................................................................................................................................3 1.3 – Introdução ao OpenGL ..................................................................................................................4 1.4 – Funções Básicas...............................................................................................................................4 1.5 – gluOrtho2D ...........................................................................................................................................6 1.6 – Exemplo: Plotar uma reta unindo dois pontos...................................................................7

1.6.1 – Algoritmo ingênuo .....................................................................................................................................7 1.6.2 – Retas no Opengl ........................................................................................................................................8

1.7 – Exemplo: Plotar o gráfico de uma função ............................................................................9 1.8 – Fontes ..................................................................................................................................................11

2. TECLADO E MOUSE(Callbacks) .......................................................................................13 2.1 – Introdução ..........................................................................................................................................13 2.2 – Teclado................................................................................................................................................13

2.2.1 – Exemplo: Utilização do teclado no programa funções........................................................13 2.3 – Mouse ..................................................................................................................................................14

2.3.1 – Interrupções a partir do mouse .......................................................................................................14 2.3.2 – Aplicações: Realizando o “zoom” do gráfico............................................................................17 2.3.3 – Aplicações: Pilha.....................................................................................................................................22

3. RETAS E POLÍGONOS NO OPENGL ...............................................................................28 3.1 – Primitivas............................................................................................................................................28 3.2 – Exemplo: Visualização de Métodos Numéricos de Integração .............................29

4. CURVAS PARAMÉTRICAS ..................................................................................................32 4.1 – Introdução ..........................................................................................................................................32 4.2 – Exemplo: Visualização de Curvas Paramétricas ..........................................................32 4.3 – Curvas na forma Polar ................................................................................................................36 4.4 – Exemplo: Visualização de Curvas Polares ......................................................................37

5. CURVAS IMPLÍCITAS ............................................................................................................39 5.1 – Introdução ..........................................................................................................................................39 5.2 – Visualização de Curvas Implícitas ........................................................................................39 5.3 – Programa Curva Implícita..........................................................................................................40

Page 44: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

3

Capítulo II – Aplicações Gráficas 2D 1. PONTOS E RETAS NO OPENGL 1.1 – Sistemas Gráficos Uma imagem gráfica é formada por uma matriz de elementos denominados pixels. Os pixels são armazenados em uma porção da memória denominada Frame Buffer.

0,0 1,0 2,0 …

0,1 1,1 2,1 …

A resolução do frame buffer corresponde ao número de pixels que ele representa e varia conforme a placa gráfica disponível. As resoluções básicas encontradas são:

640 x 480 800 x 600

1024 x 768 1280 x 1024

1.2 – Cores A profundidade do frame buffer corresponde ao número de bits presentes para cada pixel e através do qual fica estabelecido, por exemplo, o número de cores que podem ser representados em cada pixel. O número de cores possíveis varia conforme o hardware. Cada pixel tem uma mesma quantidade de memória para armazenar suas cores. O buffer de cores (Color Buffer) é uma porção da memória reservada para armazenar as cores em cada pixel. Um buffer de 8 bits pode exibir 256 cores diferentes simultaneamente. Conforme a capacidade da placa gráfica podemos ter:

8 bits – 256 cores

(High Color) 16 bits – 65.536 cores

(True Color) 24 bits – 16.777.216 cores

(True Color) 32 bits – 4.294.967.296 cores

Existem duas formas básicas de acessar as cores no OpenGL: RGB e Modo Indexado. Trabalharemos sempre em formato RGB. No formato RGB você deve informar as intensidades de Vermelho, Verde e Azul. Estas intensidades devem variar entre 0,0 a 1.0. A tabela abaixo mostra como obter as cores básicas:

Cores R G B Vermelho 1.0 0.0 0.0 Verde 0.0 1.0 0.0 Azul 0.0 0.0 1.0 Amarelo 1.0 1.0 0.0 Cyan 0.0 1.0 1.0 Magenta 1.0 0.0 1.0 Branco 1.0 1.0 1.0 Preto 0.0 0.0 0.0

Page 45: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

4

1.3 – Introdução ao OpenGL O sistema gráfico OpenGL (GL significa Graphics Library) é uma biblioteca (de aproximadamente 350 funções) para aplicações gráficas. O OpenGL foi desenvolvido pela Silicon Graphics (SGI) voltado para aplicações de computação gráfica 3D, embora possa ser usado também em 2D. As funções permitem a geração de primitivas (pontos, linhas, polígonos, etc.) e utilizar recursos de iluminação. O OpenGL é independente do sistema de janelas, ou seja, suas funções não especificam como manipular janelas. Isto permite que o OpenGL possa ser implementado para diferentes sistemas: Linux, Windows, Mac OS X, etc. 1.4 – Funções Básicas O código abaixo cria uma janela gráfica. #include <gl\glut.h> void display() { } void main(int argc, char **argv) { glutInit(&argc,argv); glutCreateWindow("Ponto"); glutDisplayFunc(display); glutMainLoop(); } Vamos comentar função a função: 1) glutInit(&argc,argv); Esta função é utilizada para iniciar a biblioteca GLUT. 2) glutCreateWindow("Ponto"); Cria uma janela para o OpenGL com o nome: Ponto 3) glutDisplayFunc(display); Esta função registra que a função void display() será a função a ser chamada sempre que a janela gráfica necessita ser atualizada. 4) glutMainLoop(); Inicia o gerenciamento de eventos, aguardando que algum evento seja acionado. O próximo passo é gerar uma primeira saída gráfica. Para isso, precisamos implementar o código desejado na função display(). No exemplo, ilustramos como acender o pixel central na cor vermelha. #include <gl\glut.h> void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); glVertex2f(0.0,0.0); glEnd(); glFlush(); glutSwapBuffers(); }

Page 46: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

5

Quando a função display é chamada temos o seguinte resultado: glClearColor(0.0,0.0,0.0,0.0); Indica a cor para ser utilizada no fundo da janela. glClear(GL_COLOR_BUFFER_BIT); Limpa o buffer indicado com a cor do glClearColor() glColor3f(1.0,0.0,0.0); Define o vermelho como cor atual. glBegin(GL_POINTS); glVertex2f(0.0, 0.0); glEnd(); Inicialmente a janela gráfica está definida para valores no intervalo [-1,1], tanto em x quanto em y. Assim a função glVertex2f(0.0, 0.0) acende o pixel na posição do centro glFlush(); Envia uma solicitação que o conteúdo do Frame Buffer seja exibido. Podemos alterar as configurações iniciais da janela gráfica: #include <gl\glut.h> void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); glVertex2f(0.0,0.0); glEnd(); glFlush(); glutSwapBuffers(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(400,400); glutInitWindowPosition(1,1); glutCreateWindow("Ponto"); glutDisplayFunc(display); glutMainLoop(); } glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); Quando uma janela é criada, seu tipo é determinado pelo Display Mode. O tipo da janela inclui um conjunto de características desejadas. Neste caso temos três: GLUT_DOUBLE: Buffer duplo GLUT_RGBA...: Modelo de representação das cores. GLUT_DEPTH.: Buffer de profundidade (utilizado em remoção de superfícies escondidas). glutInitWindowSize(400,400); Indica o tamanho da janela a ser aberta (em pixels). glutInitWindowPosition(1,1); Indica a posição inicial da janela. glutSwapBuffers(); Troca os buffers (duplo buffer)

Page 47: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

6

Exercícios:

1) Comente as seguintes linhas na função display e veja o resultado: glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 2) Acrescente um contador para verificar quantas vezes a função display é chamada.

void display() { static int i = 0; glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); glVertex2f(200.0,200.0); glEnd(); glFlush(); cout << i++ << endl; } 3) Comente a seguinte linha do código e veja o resultado. glutDisplayFunc(display);

1.5 – gluOrtho2D Na maioria de nossas aplicações desejamos nos referenciar a um ponto na janela, não por coordenadas correspondendo as dimensões informadas na função glutInitWindowSize(), mas sim levando-se em conta o domínio de visualização relacionado ao problema. Para isso, a função gluOrtho2D() realiza a mudança para o sistema de coordenadas desejado. Esta tarefa é realizada fazendo a correspondência entre os intervalos em questão:

Assim:

e segue que

e identicamente para a coordenada y: .

O programa abaixo ilustra o efeito do gluOrttho2D. #include <iostream> using namespace std; #include <gl\glut.h> const int DIMX = 400; const int DIMY = 600; float xmin = -1; float xmax = 1; float ymin = -1; float ymax = 1; void converte(float L,float R,float T,float B,float& x,float& y) { /* Faz a funcao do glOrtho */ x = ((x - L)/(R-L) * DIMX); y = ((y - B)/(T-B) * DIMY); }

Page 48: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

7

void display() { float x = 0.5; /* Ponto que gostariamos de converter */ float y = 0.5; converte(xmin,xmax,ymin,ymax,x,y); cout << "x= " << x << " y= " <<y << endl; glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); glVertex2f(x,y); glEnd(); glFlush(); glutSwapBuffers(); } int main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(DIMX,DIMY); glutInitWindowPosition(50,50); glutCreateWindow("Ortho"); gluOrtho2D(0,DIMX-1,DIMY-1,0);/* Matriz de pontos DIMx x DIMy */ glutDisplayFunc(display); glutMainLoop(); } 1.6 – Exemplo: Plotar uma reta unindo dois pontos Como exemplo vamos desenhar uma reta (não vertical) unindo dois pontos (x0,y0) e (x1,y1). A equação da reta que passa por dois pontos é:

1.6.1 – Algoritmo ingênuo

A primeira idéia de como resolver este problema é proposto pelo programa abaixo. Este é um exemplo ingênuo de como desenhar a reta que passa por dois pontos dados. Vamos discutir a seguir os principais problemas deste programa e as possíveis soluções.

* -------------------------------------------------------------- */ /* Exemplo ingenuo de como plotar a reta definida por dois pontos */ /* -------------------------------------------------------------- */ #include <gl\glut.h> #include <iostream> using namespace std; float x0,y0,x1,y1; void display() {

Page 49: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

8

float x,y; glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); for (x = x0;x <= x1;x+=0.001) { y = (y1-y0)/(x1-x0)*(x-x0) +y0; glVertex2f(x,y); } glEnd(); glFlush(); glutSwapBuffers(); } void main(int argc, char **argv) { cout << "x0 = "; cin >> x0; cout << "y0 = "; cin >> y0; cout << "x1 = "; cin >> x1; cout << "y1 = "; cin >> y1; glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Reta"); gluOrtho2D(-3,3,-3,3); glutDisplayFunc(display); glutMainLoop(); }

Algumas desvantagens do programa proposto: 1) Este método requer operações em ponto flutuante (float ou double) para cada pixel. Isto acarreta

em um algoritmo lento, se comparado a um algoritmo que opera somente com números inteiros. Para o caso da reta, existe um tal algoritmo que utiliza somente aritmética com números inteiros. Este algoritmo foi desenvolvido por Jack E. Bresenham na década de 60 e será descrito adiante.

2) O usuário estabelece o número de pontos da reta a serem plotados entre os dois pontos. Podem ocorrer dois casos: faltarem pontos (a reta fica pontilhada), sobrarem pontos (neste caso o algoritmo faz contas desnecessárias). O ideal é o próprio programa se encarregar de determinar o número de pontos necessários e suficientes para resolver o problema.

3) O caso particular da reta vertical (onde K é constante) não pode ser plotado.

1.6.2 – Retas no Opengl O OpenGL dispõe em sua biblioteca interna de uma função que plota uma reta por dois pontos dados. Esta função é descrita abaixo:

Page 50: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

9

void display() { float x,y; glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex2f(x0,y0); glVertex2f(x1,y1); glEnd(); glFlush(); }

1.7 – Exemplo: Plotar o gráfico de uma função Vamos começar com uma versão bem simplificada, para plotar o gráfico de uma função y=f(x).

#include <gl\glut.h> float funcao(float x) { return(x*x); } void display() { float x,y,dx; glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,0.0,0.0); dx = 0.02; x = -1; for(int i = 0;i < 100;i++) { y = funcao(x); glBegin(GL_POINTS); glVertex2f(x,y); glEnd(); x += dx; } glutSwapBuffers(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); gluOrtho2D(-1,1,-1,1); glutDisplayFunc(display); glutMainLoop(); }

Page 51: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

10

Em seguida vamos definir a classe função: funcao.h

#include <cmath> class funcao { int pontos; float xmin,xmax,ymin,ymax; public: funcao(int p = 300,float xm = -1,float xM = 1); float f(float x) { return(sin(x)); } void dominio(); void plota_funcao(); };

funcao.cpp

#include <gl\glut.h> #include "funcao.h" #include <iostream> using namespace std; funcao::funcao(int p ,float xm ,float xM) { pontos = p; xmin = xm; xmax = xM; } void funcao::dominio() { cout << "xmin = "; cin >> xmin; cout << "xmax = "; cin >> xmax; } void funcao::plota_funcao() { float dx; float x, y; dx = (xmax - xmin)/pontos; glColor3f (1.0, 0.0, 0.0); x = xmin; for (int i = 0; i < pontos; i++) { y = f(x); glBegin ( GL_POINTS); glVertex2f (x,y); glEnd(); x = x + dx; } }

Page 52: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

11

main.cpp #include <gl\glut.h> #include <cmath> #include "funcao.h" float L = -5; float R = 5; float B = -5; float T = 5; funcao f(400,L,R); void plota_eixo() { glColor3f (0.0, 1.0, 0.0); glBegin (GL_LINES); glVertex2f (L,0); glVertex2f (R,0); glVertex2f (0,B); glVertex2f (0,T); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixo(); f.plota_funcao(); glFlush(); glutSwapBuffers(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); gluOrtho2D(L,R,B,T); glutMainLoop(); }

1.8 – Fontes Utilizando o glut é possível incluir textos na visualização do gráficos. Para isso precisamos de duas funções: glRasterPos2f(float x, float y); Define a posição inicial do texto, glutBitmapCharacter(void *font, int character); Define a fonte e o caracter a ser exibido.

Page 53: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

12

Assim podemos, no exemplo do gráfico, incluir variáveis que indiquem os eixos e pontos no nosso gráfico. main.cpp void display_fontes(float x,float y,void *tipo_fonte,char *texto) // font = GLUT_BITMAP_9_BY_15 // GLUT_BITMAP_8_BY_13 // GLUT_BITMAP_HELVETICA_10 // GLUT_BITMAP_HELVETICA_14 { glRasterPos2f(x, y); for (int i = 0; texto[i] != '\0'; i++) { glutBitmapCharacter((tipo_fonte, texto[i]); } } void plota_eixo() { glColor3f (1, 1, 1); display_fontes(4.7,-0.3,GLUT_BITMAP_HELVETICA_12,"x"); display_fontes(0.1, 4.7,GLUT_BITMAP_HELVETICA_12,"y"); display_fontes(0.1,-0.3,GLUT_BITMAP_HELVETICA_12,"0"); glColor3f (0, 1, 0); glBegin (GL_LINES); glVertex2f (w.getL(),0); glVertex2f (w.getR(),0); glEnd(); glBegin (GL_LINES); glVertex2f (0,w.getB()); glVertex2f (0,w.getT()); glEnd(); } . . .

Page 54: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

13

2. TECLADO E MOUSE(Callbacks) 2.1 – Introdução O usuário pode interagir com o programa de duas formas principais: através do Mouse ou Teclado. Para isso o GLUT dispõe de dois tipos de funções (que denominamos Callbacks) específicas para habilitar a utilização do teclado e do mouse. Vamos descrevê-las a seguir. 2.2 – Teclado Para registrar ocorrências no teclado o GLUT dispõe da função: void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)) Esta função determina que quando uma tecla for pressionada, o controle do programa deve passar a função definida no campo (*func) e esta função receberá como parâmetros de entrada, a tecla pressionada (unsigned char key), e a posição do mouse (int x, int y). O exemplo abaixo exemplifica uma aplicação para o programa funções.

2.2.1 – Exemplo: Utilização do teclado no programa funções Como exemplo vamos acrescentar no programa funções a possibilidade de alterarmos o domínio da função durante a execução do programa. Assim podemos estabelecer que quando o usuário pressionar a tecla “D” ou “d”, o programa interrompe e solicita as novas informações sobre o domínio da função. main.cpp #include <gl\glut.h> #include <cmath> #include "funcao.h" #include <iostream> using namespace std; float L = -5; float R = 5; float B = -5; float T = 5; funcao f(400,L,R); void plota_eixo() { glColor3f (0.0, 1.0, 0.0); glBegin (GL_LINES); glVertex2f (L,0); glVertex2f (R,0); glVertex2f (0,B); glVertex2f (0,T); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixo(); f.plota_funcao(); glFlush(); glutSwapBuffers(); } void teclado(unsigned char key, int x, int y)

Page 55: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

14

{ switch(key) { case 'D': case 'd': f.dominio(); glutPostRedisplay(); break; case 'W': case 'w': cout << "L = "; cin >> L; cout << "R = "; cin >> R; cout << "B = "; cin >> B; cout << "T = "; cin >> T; glLoadIdentity(); gluOrtho2D(L,R,B,T); glutPostRedisplay(); break; } } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); gluOrtho2D(L,R,B,T); glutMainLoop(); } 2.3 – Mouse O GLUT é capaz de obter três tipos de ocorrências diferentes a partir do mouse. Vamos descrevê-las em seguida e discutir uma interessante aplicação para o estudo de gráficos de funções.

2.3.1 – Interrupções a partir do mouse a) glutMouseFunc void glutMouseFunc(void (*func)(int button, int state, int x, int y)) Este evento detecta quando algum botão do mouse foi pressionado. Quando isto ocorre, o programa executa a rotina definida em void (*func). Os parâmetros desta rotina podem receber os seguintes valores: - button : informa qual botão do mouse foi pressionado, sendo atribuído com um dos seguintes

valores: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON. - state: informa quando o botão foi pressionado e quando o botão foi solto, sendo atribuído com

dois possíveis valores: GLUT_DOWN ou GLUT_UP. - x,y: informa a posição do mouse quando o botão foi pressionado. Para ilustrar essa interrupção, alteramos o main.cpp e acrescentamos outra forma de interrupção para alterar o domínio. Assim se o usuário pressionar o botão direito do mouse, o programa solicita no console o novo domínio de visualização. Se pressionar o botão esquerdo, o programa informa em qual coordenada da tela o mouse se encontra.

Page 56: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

15

#include <gl\glut.h> #include <cmath> #include "funcao.h" #include <iostream> using namespace std; float L = -5; float R = 5; float B = -5; float T = 5; funcao f(400); void plota_eixo() { glColor3f (0.0, 1.0, 0.0); glBegin (GL_LINES); glVertex2f (L,0); glVertex2f (R,0); glVertex2f (0,B); glVertex2f (0,T); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixo(); f.plota_funcao(); glFlush(); glutSwapBuffers(); } void window_dimension() { cout << "L = "; cin >> L; cout << "R = "; cin >> R; cout << "B = "; cin >> B; cout << "T = "; cin >> T; glLoadIdentity(); gluOrtho2D(L,R,B,T); } void teclado(unsigned char key, int x, int y) { switch(key) { case 'D': case 'd': f.dominio(); glutPostRedisplay(); break; case 'W': case 'w': window_dimension(); glutPostRedisplay(); break; } } void botao_mouse(int b,int state,int x, int y) { switch(b) { case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) { window_dimension(); glutPostRedisplay(); } break; case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) cout << "Botão esquerdo pressionado: x = " << x << " y = " << y << endl; else if (state == GLUT_UP) cout << "Botão esquerdo solto: x = " << x << " y = " << y << endl; break;

Page 57: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

16

} } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); glutMouseFunc(botao_mouse); gluOrtho2D(L,R,B,T); glutMainLoop(); } b) glutMotionFunc void glutMotionFunc(void (*func)(int x, int y)) Este evento detecta o movimento do mouse enquanto algum botão do mouse está pressionado. Quando isto ocorre, o programa executa a rotina definida em void (*func) e informa em x,y a posição do mouse na janela. No exemplo abaixo, a rotina botao_movimento_mouse(int x, int y) imprime a posição do mouse enquanto mantemos um de seus botões pressionados. . . . void botao_movimento_mouse(int x, int y) { cout << "Botao+movimento x = " << x << " y = " << y << endl; } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); glutMouseFunc(botao_mouse); glutMotionFunc(botao_movimento_mouse); gluOrtho2D(L,R,B,T); glutMainLoop(); } c) glutPassiveMotionFunc void glutPassiveMotionFunc(void (*func)(int x, int y)) Este evento detecta o movimento do mouse quanto nenhum botão do mouse está pressionado. Quando isto ocorre, o programa executa a rotina definida em void (*func) e informa em x,y a posição do mouse na janela. No exemplo abaixo, a rotina movimento_mouse(int x, int y) imprime a posição do mouse quando movimentamos o mouse dentro da janela OpenGL.

Page 58: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

17

. . . void movimento_mouse(int x, int y) { cout << "Movimento x = " << x << " y = " << y << endl; } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); glutMouseFunc(botao_mouse); glutMotionFunc(botao_movimento_mouse); glutPassiveMotionFunc(movimento_mouse); gluOrtho2D(L,R,B,T); glutMainLoop(); }

2.3.2 – Aplicações: Realizando o “zoom” do gráfico No processo de visualização das funções, ou mesmo da integração numérica, muitas vezes desejamos alterar o domínio do nosso gráfico. Para isso selecionamos a tecla “D” e “d” como uma interrupção do teclado para que pudéssemos informar o novo domínio. Uma forma mais ágil seria selecionar com o mouse interativamente um retângulo que gostaríamos de visualizar. É o que faremos no próximo programa. Para isso utilizaremos as interrupções do mouse para selecionarmos a região desejada. Quando o botão direito do mouse é pressionado, marcamos o ponto inicial da região. Enquanto o mouse está em movimento (com o botão direito pressionado), desenhamos o retângulo desejado. Quando o botão do mouse é solto, obtemos o ponto final da região e atualizamos o domínio da função. Observe que as coordenadas obtidas pelos eventos do mouse precisam ser convertidas para o sistma de coordendas indicado nos parâmetros da janela de visualização. Para isso, basta considerarmos a transformação inversa a aplicada na seção 1.5:

e segue que

e identicamente para a coordenada y. funcao.h #include <cmath> class funcao { int pontos; float xmin,xmax; public: funcao(int p = 300,float xm = -1,float xM = 1);

Page 59: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

18

float get_xmin() { return xmin; } float get_xmax() { return xmax; } void set_dominio(float x,float y); float f(float x) { return(sin(x)); } void dominio(); void plota_funcao(); }; funcao.cpp #include <gl\glut.h> #include "funcao.h" #include <iostream> using namespace std; funcao::funcao(int p ,float xm ,float xM) { pontos = p; xmin = xm; xmax = xM; } void funcao::dominio() { cout << "xmin = "; cin >> xmin; cout << "xmax = "; cin >> xmax; } void funcao::set_dominio(float xi,float xf) { xmin = xi; xmax = xf; } void funcao::plota_funcao() { float dx; float x, y; dx = (xmax - xmin)/pontos; glColor3f (1.0, 0.0, 0.0); x = xmin; glBegin ( GL_POINTS); for (int i = 0; i < pontos; i++) { y = f(x); glVertex2f (x,y); x = x + dx; } glEnd(); } window.h class window { float L,R,B,T; public: window(float L = -1,float R = 1,float B = -1,float T = 1);

Page 60: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

19

float getL() { return(L); } float getR() { return(R); } float getB() { return(B); } float getT() { return(T); } void set(); void set_window (int xv_1,int yv_1,int xv_2,int yv_2,int DIMX,int DIMY) ; void plota_retangulo(int xv0,int yv0,int xv1,int yv1,int DIMX,int DIMY); }; window.cpp #include <gl\glut.h> #include <iostream> using namespace std; #include "window.h" window::window(float Left,float Right,float Bottom,float Top) { L = Left; R = Right; B = Bottom; T = Top; } static float converte(int p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); } void window::set_window (int xv_1,int yv_1,int xv_2,int yv_2, int DIMX,int DIMY) { float xmin1,xmax1; float ymin1,ymax1; xmin1 = converte(xv_1,L,R,DIMX); xmax1 = converte(xv_2,L,R,DIMX); L = xmin1; R = xmax1; ymin1 = converte(yv_2,T,B,DIMY); ymax1 = converte(yv_1,T,B,DIMY); B = ymin1; T = ymax1; glLoadIdentity(); gluOrtho2D(L,R,B,T); } void window::set() { cout << "L = "; cin >> L; cout << "R = "; cin >> R; cout << "B = "; cin >> B; cout << "T = "; cin >> T; glLoadIdentity(); gluOrtho2D(L,R,B,T); }

Page 61: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

20

void window::plota_retangulo(int xv0,int yv0,int xv1,int yv1, int DIMX,int DIMY) { float t; float retxmin,retxmax,retymin,retymax; retxmin = converte(xv1,L,R,DIMX); retxmax = converte(xv0,L,R,DIMX); retymin = converte(yv0,T,B,DIMY); retymax = converte(yv1,T,B,DIMY); glColor3f(1.0,1.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(retxmin,retymin); glVertex2f(retxmin,retymax); glVertex2f(retxmax,retymax); glVertex2f(retxmax,retymin); glEnd(); } main.cpp #include <gl\glut.h> #include <cmath> #include "funcao.h" #include "window.h" #include <iostream> using namespace std; const int DIMX = 400; const int DIMY = 400; window w(-5,5,-5,5); funcao f(400,w.getL(),w.getR()); int mov = 0; /* Detecta o movimento do mouse */ int xv1,xv2,yv1,yv2; /* Domínio da nova janela */ void plota_eixo() { glColor3f (0.0, 1.0, 0.0); glBegin (GL_LINES); glVertex2f (w.getL(),0); glVertex2f (w.getR(),0); glVertex2f (0,w.getB()); glVertex2f (0,w.getT()); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixo(); f.plota_funcao(); if (mov == 1) w.plota_retangulo(xv1,yv1,xv2,yv2,DIMX,DIMY); glFlush(); glutSwapBuffers(); }

Page 62: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

21

void teclado(unsigned char key, int x, int y) { switch(key) { case 'D': case 'd': f.dominio(); glutPostRedisplay(); break; case 'W': case 'w': w.set(); glutPostRedisplay(); break; } } void botao_mouse(int b,int state,int x, int y) { switch(b) { case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) { xv1 = x; yv1 = y; mov = 1; } else if (state == GLUT_UP) { xv2 = x; yv2 = y; mov = 0; w.set_window(xv1,yv1,xv2,yv2,DIMX,DIMY); f.set_dominio(w.getL(),w.getR()); glutPostRedisplay(); } break; case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) cout << "Botao esquerdo pressionado em: x = " << x << " y = " << y << endl; else if (state == GLUT_UP) cout << "Botao esquerdo solto em: x = " << x << " y = " << y << endl; break; } } void botao_movimento_mouse(int x, int y) { xv2 = x; yv2 = y; glutPostRedisplay(); } void window_size(int dimx,int dimy) { DIMX = dimx; DIMY = dimy; }

Page 63: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

22

void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(DIMX,DIMY); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); glutMouseFunc(botao_mouse); glutMotionFunc(botao_movimento_mouse); glutReshapeFunc(window_size); gluOrtho2D(w.getL(),w.getR(),w.getB(),w.getT()); glutMainLoop(); }

2.3.3 – Aplicações: Pilha Em uma segunda versão gostariamos de voltarmos ao domínio original. Para isso, precisamos armazenar as alterações anteriores do domínio. Uma estrutura adequada para esta situação seria montar uma pilha. O exemplo abaixo ilustra a implementação de uma classe Pilha e sua aplicação no exemplo de zoom. Stack.h #ifndef STACK_H #define STACK_H #include "window.h" #include <cstdlib> struct Node { window a ; Node* next; }; class Stack { Node* top; public: Stack(); void push(window& b); window pop(); bool Empty(); int size(); window peek(); }; #endif Stack.cpp #include "Stack.h" #include <cstdio> Stack::Stack() { top = NULL; } void Stack::push(window& b) { Node* new_top = new Node; new_top->a = b;

Page 64: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

23

new_top->next = top; top = new_top; } window Stack::pop() { Node *remove; window a = top->a; remove = top; top = top->next; delete remove; return a; } bool Stack::Empty() { if (top == NULL) return (true); else return(false); } int Stack::size() { int i = 0; Node *n; for(n = top; n != NULL; n = n->next) i++; return(i); } window Stack::peek() { return (top->a); } Na classe window foram incluídas funções para auxiliar no empilhamento das coordenadas. window.h #ifndef WINDOW_H #define WINDOW_H class window { float L,R,B,T; public: window(float L = -1,float R = 1,float B = -1,float T = 1); window(window& a); float getL() { return(L); } float getR() { return(R); } float getB() { return(B); } float getT() { return(T); } void set_window (); void set_window (int xv_1,int yv_1,int xv_2,int yv_2,int DIMX,int DIMY) ; void set_window (window& a); void plota_retangulo(int xv0,int yv0,int xv1,int yv1,int DIMX,int DIMY);

Page 65: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

24

}; #endif window.cpp #include <gl\glut.h> #include <iostream> using namespace std; #include "window.h" window::window(float Left,float Right,float Bottom,float Top) { L = Left; R = Right; B = Bottom; T = Top; } window::window(window& a) { L = a.L; R = a.R; B = a.B; T = a.T; } static float converte(int p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); } void window::set_window (int xv_1,int yv_1,int xv_2,int yv_2, int DIMX,int DIMY) { float xmin1,xmax1; float ymin1,ymax1; xmin1 = converte(xv_1,L,R,DIMX); xmax1 = converte(xv_2,L,R,DIMX); L = xmin1; R = xmax1; ymin1 = converte(yv_2,T,B,DIMY); ymax1 = converte(yv_1,T,B,DIMY); B = ymin1; T = ymax1; glLoadIdentity(); gluOrtho2D(L,R,B,T); } void window::set_window (window& a) { L = a.L; R = a.R; B = a.B; T = a.T; glLoadIdentity(); gluOrtho2D(L,R,B,T); }

Page 66: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

25

void window::set_window() { cout << "L = "; cin >> L; cout << "R = "; cin >> R; cout << "B = "; cin >> B; cout << "T = "; cin >> T; glLoadIdentity(); gluOrtho2D(L,R,B,T); } void window::plota_retangulo(int xv0,int yv0,int xv1,int yv1, int DIMX,int DIMY) { float t; float retxmin,retxmax,retymin,retymax; retxmin = converte(xv1,L,R,DIMX); retxmax = converte(xv0,L,R,DIMX); retymin = converte(yv0,T,B,DIMY); retymax = converte(yv1,T,B,DIMY); glColor3f(1.0,1.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(retxmin,retymin); glVertex2f(retxmin,retymax); glVertex2f(retxmax,retymax); glVertex2f(retxmax,retymin); glEnd(); } No main.cpp armazena-se a cada mudança de janela, o novo dominio. Também é preciso inserir na interrupção do botão esquerdo do mouse, a função que retorna o dominio anterior. main.cpp #include <gl\glut.h> #include "funcao.h" #include "window.h" #include "Stack.h" #include <iostream> using namespace std; int DIMX = 400; int DIMY = 400; window w(-5,5,-5,5); funcao f(400,w.getL(),w.getR()); Stack P; int mov = 0; /* Detecta o movimento do mouse */ int xv1,xv2,yv1,yv2; /* Domínio da nova janela */ void plota_eixo() { glColor3f (0.0, 1.0, 0.0); glBegin (GL_LINES); glVertex2f (w.getL(),0);

Page 67: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

26

glVertex2f (w.getR(),0); glVertex2f (0,w.getB()); glVertex2f (0,w.getT()); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixo(); f.plota_funcao(); if (mov == 1) w.plota_retangulo(xv1,yv1,xv2,yv2,DIMX,DIMY); glFlush(); glutSwapBuffers(); } void teclado(unsigned char key, int x, int y) { switch(key) { case 'D': case 'd': f.dominio(); glutPostRedisplay(); break; case 'W': case 'w': w.set_window(); glutPostRedisplay(); break; } } void botao_mouse(int b,int state,int x, int y) { switch(b) { case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) { xv1 = x; yv1 = y; mov = 1; } else if (state == GLUT_UP) { xv2 = x; yv2 = y; mov = 0; if ((xv1 != xv2) && (yv1 != yv2)) { P.push(w); w.set_window(xv1,yv1,xv2,yv2,DIMX,DIMY); f.set_dominio(w.getL(),w.getR()); glutPostRedisplay(); } } break; case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { cout << "Botao esquerdo pressionado em: x = " << x << " y = " << y << endl; if (!P.Empty()) {

Page 68: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

27

w.set_window(P.pop()); f.set_dominio(w.getL(),w.getR()); } glutPostRedisplay(); } else if (state == GLUT_UP) cout << "Botao esquerdo solto em: x = " << x << " y = " << y << endl; break; } } void botao_movimento_mouse(int x, int y) { xv2 = x; yv2 = y; glutPostRedisplay(); } void window_size(int dimx,int dimy) { DIMX = dimx; DIMY = dimy; } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(DIMX,DIMY); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); glutMouseFunc(botao_mouse); glutMotionFunc(botao_movimento_mouse); glutReshapeFunc(window_size); gluOrtho2D(w.getL(),w.getR(),w.getB(),w.getT()); glutMainLoop(); } Exercício: Ajuste a função void window::set_window (int xv_1,int yv_1,int xv_2,int yv_2,int DIMX,int DIMY) de forma que o zoom seja aplicado corretamente independente do ponto inicial ou final.

Page 69: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

28

3. RETAS E POLÍGONOS NO OPENGL 3.1 – Primitivas Além de pontos e retas, o OpenGL possui no total 10 tipos de primitivas úteis. Todos os modelos da tabela abaixo devem ser utilizados iniciando com glBegin(...) e finalizando com glEnd(...), por exemplo para o GL_LINES temos: glBegin(GL_LINES); glVertex2f(1.0,1.0); glVertex2f(1.0,2.0); glVertex2f(2.0,-2.0); ... glEnd(); GL_POINTS Pontos individuais. GL_LINES Reta entre dois pontos. GL_POLYGON Polígono convexo . GL_TRIANGLES Tripla de vértices é interpretado como um triângulo. GL_QUADS Conjunto de quatro vértices interpretado como

quadrilátero. GL_LINE_STRIP Sequência de retas. GL_LINE_LOOP Idêntico ao anterior, porém com uma reta unindo o

primeiro e último vértice. GL_TRIANGLE_STRIP Lista de triângulos. GL_TRAINGLE_FAN Lista de triângulos com o primeiro vértice em

comum. GL_QUAD_STRIP Lista de quadriláteros.

Page 70: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

29

3.2 – Exemplo: Visualização de Métodos Numéricos de Integração Como exemplo de aplicação dos novos objetos vamos visualizar o métodos numérico de integração do ponto a esquerda, apresentado no capítulo 1. Partindo do código já implementado para visualização de funções, foram acrescentados a classe integral e o código main.cpp foi alterado para incluir a nova classe. Integral.h #include "funcao.h" class integral { float a; float b; funcao f; int particao; int metodo; // 0 - ponto a esquerda // 1 - trapezio // 2 - Simpson public: integral(float xi,float xf,funcao g,int part = 10,int met = 0) { a = xi; b = xf; f = g; particao = part; metodo = met ; } void inc_particao() { particao++; } void dec_particao() { particao = (particao == 1) ? 1 : --particao; } void plota_integral_esquerda(); float integral_esquerda(); };

Integral.cpp #include <gl/glut.h> #include "integral.h" void integral::plota_integral_esquerda() { float x,y; float dx; dx = (b-a)/particao; x = a; for(int i=0; i < particao; i++) {

Page 71: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

30

y = f.f(x); glColor3f(0.0f,0.0f,1.0f); glBegin(GL_POLYGON); glVertex2f(x,y); glVertex2f(x+dx,y); glVertex2f(x+dx,0); glVertex2f(x,0); glEnd(); glColor3f(1.0f,1.0f,0.0f); glBegin(GL_LINE_LOOP); glVertex2f(x,y); glVertex2f(x+dx,y); glVertex2f(x+dx,0); glVertex2f(x,0); glEnd(); x = x+dx; } } float integral::integral_esquerda() { float x; float dx; float soma; dx = (b-a)/particao; x = a; soma = 0; for(int i=0; i < particao; i++) { soma += f.f(x) * dx; x = x+dx; } return(soma); } main.cpp #include <gl\glut.h> #include "funcao.h" #include "integral.h" #include "window.h" #include "Stack.h" #include <iostream> using namespace std; int DIMX = 400; int DIMY = 400; window w(-5,5,-5,5); funcao f(400,w.getL(),w.getR()); integral h(-2,2,f); Stack P; . . . void display()

Page 72: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

31

{ glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT ); plota_eixo(); h.plota_integral_esquerda(); cout << "Integral = " << h.integral_esquerda() << endl; f.plota_funcao(); if (mov == 1) w.plota_retangulo(xv1,yv1,xv2,yv2,DIMX,DIMY); glFlush(); glutSwapBuffers(); } void teclado(unsigned char key, int x, int y) { switch(key) { case 'D': case 'd': f.dominio(); glutPostRedisplay(); break; case 'W': case 'w': w.set_window(); glutPostRedisplay(); break; case '+': h.inc_particao(); glutPostRedisplay(); break; case '-': h.dec_particao(); glutPostRedisplay(); break; } } . . .

Page 73: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

32

4. CURVAS PARAMÉTRICAS 4.1 – Introdução Considere uma curva C representando a trajetória de uma partícula P, de tal forma que a posição P(x,y) da partícula é conhecida em cada instante de tempo t. Assim as coordenadas x e y são conhecidas como funções da variável t de modo que: x = x(t) y = y(t) Estas são as equações paramétricas da curva C e t é denominado parâmetro. Como exemplo de curvas temos: a) Circunferência de centro na origem e raio 1: x = cos(t) y = sen(t) onde 0 <= t <= 2*Pi b) Ciclóide (curva traçada por um ponto da circunferência quando o círculo rola sobre uma reta): x = t - sen(t) y = 1 - cos(t) 4.2 – Exemplo: Visualização de Curvas Paramétricas Vamos implementar um programa que visualize curvas paramétricas. Observe que a diferença principal para o programa funções é que tanto a variável x, quanto y devem ser calculadas em função do parâmetro t. Vamos aproveitar uma boa parte da estrutura já implementada no programa função. curva.h #include <cmath> class curva { int pontos; float tmin,tmax; public: curva(int p = 300,float tm = 0,float tM = 1); float get_tmin() { return tmin; } float get_tmax() { return tmax; } void set_dominio(float tm,float tM); void c(float t,float *v); void dominio(); void plota_curva(); }; curva.cpp #include <gl\glut.h> #include <cmath> #include "curva.h" #include <iostream> using namespace std; curva::curva(int p ,float tm ,float tM) { pontos = p; tmin = tm; tmax = tM; }

Page 74: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

33

void curva::dominio() { cout << "tmin = "; cin >> tmin; cout << "tmax = "; cin >> tmax; } void curva::set_dominio(float ti,float tf) { tmin = ti; tmax = tf; } void::curva::c(float t,float *v) { v[0] = cos(t); v[1] = sin(t); // v[0] = sin(3*t); // v[1] = sin(4*t); // v[0] = (t+sin(t)); // v[1] = (t+cos(t)); // v[0] = t+2*sin(2*t); // v[1] = t+2*cos(5*t); // v[0] = cos(t)-cos(80*t)*sin(t); // v[1] = 2*sin(t)-sin(80*t); // v[0] = 31 * cos(t) - 7 * cos(31.0/7 * t); // v[1] = 31 * sin(t) - 7 * sin(31.0/7 * t); // v[0] = cos(t) + 0.5 * cos(7*t) + 1/3.0 * sin(17*t); // v[1] = sin(t) + 0.5 * sin(7*t) + 1/3.0 * cos(17*t); } void curva::plota_curva() { float t,dt,v[2]; dt = (tmax - tmin)/pontos; glColor3f (1.0, 0.0, 0.0); t = tmin; glBegin ( GL_POINTS); for (int i = 0; i < pontos; i++) { c(t,v); glVertex2f (v[0],v[1]); t = t + dt; } glEnd(); } main.cpp #include <gl\glut.h> #include "curva.h" #include "window.h" #include "Stack.h" #include <iostream> using namespace std; int DIMX = 400; int DIMY = 400;

Page 75: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

34

window w(-5,5,-5,5); curva c(400,0,6.29); Stack P; int mov = 0; /* Detecta o movimento do mouse */ int xv1,xv2,yv1,yv2; /* Domínio da nova janela */ void plota_eixo() { glColor3f (0.0, 1.0, 0.0); glBegin (GL_LINES); glVertex2f (w.getL(),0); glVertex2f (w.getR(),0); glVertex2f (0,w.getB()); glVertex2f (0,w.getT()); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixo(); c.plota_curva(); if (mov == 1) w.plota_retangulo(xv1,yv1,xv2,yv2,DIMX,DIMY); glFlush(); glutSwapBuffers(); } void teclado(unsigned char key, int x, int y) { switch(key) { case 'D': case 'd': c.dominio(); glutPostRedisplay(); break; case 'W': case 'w': w.set_window(); glutPostRedisplay(); break; } } void botao_mouse(int b,int state,int x, int y) { switch(b) { case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) { xv1 = x; yv1 = y; mov = 1; } else if (state == GLUT_UP) { xv2 = x;

Page 76: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

35

yv2 = y; mov = 0; if ((xv1 != xv2) && (yv1 != yv2)) { P.push(w); w.set_window(xv1,yv1,xv2,yv2,DIMX,DIMY); glutPostRedisplay(); } } break; case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { cout << "Botao esquerdo pressionado em: x = " << x << " y = " << y << endl; if (!P.Empty()) { w.set_window(P.pop()); glutPostRedisplay(); } } else if (state == GLUT_UP) cout << "Botao esquerdo solto em: x = " << x << " y = " << y << endl; break; } } void botao_movimento_mouse(int x, int y) { xv2 = x; yv2 = y; glutPostRedisplay(); } void window_size(int dimx,int dimy) { DIMX = dimx; DIMY = dimy; } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(DIMX,DIMY); glutInitWindowPosition(50,50); glutCreateWindow("Funcao"); glutDisplayFunc(display); glutKeyboardFunc(teclado); glutMouseFunc(botao_mouse); glutMotionFunc(botao_movimento_mouse); glutReshapeFunc(window_size); gluOrtho2D(w.getL(),w.getR(),w.getB(),w.getT()); glutMainLoop(); } Exercício Como exercício implemente: 1) x(t) = 3*t*t, y(t)=4*t*t*t (t assume qualquer valor real).

Page 77: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

36

2) x(t) = cos(2*t), y(t)= sin(2*t) (0 <= t <= 2*PI) (Qual a diferença para a curva do programa ?)

3) x(t) = cos(t), y(t)= sin(2*t) 4) x(t) = 2 * cos(t), y(t)= 3 * sin(t) (0 <= t <= 2*PI) . 5) Como você poderia visualizar gráficos de funções em uma variável y = f(x) com este programa

? Visualize y=x*x, y = sin(x), y = ln(x). 6) Visualize o vetor tangente em alguns pontos da curva. 4.3 – Curvas na forma Polar Para formar as coordenadas polares considere um ponto fixo O, denominado origem (ou polo) e um eixo partindo de O, denominado eixo polar. A cada ponto P do plano podemos associar uma par de coordenadas polares (r,theta) onde:

r: distância orientada da origem ao ponto P. theta: ângulo entre o eixo polar e o segmento OP.

. As coordenadas polares podem ser relacionadas com as coordenadas retangulares (ou cartesianas) através das expressões abaixo:

Como exemplo de curvas na forma polar temos: a) Circunferência de centro na origem e raio 1: r = 1 b) Reta passando na origem com coeficiente angular m:

c) Circunferência com centro em P(0, 0.5) e raio 1:

d) Cardióide

e) Espiral

f) Rosácea

Page 78: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

37

4.4 – Exemplo: Visualização de Curvas Polares Para visualizar as curvas polares, podemos utilizar o mesmo programa das curvas paramétricas. Para isso, considere uma curva dada na forma polar:

Em coordenadas cartesianas temos:

Substituindo r nas duas equações obtemos:

Assim temos uma curva na forma paramétrica. Como exemplo vamos visualizar a curva do cardióide, alterando apenas a classe curva do programa anterior: . . . float curva::r(float theta) { float r; r = 1 + cos(theta); return(r); } void::curva::c(float t,float *v) { v[0] = r(t) * cos(t); v[1] = r(t) * sin(t); } . . . Exercícios 1) Como exercício visualize as demais curvas dadas em coordenadas polares. 2) Visualize a curva dada em coordenadas polares por r = sec(theta). 3) Faça o grafico das seguintes curvas:

(a)

(b) (c) (d) (e)

(f)

Page 79: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

38

Page 80: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

39

5. CURVAS IMPLÍCITAS 5.1 – Introdução Já aprendemos na seção 3 como representar curvas na forma paramétrica. Vamos discutir agora outro tipo de representação muito utilizada para curvas: a representação implícita. A equação implícita de uma curva descreve uma relação entre as coordenadas x e y dos pontos que pertencem a curva. Assim no plano xy a equação implícita de uma curva tem a forma :

Como exemplo a representação implícita de uma circunferência de raio 1 centrado na origem é dado por:

Na forma paramétrica a mesma curva é representada por:

Qual das duas representações é mais vantajosa em termos computacionais ? Na verdade ambas representações têm vantagens e desvantagens em comparação uma com a outra. Por exemplo, é muito simples determinar se um ponto dado pertence ou não a uma curva dada na forma implícita. Já na forma paramétrica é simples determinar pontos que pertençam a curva, para que se possa fazer uma representação gráfica da curva (como foi feito na seção anterior). Vamos agora resolver este último problema para uma curva dada na forma implícita, ou seja, vamos representar graficamente a curva implícita. 5.2 – Visualização de Curvas Implícitas Vamos implementar um programa que visualize curvas implícitas. Partindo por exemplo da equação:

Observe que não é simples exibir um conjunto de pontos que pertençam a esta curva. Vamos definir uma função de duas variáveis utilizando a equação acima, da seguinte forma:

Assim a curva inicial desejada, será a curva de nível . A estratégia para obter esta curva será a seguinte: - Vamos estabelecer um domínio no plano como partida (a priori não sabemos se

existem ou não pontos da curva nesse domínio). - Em seguida discretizamos este domínio, determinando uma matriz de 10x10 pontos ,

por exemplo. - A cada três pontos, definimos um triângulo como na figura abaixo. - Para cada ponto calculamos . - Para cada triângulo, observamos os sinais = sinal( ) obtidos em cada vértice e temos as

seguintes situações:

- Se V1 * V2 < 0, então a função se anula em um ponto entre V1 e V2. Este ponto pode ser aproximado linearmente.

- Se V1 * V3 < 0, então a função se anula em um ponto entre V1 e V3.

Page 81: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

40

- Se V2 * V3 < 0, então a função se anula em um ponto entre V2 e V3.

- Se V1 = 0, então a função se anula exatamente sobre o vértice V1.

- Se V2 = 0, então a função se anula exatamente sobre o vértice V2.

- Se V3 = 0, então a função se anula exatamente sobre o vértice V3.

- Considerando que exatamente duas das condições acima se verificaram simultaneamente,

aproximamos a curva nesse triângulo por um segmento de reta unindo os dois pontos obtidos. 5.3 – Programa Curva Implícita O programa mantém a mesma estrutura do programa curva paramétrica, alterando a classe curva, conforme abaixo. curva_implicita.h #include <cmath> class curva_implicita { int pontos; float xmin,xmax,ymin,ymax; public: curva_implicita(int p = 10,float xm = 0,float xM = 1,float ym = 0,float yM = 1); void set_dominio(float xm,float xM,float ym,float yM); void calcula_curva(float* xf,float* yf); float f(float x,float y); void dominio(); void plota_curva(); }; curva_implicita.cpp #include <gl\glut.h> #include <cmath> #include "curva_implicita.h" #include <iostream> using namespace std; curva_implicita::curva_implicita(int p ,float xm ,float xM, float ym,float yM) { pontos = p; xmin = xm; xmax = xM; ymin = ym; ymax = yM; } void curva_implicita::dominio() { cout << "xmin = "; cin >> xmin; cout << "xmax = "; cin >> xmax;

Page 82: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

41

cout << "ymin = "; cin >> ymin; cout << "ymax = "; cin >> ymax; } void curva_implicita::set_dominio(float xi,float xf,float yi,float yf) { xmin = xi; xmax = xf; ymin = yi; ymax = yf; } float curva_implicita::f(float x,float y) { return x*x-y*y-1.3; // return x*x+y*y-1; } void curva_implicita::calcula_curva(float* xf,float* yf) { int j; int i = 0; float t; float x[3],y[3],s[3]; glColor3f(0,0,1); glBegin(GL_LINE_LOOP); glVertex2f(xf[0],yf[0]); glVertex2f(xf[1],yf[1]); glVertex2f(xf[2],yf[2]); glEnd(); for(j=0;j<3;j++) s[j] = f(xf[j],yf[j]); if ((s[0] * s[1]) < 0) { t = -s[0]/(s[1]-s[0]); x[i] = xf[0] + t * (xf[1]-xf[0]); y[i] = yf[0]; i++; } if ((s[0] * s[2]) < 0) { t = -s[0]/(s[2]-s[0]); x[i] = xf[0] ; y[i] = yf[0] + t * (yf[2]-yf[0]); i++; } if ((s[1] * s[2]) < 0) { t = -s[1]/(s[2]-s[1]); x[i] = xf[1] + t * (xf[2]-xf[1]); y[i] = yf[1] + t * (yf[2]-yf[1]); i++; } for(j=0;j<3;j++) { if (s[j] == 0) { x[i] = xf[j]; y[i] = yf[j]; i++; } }

Page 83: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

42

if (i == 2) { glLineWidth(2.0f); glColor3f(1.0f,0.0f,0.0f); glBegin(GL_LINES); glVertex2f(x[0],y[0]); glVertex2f(x[1],y[1]); glEnd(); glLineWidth(1.0f); } } void curva_implicita::plota_curva() { float tx[3]; float ty[3]; float x,y; float dx = (xmax - xmin)/pontos; float dy = (ymax - ymin)/pontos; glColor3f(1.0f,0.0f,0.0f); x = xmin; for(int i=0;i<pontos;i++) { y = ymin; for(int j=0;j<pontos;j++) { tx[0] = x; tx[1] = x + dx; tx[2] = x; ty[0] = y; ty[1] = y; ty[2] = y + dy; calcula_curva(tx,ty); tx[0] = x + dx; tx[1] = x; tx[2] = x + dx; ty[0] = y + dy; ty[1] = y + dy; ty[2] = y; calcula_curva(tx,ty); y += dy; } x += dx; } } Exercício 1) Como exercício implemente as seguintes curvas implícitas:

a) . c) .

b) . d) 2) Implemente no programa uma rotina que imprima simultaneamente varias curvas de nivel de uma mesma função , ou seja . Por exemplo, .

Page 84: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

1

Capítulo III – Aplicações Gráficas 3D........................................................................... 2  1- TRANSFORMAÇÕES DE VISUALIZAÇÃO ...........................................................................2  

1.1 - Introdução ......................................................................................................................................... 2  1.2 – Transformações .............................................................................................................................. 5  1.3 - Comandos de Auxílio ...................................................................................................................... 5  1.4- Exemplo: cubo unitário .................................................................................................................... 6  1.5 - Transformações de Modelagem e Visualização......................................................................... 8  1.6- Projeção Ortográfica ...................................................................................................................... 10  1.7- Ângulos de Euler............................................................................................................................. 10  1.8 - Criando um Ambiente de Visualização 3D ................................................................................ 11  1.9– Comando glLookAt ........................................................................................................................ 14  1.10 – Visualização de gráfico de funções ......................................................................................... 15  

2- ILUMINAÇÃO ..........................................................................................................................18  2.1 – Introdução ...................................................................................................................................... 18  2.2 – Criando Fontes de Luz................................................................................................................. 22  2.3– Selecionando o Modelo de Iluminação ...................................................................................... 23  2.4– Selecionando as Propriedades do Material ............................................................................... 24  2.5 – Visualizando as normais.............................................................................................................. 27  

3-SUPERFÍCIES PARAMÉTRICAS...........................................................................................28  4- SUPERFÍCIES IMPLÍCITAS .................................................................................................32  

4.1 – Introdução ...................................................................................................................................... 32  4.2 – Visualização de Superfícies Implícitas ...................................................................................... 32  4.3 – Implementação.............................................................................................................................. 34  

5- TEXTURA .................................................................................................................................41  5.1 – Introdução ...................................................................................................................................... 41  5.2 – Parâmetros Básicos ..................................................................................................................... 41  5.3 – Aplicação em Superfícies Paramétricas ................................................................................... 43  

6- Curvas de Bezier ........................................................................................................................50  6.1 – Introdução ...................................................................................................................................... 50  

Page 85: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

2

Capítulo III – Aplicações Gráficas 3D 1- TRANSFORMAÇÕES DE VISUALIZAÇÃO 1.1 - Introdução Nosso objetivo nesta seção é descrever a geração de uma imagem bi-dimensional partindo de um objeto tri-dimensional. Para isso vamos partir de um exemplo: um cubo. A idéia é construir algum tipo de visualização deste cubo, que nos transmita a sensação de estar visualizando um objeto 3-dimensional. Vamos considerar o cubo da figura abaixo: As coordenadas dos vértices deste cubo são:

v0 (0,0,0) v4 (0,0,1) v1 (1,0,0) v5 (1,0,1) v2 (1,1,0) v6 (1,1,1) v3 (0,1,0) v7 (0,1,1)

Para visualizar este modelo, uma primeira estratégia seria definir uma projeção de nosso modelo 3D para o bi-dimensional. Cubo.h /* * * * * * * * * * * * * * * * */ /* Modulo: cubo.h */ /* * * * * * * * * * * * * * * * */ class cubo { float P[8][3]; public: cubo(); void inicializa(); void rotaciona_x(double t); void rotaciona_y(double t); void rotaciona_z(double t); void draw_cube(); }; Cubo.cpp /* * * * * * * * * * * * * * * * */ /* Modulo: cubo.cpp */ /* * * * * * * * * * * * * * * * */ #include "cubo.h" #include <gl\glut.h> #include <math.h> #define PI 3.1415926535897932384626433832795 /* -------------------------------- */ cubo::cubo() /* -------------------------------- */ { inicializa(); }

Page 86: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

3

void cubo::inicializa() { P[0][0] = 0; P[4][0] = 0; P[0][1] = 0; P[4][1] = 0; P[0][2] = 0; P[4][2] = 1; P[1][0] = 1; P[5][0] = 1; P[1][1] = 0; P[5][1] = 0; P[1][2] = 0; P[5][2] = 1; P[2][0] = 1; P[6][0] = 1; P[2][1] = 1; P[6][1] = 1; P[2][2] = 0; P[6][2] = 1; P[3][0] = 0; P[7][0] = 0; P[3][1] = 1; P[7][1] = 1; P[3][2] = 0; P[7][2] = 1; } /* -------------------------------- */ void cubo::rotaciona_x(double t) /* -------------------------------- */ { float y,z; for(int i =0; i < 8 ;i++) { y = P[i][1] * cos(t) - P[i][2] * sin(t); z = P[i][1] * sin(t) + P[i][2] * cos(t); P[i][1] = y; P[i][2] = z; } } /* -------------------------------- */ void cubo::rotaciona_y(double t) /* -------------------------------- */ { float x,z; for(int i =0; i < 8 ;i++) { x = P[i][0] * (float) cos(t) - P[i][2] * (float) sin(t); z = P[i][0] * (float) sin(t) + P[i][2] * (float) cos(t); P[i][0] = x; P[i][2] = z; } } /* -------------------------------- */ void cubo::rotaciona_z(double t) /* -------------------------------- */ { float x,y; for(int i =0; i < 8 ;i++) { x = P[i][0] * (float) cos(t) - P[i][1] * (float) sin(t); y = P[i][0] * (float) sin(t) + P[i][1] * (float) cos(t); P[i][0] = x; P[i][1] = y; } } /* -------------------------------- */

Page 87: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

4

void cubo::draw_cube() /* -------------------------------- */ { inicializa(); rotaciona_z(PI / 4); rotaciona_y(PI / 4); rotaciona_z(PI / 6); glBegin(GL_LINE_LOOP); glVertex2f(P[0][0],P[0][1]); glVertex2f(P[1][0],P[1][1]); glVertex2f(P[2][0],P[2][1]); glVertex2f(P[3][0],P[3][1]); glEnd(); glBegin(GL_LINE_LOOP); glVertex2f(P[4][0],P[4][1]); glVertex2f(P[5][0],P[5][1]); glVertex2f(P[6][0],P[6][1]); glVertex2f(P[7][0],P[7][1]); glEnd(); glBegin(GL_LINES); glVertex2f(P[0][0],P[0][1]); glVertex2f(P[4][0],P[4][1]); glVertex2f(P[1][0],P[1][1]); glVertex2f(P[5][0],P[5][1]); glVertex2f(P[2][0],P[2][1]); glVertex2f(P[6][0],P[6][1]); glVertex2f(P[3][0],P[3][1]); glVertex2f(P[7][0],P[7][1]); glEnd(); } Main.cpp /* * * * * * * * * * * * * * * * * */ /* Modulo: Main.cpp */ /* * * * * * * * * * * * * * * * * */ #include <gl\glut.h> #include "cubo.h" cubo p; void redesenha() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); p.draw_cube(); glutSwapBuffers(); } void main(int argc, char **argv) { glutInit(&argc,argv);

Page 88: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

5

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Cube"); glutDisplayFunc(redesenha); glOrtho(-2,2,-2,2,-2,2); glutMainLoop(); } 1.2 – Transformações As transformações necessárias para visualização de uma cena podem ser comparadas ao processo de fotografar uma cena real [OpenGL Guide – pg. 65]: 1. Monte o tripé e aponte a camera para a cena desejada (viewing transformation) 2. Prepare a cena a ser fotografada na posição desejada (modeling transformation). 3. Escolhas a lente certa para a câmera e ajuste o zoom. (projection transformation). 4. Defina os limites da cena que estarão na foto final (viewport transformation). De forma geral podemos dividir as operações necessárias em três grupos: - Transformações (representadas por multiplicação de matrizes) incluindo operações de projeção,

visualização e modelagem. Estas operações incluem rotações, escalas, translações, reflexões, projeções ortográficas e perspectivas.

- Operações de Clipping são responsáveis pela eliminação de objetos que estão fora da janela de visualização.

- Transformações que estabeleçam a correspondência entre as coordenadas e a dimensão da tela (Viewport transformation).

De forma esquemática podemos estabelecer:

Para especificar uma transformação o OpenGL constrói uma matriz 4x4 que representa a transformação desejada. Esta matriz é então multiplicada pelas coordenadas de cada vértice na cena. As transformações de Modelagem e Visualização são combinadas em uma única matriz denominada MODELVIEW matrix. A transformação de projeção é armazenada na PROJECTION matrix. 1.3 - Comandos de Auxílio Antes de iniciar a descrição do mecanismo das transformações acima, apresentaremos um conjunto de comandos de caráter geral. Os comandos a seguir serão úteis durante todas as etapas do processo de modelagem, visualização e Projeção. GlMatrixMode(Glenum tipo);

Page 89: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

6

Este comando especifica a matriz a ser alterada. Existem três argumentos conforme o tipo da matriz: 1) GL_MODELVIEW 2) GL_PROJECTION 3) GL_TEXTURE As transformações subsequentes afetam a matriz especificada. Observe que somente uma matriz pode ser alterada por vez. GlLoadIdentity(void); Este comando carrega a matriz identidade na matriz corrente especificada anteriormente pelo GlMatrixMode. O objetivo é limpar qualquer alteração anterior realizada sobre a matriz. GlLoadMatrix(const TYPE *M); Quando você deseja especificar uma matriz M particular para ser a matriz corrente, utilize o glLoadMatrix(M). GlMultMatrix(const TYPE *M); Este comando multiplica a matriz definida por

pela matriz corrente. 1.4- Exemplo: cubo unitário Antes de detalhar as transformações principais, vamos apresentar um programa exemplo que visualiza o mesmo cubo do exemplo anterior, porem utilizando as transformações do OpenGL. cubo.cpp /* * * * * * * * * * * * * * * * */ /* Modulo: cubo.cpp */ /* * * * * * * * * * * * * * * * */ #include "cubo.h" #include <gl\glut.h> /* -------------------------------- */ cubo::cubo() /* -------------------------------- */ { inicializa(); } void cubo::inicializa() { P[0][0] = 0; P[4][0] = 0; P[0][1] = 0; P[4][1] = 0;

Page 90: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

7

P[0][2] = 0; P[4][2] = 1; P[1][0] = 1; P[5][0] = 1; P[1][1] = 0; P[5][1] = 0; P[1][2] = 0; P[5][2] = 1; P[2][0] = 1; P[6][0] = 1; P[2][1] = 1; P[6][1] = 1; P[2][2] = 0; P[6][2] = 1; P[3][0] = 0; P[7][0] = 0; P[3][1] = 1; P[7][1] = 1; P[3][2] = 0; P[7][2] = 1; } /* -------------------------------- */ void cubo::draw_cube() /* -------------------------------- */ { glColor3f(1.0,1.0,1.0); glBegin(GL_LINE_LOOP); glVertex3f(P[0][0],P[0][1],P[0][2]); glVertex3f(P[1][0],P[1][1],P[1][2]); glVertex3f(P[2][0],P[2][1],P[2][2]); glVertex3f(P[3][0],P[3][1],P[3][2]); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(P[4][0],P[4][1],P[4][2]); glVertex3f(P[5][0],P[5][1],P[5][2]); glVertex3f(P[6][0],P[6][1],P[6][2]); glVertex3f(P[7][0],P[7][1],P[7][2]); glEnd(); glBegin(GL_LINES); glVertex3f(P[0][0],P[0][1],P[0][2]); glVertex3f(P[4][0],P[4][1],P[4][2]); glVertex3f(P[1][0],P[1][1],P[1][2]); glVertex3f(P[5][0],P[5][1],P[5][2]); glVertex3f(P[2][0],P[2][1],P[2][2]); glVertex3f(P[6][0],P[6][1],P[6][2]); glVertex3f(P[3][0],P[3][1],P[3][2]); glVertex3f(P[7][0],P[7][1],P[7][2]); glEnd(); } Main.cpp /* * * * * * * * * * * * * * * * * */ /* Modulo: Main.cpp */ /* * * * * * * * * * * * * * * * * */ #include <gl\glut.h> #include "cubo.h" cubo p; float theta = 45.0; float phi = 135.0; float gama = 0.0; void inicia_config()

Page 91: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

8

{ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2,2,-2,2,-2,2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gama,0,0,1); // eixo x glRotatef(phi,1,0,0); // eixo z glRotatef(theta,0,0,1); // eixo x } void redesenha() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); p.draw_cube(); glutSwapBuffers(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Cube"); glutDisplayFunc(redesenha); inicia_config(); glutMainLoop(); } 1.5 - Transformações de Modelagem e Visualização Existem três tipos de comandos para transformações de modelagem: glTranslate(), glRotate() e glScale(). Vamos descrever abaixo cada uma dessas funções.

1.5.1- Translação void glTranslatef(float x, float y, float z);

Este comando multiplica a matriz corrente por uma matriz que translada o objeto conforme o vetor .

1.5.2- Rotação void glRotatef(float theta, float x, float y, float z); Multiplica a matriz corrente por uma matriz que rotaciona o objeto no sentido anti-horário de theta graus,

na direção do eixo dado pelo vetor .

Page 92: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

9

1.5.3- Escala void glScalef(float x, float y, float z); Este comando realiza transformações de escala e reflexão. Cada ponto x, y e z do objeto é multiplicado pelo correspondente argumento x,y e z.

1.5.4-Exemplo Como exemplo vamos apresentar um programa que executa as três transformações citadas acima. Partindo de um triângulo, desenhamos este triângulo quatro vezes sendo que: - O triângulo vermelho é desenhado sem nenhuma transformação. - O triângulo verde sofreu uma translação. - O triângulo azul sofreu uma rotação. - O triângulo amarelo sofreu uma transformação de escala. #include <gl\glut.h> void draw_triangulo() { glBegin(GL_LINE_LOOP); glVertex3f(0.0,0.0,0.0); glVertex3f(0.5,0.0,0.0); glVertex3f(0.25,0.43,0.0); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,0.0,0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); draw_triangulo(); glColor3f(0.0,1.0,0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef( 0.5, 0.5,0.0); draw_triangulo(); glColor3f(0.0,0.0,1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(45,0.0,0.0,1.0); draw_triangulo(); glColor3f(1.0,1.0,0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glScalef(0.5, 0.5,0.5); draw_triangulo(); glFlush(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50);

Page 93: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

10

glutCreateWindow("Triangulo"); glutDisplayFunc(display); glutMainLoop(); } 1.6- Projeção Ortográfica Em uma projeção ortográfica, nós estabelecemos um volume de visualização (que corresponde a um paralelepípedo retângulo). O objeto só será visualizado se ele estiver contido neste volume. O comando utilizado é: glOrtho(double left, double right, double bottom, double top, double near, double far); 1.7- Ângulos de Euler Um sistema de referência que irá nos auxiliar na montagem do ambiente 3D são ao ângulos de Euler. Os Ângulos de Euler são definidos como três sucessivos ângulos de rotação através do qual definiremos um novo sistema de coordenadas partindo das coordenadas cartesianas. No Opengl o sistema de coordenadas está posicionado conforme o desenho abaixo, onde o eixo x está na posição horizontal, o eixo y na posição vertical e o eixo z está apontando para fora da tela do computador.

A seqüência inicia rotacionando o sistema de coordenadas xyz por um ângulo no sentido anti-horário em torno do eixo z.

Page 94: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

11

Em seguida o sistema de coordenadas resultante é rotacionado em torno do eixo y de graus.

Por fim o sistema de coordenadas sofre uma nova rotação de em torno do eixo z.

Estes três ângulos definem os ângulos de Euler. 1.8 - Criando um Ambiente de Visualização 3D Vamos montar um ambiente para visualização tri-dimensional, através do qual poderemos visualizar nossos objetos 3D.

1.8.1- Módulo Básico de Visualização Como primeiro passo vamos desenhar os três eixos de referencia, mantendo a seguinte escala de cores: - Eixo x: vermelho - Eixo y: verde - Eixo z: azul Uma posição inicial para a visualização pode ser obtida utilizando-se os ângulos theta = 135, phi = 45, gamma=90.

Page 95: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

12

Main.cpp #include <gl\glut.h> float gamma=90.0,phi=45.0,theta=135.0; void draw_eixos() { glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex3f(10.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,1.0,0.0); glBegin(GL_LINES); glVertex3f(0.0,10.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.0,0.0,10.0); glVertex3f(0.0,0.0,0.0); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,1.0,0.0); draw_eixos(); glFlush(); } void inicia_config() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gamma,0.0,0.0,1.0); glRotatef(phi,0.0,1.0,0.0); glRotatef(theta,0.0,0.0,1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2.0,2.0,-2.0,2.0,-10.0,10.0); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Cubo 3D"); glutDisplayFunc(display); inicia_config(); glutMainLoop(); }

Page 96: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

13

1.8.2- Alterando os ângulos de Euler Vamos agora acrescentar a possibilidade de alterar os ângulos com auxílio do mouse. Com o botão Esquerdo do mouse pressionado, quando o mouse anda na direção horizontal, alteramos theta, quando o mouse anda na direção vertical alteramos phi. #include <gl\glut.h> int xm,xb,ym,yb; float gamma=90.0,phi=45.0,theta=135.0; void draw_eixos() { glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex3f(10.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,1.0,0.0); glBegin(GL_LINES); glVertex3f(0.0,10.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.0,0.0,10.0); glVertex3f(0.0,0.0,0.0); glEnd(); } void display() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3f(1.0,1.0,0.0); draw_eixos(); glFlush(); } void inicia_config() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2.0,2.0,-2.0,2.0,-10.0,10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gamma,0.0,0.0,1.0); glRotatef(phi,0.0,1.0,0.0); glRotatef(theta,0.0,0.0,1.0); } void botao_mouse(int b,int state,int x, int y) { switch(b) {

Page 97: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

14

case GLUT_LEFT_BUTTON: switch(state) { case GLUT_DOWN: xb = x; yb = y; break; case GLUT_UP: theta = theta + xm - xb; phi = phi - ym + yb ; break; } break; } } void mov_mouse(int x, int y) { xm = x; ym = y; theta = theta + xm - xb; phi = phi - ym + yb ; inicia_config(); theta = theta - xm + xb; phi = phi + ym - yb; display(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("Cubo 3D"); glutDisplayFunc(display); inicia_config(); glutMouseFunc(botao_mouse); glutMotionFunc(mov_mouse); glutMainLoop(); } 1.9– Comando glLookAt O comando glLookAt é uma alternativa para controlar definir a visualização por três parâmetros: 1) A posição do observador (ox,oy,oz). 2) ,A direção em que o observador está olhando (dx,dy,dz). 3) A posição da camera (px,py,pz). Assim a sintaxe do comando é glLookAt(ox,oy,oz, dx,dy,dz, px,py,pz). Podemos criar interessantes efeitos, movimentando o observador sobre uma curva paramétrica, por exemplo, ou movimentando a fonte de iluminação ao mesmo tempo, etc.

Page 98: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

15

1.10 – Visualização de gráfico de funções A seguir apresentamos um programa exemplo para visualização de gráficos de funções . O programa está dividido em dois módulos: main.cpp e funcao.cpp. Main.cpp #include <gl\glut.h> #include "funcao.h" float theta = 135; float phi = 45; float gamma = 90; float scale = 1.0; int xb,xm,yb,ym; funcao f; void plota_eixos() { glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex3f(10.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,1.0,0.0); glBegin(GL_LINES); glVertex3f(0.0,10.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.0,0.0,10.0); glVertex3f(0.0,0.0,0.0); glEnd(); } void inicia_config() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2.0,2.0,-2.0,2.0,-20.0,20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gamma,0.0,0.0,1.0); glRotatef(phi,0.0,1.0,0.0); glRotatef(theta,0.0,0.0,1.0); glScalef(scale,scale,scale); } void redesenha() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixos(); f.plota_funcao(); glutSwapBuffers(); }

Page 99: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

16

void keyboard(unsigned char key, int x, int y) { switch(key) { case 'S': scale += 0.2; inicia_config(); redesenha(); break; case 's': scale -= 0.2; inicia_config(); redesenha(); break; } } void botao_mouse(int b,int state,int x, int y) { switch(b) { case GLUT_LEFT_BUTTON: switch(state) { case GLUT_DOWN: xb = x; yb = y; break; case GLUT_UP: theta = theta + xm - xb; phi = phi - ym + yb ; break; } break; } } void mov_mouse(int x, int y) { xm = x; ym = y; theta = theta + xm - xb; phi = phi - ym + yb ; inicia_config(); xb = xm; yb = ym; redesenha(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("3D"); glutDisplayFunc(redesenha); glutKeyboardFunc(keyboard); glutMouseFunc(botao_mouse);

Page 100: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

17

glutMotionFunc(mov_mouse); inicia_config(); glutMainLoop(); } funcao.h class funcao { float xmin,xmax,ymin,ymax; int points; public: funcao(float xm = -1,float xM = 1,float ym = -1,float yM = 1,int p = 10) { xmin = xm; ymin = ym; xmax = xM; ymax = yM; points = p ; } float f(float x,float y) { return(x*x-y*y); } void plota_funcao(); }; funcao.cpp #include <gl/glut.h> #include "funcao.h" void funcao::plota_funcao() { float x,y; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; glColor3f (1.0f, 1.0f, 1.0f); x = xmin; for(int i=0;i<points;i++) { y = ymin; for(int j=0;j<points;j++){ glBegin(GL_LINE_LOOP); glVertex3f(x ,y ,f(x ,y) ); glVertex3f(x+dx,y ,f(x+dx,y) ); glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); glVertex3f(x ,y+dy,f(x ,y+dy)); glEnd(); y += dy; } x += dx; } }

Page 101: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

18

2- ILUMINAÇÃO 2.1 – Introdução Para adicionar iluminação são necessárias quatro etapas básicas: 1) Definir o vetor normal a cada vértice de seu modelo; 2) Definir as fontes de luz (posição, cor, direção, etc.); 3) Definir um modelo de iluminação (nível da iluminação global e posição do observador) 4) Definir as propriedades do material de cada objeto. O modelo de iluminação do OPENGL considera que a iluminação pode ser dividida em três componentes independentes: ambiente, difusa e especular. - Luz Ambiente: é a luz proveniente de uma fonte dispersa tal que sua direção não pode ser determinada. - Luz Difusa: é uma luz proveniente de uma única direção que quando incide sobre o objeto não mantém

uma direção preferencial, e se divide em componentes em todas as direções. - Luz Especular: é a luz proveniente de uma direção particular e tende a refletir em uma direção

preferencial. A cor de uma fonte de luz é caracterizada pela intensidade de cada uma de suas componentes: vermelho, verde e azul. O material da superfície é caracterizado pela quantidade de luz refletida ou absorvida. Um material verde, refle a luz verde e absorve as outras componentes, por exemplo. O material tem as mesmas características de uma fonte de luz, sendo necessário definir qual o seu comportamento relativo à luz ambiente, difusa e especular. Para determinar a iluminação de cada face de um objeto, um elemento essencial deve ser introduzido agora: o vetor normal em cada vértice. Assim, a cada vértice introduzido via glVertex3f(x,y,z), corresponde um vetor normal definido por glNormal3f(vx,vy,vz). A normal deve ser especificada antes do vértice, ou seja, a sequência de comandos deve ser: . . . glNormal3f(vx,vy,vz); glVertex3f(x,y,z); . . . Vamos iniciar com um simples exemplo, ilustrando as dificuldades de se estabelecer uma boa iluminação. Nosso primeiro exemplo é um toro, gerado pelo comando glutSolidTorus, onde se estabeleceu uma iluminação básica, porém não satisfatória ainda. A classe iluminação foi definida com alguns parâmetros básicos.

Page 102: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

19

iluminacao.h class iluminacao { float mat_specular[4]; float mat_shininess; float light_position[4]; public: iluminacao(); void light_on(); void render_light(); void light_off(); }; iluminação.cpp #include <gl/glut.h> #include "iluminacao.h" iluminacao::iluminacao() { mat_specular[0] = 1.0f; mat_specular[1] = 1.0f; mat_specular[2] = 1.0f; mat_specular[3] = 1.0f; mat_shininess = 50.0f; light_position[0] = 2.0f; light_position[1] = 2.0f; light_position[2] = 2.0f; light_position[3] = 1.0f; } void iluminacao::light_on() { glShadeModel (GL_FLAT); // GL_SMOOTH or GL_FLAT glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_NORMALIZE); } void iluminacao::render_light() { glColor3f(1,0,0); glPointSize(8); glBegin(GL_POINTS); glVertex3f(light_position[0], light_position[1], light_position[2]); glEnd(); } void iluminacao::light_off() { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); }

Page 103: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

20

main.cpp include <gl\glut.h> #include "iluminacao.h" float theta = 135; float phi = 45; float gamma = 90; float scale = 1.0; int xb,xm,yb,ym; iluminacao I; void plota_eixos() { glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex3f(10.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,1.0,0.0); glBegin(GL_LINES); glVertex3f(0.0,10.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.0,0.0,10.0); glVertex3f(0.0,0.0,0.0); glEnd(); } void inicia_config() { glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2.0,2.0,-2.0,2.0,-20.0,20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gamma,0.0,0.0,1.0); glRotatef(phi,0.0,1.0,0.0); glRotatef(theta,0.0,0.0,1.0); glScalef(scale,scale,scale); } void redesenha() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixos(); I.light_on(); glColor3f(1,1,0); glutSolidTorus(0.5,1, 20, 10); I.render_light(); I.light_off(); glutSwapBuffers(); } void keyboard(unsigned char key, int x, int y) {

Page 104: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

21

switch(key) { case 'S': scale += 0.2; inicia_config(); redesenha(); break; case 's': scale -= 0.2; inicia_config(); redesenha(); break; } } void botao_mouse(int b,int state,int x, int y) { switch(b) { case GLUT_LEFT_BUTTON: switch(state) { case GLUT_DOWN: xb = x; yb = y; break; case GLUT_UP: theta = theta + xm - xb; phi = phi - ym + yb ; break; } break; } } void mov_mouse(int x, int y) { xm = x; ym = y; theta = theta + xm - xb; phi = phi - ym + yb ; inicia_config(); xb = xm; yb = ym; redesenha(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("3D"); glutDisplayFunc(redesenha); glutKeyboardFunc(keyboard); glutMouseFunc(botao_mouse); glutMotionFunc(mov_mouse); inicia_config(); glutMainLoop(); }

Page 105: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

22

2.2 – Criando Fontes de Luz . As fontes de luz têm certas propriedades que devem ser definidas (Cor, direção, posição, etc.). O comando para especificar essas propriedades é: void glLightfv(GLenum luz, GLenum iluminação, GLenum param); O parâmetro luz indica apenas qual fonte de luz estamos trabalhando. Existem no máximo oito fontes que são: GL_LIGHT0, GL_LIGHT1, ... , GL_LIGHT7. Por default a luz GL_LIGHT0 inicia com a cor branca e as sete luzes restantes ficam apagadas (luz preta). Os parâmetros da iluminação são: Parâmetro Valor default Significado

GL_AMBIENT (0.0, 0.0, 0.0, 1.0) Intensidade da luz ambiente

GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) Intensidade da luz difusa GL_SPECULAR (1.0, 1.0, 1.0, 1.0) Intensidade da luz

especular GL_POSITION (0.0, 0.0, 1.0, 0.0) posição da luz GL_SPOT_DIRECTION (0.0, 0.0, -1.0) direção da luz GL_SPOT_EXPONENT 0.0 Parâmetro que controla a

distribuição da luz. GL_SPOT_CUTOFF 180.0 Ângulo de abertura da luz GL_CONSTANT_ATTENUATION 1.0 GL_LINEAR_ATTENUATION 0.0 GL_QUADRATIC_ATTENUATION 0.0

2.2.1 – Cor Para cada fonte de luz existem três parâmetros principais relacionados a cor: - Luz Ambiente: é a luz proveniente de uma fonte dispersa tal que sua direção não pode ser determinada. - Luz Difusa: é a luz proveniente de uma única direção que ao incidir sobre a superfície do material, se

reflete em todas as direções. Define a luz que naturalmente definiríamos como a cor da luz. - Luz Especular: é a luz proveniente de uma direção particular e tende a refletir em uma direção

preferencial. Se você quer criar efeitos realísticos, mantenha a luz especular com os mesmos parâmetros da luz difusa.

Cada um desses parâmetros é defindo pelos 4 atributos: R,G,B,A. Por exemplo, para alterar a luz ambiente utiliza-se o seguinte código: GLfloat luz_ambiente[4] = { 0.5, 0.2, 0.3, 1.0 }; glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambiente); Nesse caso temos R = 0.5, G = 0.2, B = 0.3 e A = 1.0.

Page 106: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

23

2.2.2– Posição A posição da luz pode ser de dois tipos básicos: - Direcional: é quando a fonte de luz é considerada no infinito. Neste caso os raios de luz incidem

paralelos ao objeto. Para obter, por exemplo, uma fonte de luz branca você deve utilizar o seguinte código:

GLfloat luz_posicao[4] = { 1.0, 1.0, 1.0, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, luz_posicao); - Posicional : Se o último valor do vetor luz_posicao[] for diferente de zero, a luz é posicional e

sua localização é definida pelo vetor: GLfloat luz_posicao[4]={x , y, z, 1.0}; 2.3– Selecionando o Modelo de Iluminação

2.3.1- Luz Ambiente Global Cada fonte de luz pode contribuir com uma parcela da luz ambiente. Além disso, é possível adicionar uma outra parcela de luz ambiente que não dependa das fontes de iluminação. Para isso utiliza-se os comandos: GLfloat luz_ambiente_modelo[4] = { 0.2, 0.2, 0.2, 1.0 }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, luz_ambiente_modelo); Observe que neste caso, mesmo que todas as fontes de luz estejam desligadas ainda assim será possível ver os objetos na cena.

2.3.2 – Posição do observador local ou no infinito A localização do observador pode ou não influenciar na iluminação. O default é o observador no infinito. Para mudar a configuração, considerando-se a iluminação conforme o observador utilize: glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

2.3.3 – Iluminação nos dois lados da face O cálculo da iluminação é feito para todos os polígonos. É possível considerar diferentes iluminações nos dois lados de um polígono. Para isso utilize: glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

2.3.4 – Habilitando a iluminação No OpenGL você precisa explicitamente habilitar a iluminação. Para isso utilize o comando: glEnable(GL_LIGHTING); Para desabilitar basta utilizar o comando: glDisable(GL_LIGHTING);

Page 107: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

24

2.4– Selecionando as Propriedades do Material Para definir as propriedades do material do objeto em cena utilizamos o seguinte comando: void glMaterialfv(GLenum face, GLenum iluminacao, TYPE param); O parâmetro face pode ser: GL_FRONT, GL_BACK ou GL_FRONT_AND_BACK. Os parâmetros da iluminação são: Parâmetro Valor default Significado

GL_AMBIENT (0.2, 0.2, 0.2, 1.0) Cor da luz ambiente do material

GL_DIFFUSE (0.8, 0.8, 0.8, 1.0) Cor da luz difusa do material

GL_SPECULAR (0.0, 0.0, 0.0, 1.0) Especular cor do material GL_SHININESS 0.0 Índice especular GL_EMISSION (0.0, 0.0, 0.0, 1.0) Cor de emissão do

material Como exemplo, inserimos o modulo de iluminacao no programa funcao3D. iluminacao.h class iluminacao { float mat_specular[4]; float mat_shininess; float light_position[4]; float light_diffuse[4]; public: iluminacao(); void light_on(); void render_light(); void light_off(); }; iluminacao.cpp #include <gl/glut.h> #include "iluminacao.h" iluminacao::iluminacao() { mat_specular[0] = 1.0f; mat_specular[1] = 1.0f; mat_specular[2] = 0.0f; mat_specular[3] = 1.0f; mat_shininess = 50.0f; light_position[0] = 2.0f; light_position[1] = 2.0f; light_position[2] = 2.0f; light_position[3] = 1.0f; light_diffuse[0] = 1.0f; light_diffuse[1] = 0.0f; light_diffuse[2] = 0.0f; light_diffuse[3] = 1.0f; }

Page 108: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

25

void iluminacao::light_on() { glShadeModel (GL_SMOOTH); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_NORMALIZE); } void iluminacao::render_light() { glColor3f(1,0,0); glPointSize(8); glBegin(GL_POINTS); glVertex3f(light_position[0], light_position[1], light_position[2]); glEnd(); } void iluminacao::light_off() { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glDisable(GL_DEPTH_TEST); } funcao.h #include <cmath> class funcao { float xmin,xmax,ymin,ymax; int points; public: funcao(float xm=-1,float xM=1,float ym=-1,float yM=1,int p=10) { xmin = xm; ymin = ym; xmax = xM; ymax = yM; points = p ; } float f(float x,float y) { return(x*x-y*y); //return(cos(sqrt(x*x+y*y))); } float dfx(float x,float y) { return(2*x); //return((-sin(sqrt(x*x+y*y))*x/sqrt(x*x+y*y))); } float dfy(float x,float y) { return(-2*y); //return((float)(-sin(sqrt(x*x+y*y))*y/sqrt(x*x+y*y)) ); } void normal(float *v,float x,float y); void plota_funcao_01(); void plota_funcao_02(); };

Page 109: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

26

funcao.cpp #include <gl/glut.h> #include "funcao.h" void funcao::normal(float *v,float x,float y) { v[0] = -dfx(x,y); v[1] = -dfy(x,y); v[2] = 1; } void funcao::plota_funcao_01() { float x,y; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; glColor3f (1.0f, 1.0f, 1.0f); x = xmin; for(int i=0;i<points;i++) { y = ymin; for(int j=0;j<points;j++){ glBegin(GL_LINE_LOOP); glVertex3f(x ,y ,f(x ,y) ); glVertex3f(x+dx,y ,f(x+dx,y) ); glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); glVertex3f(x ,y+dy,f(x ,y+dy)); glEnd(); y += dy; } x += dx; } } void funcao::plota_funcao_02() { float x,y,v[3]; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; x = xmin; for(int i=0;i<points;i++) { y = ymin; for(int j=0;j<points;j++){ glBegin(GL_QUADS); normal(v,x,y); glNormal3f(v[0],v[1],v[2]); glVertex3f(x ,y ,f(x ,y) ); normal(v,x+dx,y); glNormal3f(v[0],v[1],v[2]); glVertex3f(x+dx,y ,f(x+dx,y) ); normal(v,x+dx,y+dy); glNormal3f(v[0],v[1],v[2]); glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); normal(v,x,y+dy); glNormal3f(v[0],v[1],v[2]); glVertex3f(x ,y+dy,f(x ,y+dy)); glEnd(); y += dy; } x += dx; } }

Page 110: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

27

2.5 – Visualizando as normais Podemos acrescentar um novo metodo para visualizarmos as normais sobre a superfície. funcao.cpp . . . void funcao::plota_normal() { float x,y,v[3]; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; float n = 10; glColor3f (1.0f, 1.0f, 1.0f); x = xmin; for(int i=0;i<points;i++) { y = ymin; for(int j=0;j<points;j++){ glBegin(GL_LINES); normal(v,x,y); glVertex3f(x ,y ,f(x ,y) ); glVertex3f(x+v[0]/n,y+v[1]/n,f(x ,y)+v[2]/n); normal(v,x+dx,y); glVertex3f(x+dx,y ,f(x+dx,y) ); glVertex3f(x+dx+v[0]/n,y+v[1]/n,f(x+dx,y)+v[2]/n); normal(v,x+dx,y+dy); glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); glVertex3f(x+dx+v[0]/n,y+dy+v[1]/n,f(x+dx,y+dy)+v[2]/n); normal(v,x,y+dy); glVertex3f(x ,y+dy,f(x ,y+dy)); glVertex3f(x+v[0]/n,y+dy+v[1]/n,f(x,y+dy)+v[2]/n); glEnd(); y += dy; } x += dx; } }

Page 111: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

28

3-SUPERFÍCIES PARAMÉTRICAS Considere D uma região do plano. A cada par de D vamos associar um ponto no espaço tri-dimensional, o qual pode ser escrito em termos de suas funções coordenadas por:

Uma superfície parametrizada é uma aplicação onde D é algum domínio em . A superfície S correspondente à função é a imagem . A superfície parametrizada depende de dois parâmetros (u, v). A visualização de superfícies paramétricas pode ser feita com pequenas alterações no código anterior que visualiza o gráfico de uma função. O código abaixo ilustra um exemplo, modificando o código anterior. A classe funcao foi substituída pela classe superfície. superfície.h #include <cmath> class superficie { float umin,umax,vmin,vmax; int points; public: superficie(float um = 0,float uM = 6.28,float vm = -8,float vM = 8,int p = 30) { umin = um; vmin = vm; umax = uM; vmax = vM; points = p ; } void s(float *r,float u,float v) { r[0] = cos(u) * (0.5+sin(v)/5); r[1] = sin(u) * (0.5+sin(v)/5); r[2] = v/5; } void normal(float *v,float x,float y); void plota_superficie_01(); void plota_superficie_02(); void plota_normal(); };

Page 112: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

29

superfície.cpp #include <gl/glut.h> #include "superficie.h" void superficie::plota_superficie_01() { float u,v; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; float r[3],n[3]; glColor3f (1.0f, 1.0f, 1.0f); u = umin; for(int i=0;i<points;i++) { v = vmin; for(int j=0;j<points;j++){ glBegin(GL_LINE_LOOP); s(r,u,v); glVertex3f(r[0],r[1],r[2]); s(r,u+du,v); glVertex3f(r[0],r[1],r[2]); s(r,u+du,v+dv); glVertex3f(r[0],r[1],r[2]); s(r,u,v+dv); glVertex3f(r[0],r[1],r[2]); glEnd(); v += dv; } u += du; } } void superficie::plota_superficie_02() { float u,v; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; float r[3],n[3]; glColor3f (1.0f, 1.0f, 1.0f); u = umin; for(int i=0;i<points;i++) { v = vmin; for(int j=0;j<points;j++){ glBegin(GL_QUADS); normal(n,u,v); s(r,u,v); glNormal3f(n[0],n[1],n[2]); glVertex3f(r[0],r[1],r[2]); normal(n,u+du,v); s(r,u+du,v); glNormal3f(n[0],n[1],n[2]); glVertex3f(r[0],r[1],r[2]); normal(n,u+du,v+dv); s(r,u+du,v+dv); glNormal3f(n[0],n[1],n[2]); glVertex3f(r[0],r[1],r[2]); normal(n,u,v+dv); s(r,u,v+dv);

Page 113: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

30

glNormal3f(n[0],n[1],n[2]); glVertex3f(r[0],r[1],r[2]); glEnd(); v += dv; } u += du; } } void superficie::normal(float *n,float u,float v) { float v1[3]; float v2[3]; float norma; float p1[3]; float p2[3]; float p3[3]; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; s(p1,u,v); s(p2,u,v+dv); s(p3,u+du,v); v1[0] = p2[0]-p1[0] ; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p1[0]; v2[1] = p3[1]-p1[1]; v2[2] = p3[2]-p1[2]; n[0] = v1[1] * v2[2] - v1[2] * v2[1]; n[1] = -v1[0] * v2[2] + v1[2] * v2[0]; n[2] = v1[0] * v2[1] - v1[1] * v2[0]; norma = sqrt(n[0] * n[0] + n[1] *n[1] + n[2] * n[2]); n[0] = -n[0] / norma; n[1] = -n[1] / norma; n[2] = -n[2] / norma; } void superficie::plota_normal() { float u,v; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; float r[3],n[3]; glColor3f (1.0f, 1.0f, 1.0f); u = umin; for(int i=0;i<points;i++) { v = vmin; for(int j=0;j<points;j++){ glBegin(GL_LINES); normal(n,u,v); s(r,u,v); glVertex3f(r[0] ,r[1] ,r[2] ); glVertex3f(r[0]+n[0],r[1]+n[1],r[2]+n[2]); normal(n,u+du,v);

Page 114: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

31

s(r,u+du,v); glVertex3f(r[0] ,r[1] ,r[2] ); glVertex3f(r[0]+n[0],r[1]+n[1],r[2]+n[2]); normal(n,u+du,v+dv); s(r,u+du,v+dv); glVertex3f(r[0] ,r[1] ,r[2] ); glVertex3f(r[0]+n[0],r[1]+n[1],r[2]+n[2]); normal(n,u,v+dv); s(r,u,v+dv); glVertex3f(r[0] ,r[1] ,r[2] ); glVertex3f(r[0]+n[0],r[1]+n[1],r[2]+n[2]); glEnd(); v += dv; } u += du; } } Exercícios 1) Utilizando o programa anterior, visualize as seguintes superfícies e identifique-as:

a)

b)

c)

d)

e)

f)

g)

2) Visualize os vetores normais sobre a superfície. Observe o exemplo da letra f).

Page 115: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

32

4- SUPERFÍCIES IMPLÍCITAS 4.1 – Introdução Na seção de curva implícita, vimos que na forma implícita uma curva é representada pela equação:

Para superfícies estamos buscando o conjunto de pontos que satisfaz a equação:

Por exemplo:

Nossa estratégia é semelhante ao algoritmo de curvas implícitas, porém, agora temos uma dimensão a mais. Assim, nosso domínio será [xmin, xmax] x [ymin,ymax] x [zmin,zmax]. Ao invés de quadrados, teremos cubos, e ao invés de triângulos, teremos tetraedros. No algoritmo de curvas implícitas, buscamos obter o segmento de reta em cada triângulo que pertencia a curva, agora estamos buscando obter uma face em cada tetraedro analisado. 4.2 – Visualização de Superfícies Implícitas Para implementar a visualização de superfícies implícitas estabelecemos os seguintes passos: - Vamos estabelecer um domínio no espaço como partida (a priori não

sabemos se existem ou não pontos da superfície nesse domínio). - Em seguida discretizamos este domínio, determinando um grid 3D de 10x10x10 pontos

, por exemplo.

- A cada cubo, obtemos seis tetraedros: Partindo de um cubo, a construção é feita da seguinte forma: 1)

enumerar os vértices do cubo, como na figura; 2) trace uma diagonal do cubo unindo v0 e v7; 2) Projete esta diagonal em cada uma das seis faces do cubo; 3) os tetraedros serão obtidos selecionando os vértices que estão conectados, iniciando em v0 e terminando em v7. Assim por exemplo, considere os vértices do cubo {v0,v1,v2,v3,v4,v5,v6,v7}, então teremos os tetraedros:

T1 = {v0,v2,v6,v7} T2 = {v0,v4,v6,v7} T3 = {v0,v1,v5,v7} T4 = {v0,v1,v3,v7} T5 = {v0,v4,v5,v7} T6 = {v0,v2,v3,v7}

Page 116: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

33

O resultado será um grid, com seis tetraedros em cada cubo, como na figura abaixo:

- Para cada ponto calculamos .

- Para cada cubo, analisamos cada um dos seus 6 tetraedros. - Para cada tetraedro temos quatro vértices (Vi, i=0,1,2,3) e observamos os sinais = sinal(Vi) obtidos

em cada vértice. Analisando cada uma das seis arestas do tetraedro, teremos:

- Se S1 * S2 < 0, então a função se anula em um ponto entre V1 e V2. Este ponto pode ser aproximado linearmente.

Page 117: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

34

- Se S1 * S3 < 0, então a função se anula em um ponto entre V1 e V3.

- Se S1 * S4 < 0, então a função se anula em um ponto entre V1 e V4.

- Se S2 * S3 < 0, então a função se anula em um ponto entre V2 e V3.

- Se S2 * S4 < 0, então a função se anula em um ponto entre V2 e V4.

- Se S3 * S4 < 0, então a função se anula em um ponto entre V3 e V4.

- Se S1 = 0, então a função se anula exatamente sobre o vértice V1.

- Se S2 = 0, então a função se anula exatamente sobre o vértice V2.

- Se S3 = 0, então a função se anula exatamente sobre o vértice V3.

- Se S4 = 0, então a função se anula exatamente sobre o vértice V4.

- Considerando que exatamente três ou quatro das condições acima se verificaram simultaneamente,

aproximamos a superfícies nesse tetraedro, gerando um triângulo com os três pontos (a figura abaixo ilustra esse caso), ou um quadrilátero com os quatro pontos (no algoritmo optamos por triangular esse quadrilátero, gerando dois triângulos).

4.3 – Implementação Main.cpp #include <gl\glut.h> #include "implicito.h" float theta = 135; float phi = 45; float gamma = 90; float scale = 1.0; int xb,xm,yb,ym; implicito S(-2,2,-2,2,-2,2,5); void plota_eixos() {

Page 118: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

35

glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex3f(10.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,1.0,0.0); glBegin(GL_LINES); glVertex3f(0.0,10.0,0.0); glVertex3f(0.0,0.0,0.0); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.0,0.0,10.0); glVertex3f(0.0,0.0,0.0); glEnd(); } void inicia_config() { glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2.0,2.0,-2.0,2.0,-20.0,20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gamma,0.0,0.0,1.0); glRotatef(phi,0.0,1.0,0.0); glRotatef(theta,0.0,0.0,1.0); glScalef(scale,scale,scale); } void redesenha() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); plota_eixos(); glColor3f(1,1,0); S.plota_superficie(); glutSwapBuffers(); } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'S': scale += 0.2; inicia_config(); redesenha(); break; case 's': scale -= 0.2; inicia_config(); redesenha(); break; } } void botao_mouse(int b,int state,int x, int y)

Page 119: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

36

{ switch(b) { case GLUT_LEFT_BUTTON: switch(state) { case GLUT_DOWN: xb = x; yb = y; break; case GLUT_UP: theta = theta + xm - xb; phi = phi - ym + yb ; break; } break; } } void mov_mouse(int x, int y) { xm = x; ym = y; theta = theta + xm - xb; phi = phi - ym + yb ; inicia_config(); xb = xm; yb = ym; redesenha(); } void main(int argc, char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutInitWindowPosition(50,50); glutCreateWindow("3D"); glutDisplayFunc(redesenha); glutKeyboardFunc(keyboard); glutMouseFunc(botao_mouse); glutMotionFunc(mov_mouse); inicia_config(); glutMainLoop(); } implícito.h class implicito { float xmin,xmax,ymin,ymax,zmin,zmax; int pontos; public: implicito(float xm = -1, float xM = 1, float ym = -1, float yM = 1, float zm = -1, float zM = 1, int p = 10) { xmin = xm; xmax = xM; ymin = ym; ymax = yM; zmin = zm; zmax = zM; pontos = p; } int get_pontos() {

Page 120: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

37

return pontos; } void set_pontos(int p) { pontos = p; } float f(float x,float y,float z); void normal(float* v, float x,float y,float z); void tetraedro(float* x,float* y,float* z,float* w); void plota_superficie(); }; implícito.cpp #include <gl/glut.h> #include <cmath> #include "implicito.h" float implicito::f(float x,float y,float z) { return(x*x+cos(x)*y*y-z*y-1); } void implicito::normal(float* v, float x,float y,float z) { v[0] = 2*x-sin(x)*y*y; v[1] = 2*y*cos(x)-z; v[2] = -y; } void implicito::tetraedro(float *v0,float *v1,float *v2,float *v3) { #define TETRA 1 glColor3f(1,0,0); int i; int n = 0; float t,p[4][3]; float w0,w1,w2,w3; w0 = f(v0[0],v0[1],v0[2]); w1 = f(v1[0],v1[1],v1[2]); w2 = f(v2[0],v2[1],v2[2]); w3 = f(v3[0],v3[1],v3[2]); if (w0 * w1 < 0) { t = -w0/(w1-w0); for(i=0;i<3;i++) p[n][i] = v0[i] + t * (v1[i] - v0[i]); n++; } if (w1 * w3 < 0) { t = -w1/(w3-w1); for(i=0;i<3;i++) p[n][i] = v1[i] + t * (v3[i] - v1[i]); n++; } if (w0 * w3 < 0) { t = -w0/(w3-w0);

Page 121: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

38

for(i=0;i<3;i++) p[n][i] = v0[i] + t * (v3[i] - v0[i]); n++; } if (w2 * w3 < 0) { t = -w2/(w3-w2); for(i=0;i<3;i++) p[n][i] = v2[i] + t * (v3[i] - v2[i]); n++; } if (w0 * w2 < 0) { t = -w0/(w2-w0); for(i=0;i<3;i++) p[n][i] = v0[i] + t * (v2[i] - v0[i]); n++; } if (w1 * w2 < 0) { t = -w1/(w2-w1); for(i=0;i<3;i++) p[n][i] = v1[i] + t * (v2[i] - v1[i]); n++; } if (n == 3) { // Triangulo #if TETRA glColor3f(0,0,1); glBegin(GL_LINE_LOOP); glVertex3fv(v0); glVertex3fv(v1); glVertex3fv(v2); glEnd(); glBegin(GL_LINES); glVertex3fv(v0); glVertex3fv(v3); glVertex3fv(v1); glVertex3fv(v3); glVertex3fv(v2); glVertex3fv(v3); glEnd(); #endif // glBegin(GL_LINE_LOOP); glColor3f(1,0,0); glBegin(GL_TRIANGLES); glVertex3f(p[0][0],p[0][1],p[0][2]); glVertex3f(p[1][0],p[1][1],p[1][2]); glVertex3f(p[2][0],p[2][1],p[2][2]); glEnd(); glLineWidth(3); glBegin(GL_LINE_LOOP); glColor3f(1,1,1); glVertex3f(p[0][0],p[0][1],p[0][2]); glVertex3f(p[1][0],p[1][1],p[1][2]); glVertex3f(p[2][0],p[2][1],p[2][2]); glEnd(); glLineWidth(1); } if (n == 4) { // QUADS #if TETRA

Page 122: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

39

glColor3f(0,0,1); glBegin(GL_LINE_LOOP); glVertex3fv(v0); glVertex3fv(v1); glVertex3fv(v2); glEnd(); glBegin(GL_LINES); glVertex3fv(v0); glVertex3fv(v3); glVertex3fv(v1); glVertex3fv(v3); glVertex3fv(v2); glVertex3fv(v3); glEnd(); #endif glColor3f(1,1,1); glLineWidth(3); glBegin(GL_LINE_LOOP); glVertex3f(p[0][0],p[0][1],p[0][2]); glVertex3f(p[1][0],p[1][1],p[1][2]); glVertex3f(p[2][0],p[2][1],p[2][2]); glVertex3f(p[3][0],p[3][1],p[3][2]); glEnd(); glLineWidth(1); glColor3f(0,1,0); glBegin(GL_QUADS); glVertex3f(p[0][0],p[0][1],p[0][2]); glVertex3f(p[1][0],p[1][1],p[1][2]); glVertex3f(p[2][0],p[2][1],p[2][2]); glVertex3f(p[3][0],p[3][1],p[3][2]); glEnd(); } } void implicito::plota_superficie() { int i,j,k; float x,y,z; float dx,dy,dz; float z0,z1,z2,z3; float v[8][3]; dx = (xmax-xmin)/pontos; dy = (ymax-ymin)/pontos; dz = (zmax-zmin)/pontos; glColor3f(1.0,1.0,1.0); x = xmin; for(i=0;i < pontos; i++) { y = ymin; for(j=0 ; j < pontos; j++) { z = zmin; for(k=0; k< pontos; k++) { v[0][0] = x ; v[1][0] = x+dx; v[2][0] = x ;

Page 123: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

40

v[3][0] = x+dx; v[0][1] = y ; v[1][1] = y ; v[2][1] = y+dy; v[3][1] = y+dy; v[0][2] = z ; v[1][2] = z ; v[2][2] = z ; v[3][2] = z ; v[4][0] = x ; v[5][0] = x+dx; v[6][0] = x ; v[7][0] = x+dx; v[4][1] = y ; v[5][1] = y ; v[6][1] = y+dy; v[7][1] = y+dy; v[4][2] = z+dz; v[5][2] = z+dz; v[6][2] = z+dz; v[7][2] = z+dz; tetraedro(v[0],v[1],v[3],v[7]); tetraedro(v[0],v[1],v[5],v[7]); tetraedro(v[0],v[2],v[3],v[7]); tetraedro(v[0],v[2],v[6],v[7]); tetraedro(v[0],v[4],v[5],v[7]); tetraedro(v[0],v[4],v[6],v[7]); z += dz; } y += dy; } x += dx; } }

Page 124: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

41

5- TEXTURA 5.1 – Introdução Texturas permitem que imagens sejam aplicadas sobre as faces de um objeto. Por exemplo, podemos copiar uma imagem de um piso nos políginos que representam o chão de uma sala. No OpenGL, uma textura pode ser unidimendional, bidimensional ou até tridimensional, embora o caso bidimensional seja o principal. Para usar uma textura no OpenGL podemos destacar quatro etapas básicas [The OpenGL Programming Guide - The Redbook]:

1. Criar uma textura 2. Indicar como a textura será aplicada em cada pixel. 3. Habilitar o modo textura. 4. Definir os parâmetros da textura no modelo geométrico.

Em seguida vamos apresentar os comandos essenciais para utilizar uma textura.

5.2 – Parâmetros Básicos Etapa 1: Definir a textura 2D. O comando glTexImage2D é o comando principal. void glTexImage2D(GLenum target,

GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);

O comando glGenTextures serve apenas para retornar um inteiro ainda não usado para nomear uma textura. O inteiro é retornado na variável textureNames. void glGenTextures(GLsizei n, GLuint *textureNames); Exemplo: GLuint nameTex; glGenTextures(1, &nameTex); Etapa 2: A textura pode ser reduzida ou ampliada sobre a superfície.

Page 125: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

42

(Figura extraída de: The OpenGL Programming Guide - The Redbook - 5th Edition The Official Guide to Learning OpenGL Version 2.1) Para definir os parâmetros que controlam essas transformações temos, por exemplo: 1) void glTexParameteri(GLenum target, GLenum pname, GLint param); Parâmetros: GLenum target:

• GL_TEXTURE_1D • GL_TEXTURE_2D

GLenum pname,:

• GL_TEXTURE_MAG_FILTER • GL_TEXTURE_MIN_FILTER

GLint param

1. Para GL_TEXTURE_MAG_FILTER: o GL_NEAREST: retorna o valor do texel que estiver mais próximo. o GL_LINEAR: retorna a media dos 4 elementos ao redor do pixel mais

próximo. 2. Para GL_TEXTURE_MIN_FILTER:

o GL_NEAREST o GL_LINEAR o GL_NEAREST_MIPMAP_NEAREST o GL_NEAREST_MIPMAP_LINEAR

Exemplo: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 2) void glTexEnv{if}(GLenum target, GLenum pname, TYPEparam); Define como a textura irá ser associada a cor do objeto. Temos 4 exemplos principais para o modelo RGB:

Page 126: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

43

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); Substitui a cor pela cor da textura. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); Substitui a cor pela cor da textura. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); Faz uma média ponderada entra a cor atual pela cor da textura. Etapa 3: Para habilitar a textura, temos os comandos abaixo: Habilita o uso de textura: glEnable(GL_TEXTURE_2D); Define qual textura deve ser aplicada: glBindTexture(GL_TEXTURE_2D, texName); Etapa 4: Define as coordenadas da textura sobre cada face. A textura é representada pelas coordenadas de textura: glTexCoord2f(0.0, 0.0); glTexCoord2f(0.0, 1.0); glTexCoord2f(1.0, 1.0); glTexCoord2f(1.0, 0.0); Se voce deseja que uma unica textura seja distribuida sob a superfície, é preciso subdividi-la. Por exemplo em uma superfície parametrizada 10 x 10, a cada quad teremos: glTexCoord2f( i/10.0, j /10.0); glTexCoord2f( i/10.0, (j+1)/10.0); glTexCoord2f((i+1)/10.0, (j+1)/10,0); glTexCoord2f((i+1)/10.0, j /10.0);

5.3 – Aplicação em Superfícies Paramétricas Textura.h #include <gl/glut.h> class Textura { GLuint texName; unsigned char *imagem; int dimx,dimy; public: Textura(char *s) ; void init(); void texture_on(); void texture_off(); void draw_imagem(); };

Page 127: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

44

Textura.cpp #include <gl/glut.h> #include <cstdio> #include "textura.h" // #define RGB Textura::Textura(char *file) { FILE *fp; int i,j,k,ind; int g; fp = fopen(file,"rb"); fscanf(fp,"%d %d %d",&dimx,&dimy,&i); imagem = new unsigned char[dimx*dimy*3]; ind = 0; for(i=0;i<dimx;i++) { for(j=0;j<dimy;j++) { #if RGB for(k=0;k<3;k++) { fscanf(fp,"%d",&g); imagem[ind] = (unsigned char) g; ind++; #else fscanf(fp,"%d",&g); imagem[ind] = (unsigned char) g; imagem[ind+1] = imagem[ind+2] = imagem[ind]; ind = ind + 3; #endif } } fclose(fp); } void Textura::init() { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1,&texName); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // GL_REPEAT ou GL_CLAMP glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); // GL_LINEAR ou GL_NEAREST glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_BLEND , GL_REPLACE, GL_MODULATE GL_DECAL glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dimx,dimy, 0, GL_RGB, GL_UNSIGNED_BYTE,imagem); } void Textura::texture_on() { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texName); } void Textura::texture_off() { glDisable(GL_TEXTURE_2D);

Page 128: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

45

} void Textura::draw_imagem() { int ind = 0; for(int i=0;i<dimx;i++) for(int j = 0;j<dimy;j++) { glColor3f(imagem[ind]/255.,imagem[ind+1]/255.,imagem[ind+2]/255.); // Nao RGB glBegin(GL_POINTS); glVertex3i(i,j,0); glEnd(); ind += 3; } }

main.cpp #include<gl\glut.h> #include "ilumina.h" #include "parametrico.h" #include "textura.h" #include <iostream> using namespace std; parametrico p(0,4.28, 1, 3.2, 10); Textura T("lena.pgm"); int m = 0; float phi = 0; //235 float theta = 0; //42 float gama = 0; ilumina I; int xi,yi,xf,yf; void eixos() { glColor3f(1,0,0); glBegin(GL_LINES); glVertex3f(0,0,0); glVertex3f(1,0,0); glEnd(); glColor3f(0,1,0); glBegin(GL_LINES); glVertex3f(0,0,0); glVertex3f(0,1,0); glEnd(); glColor3f(0,0,1); glBegin(GL_LINES); glVertex3f(0,0,0); glVertex3f(0,0,1); glEnd(); } void inicia() { glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION);

Page 129: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

46

glLoadIdentity(); glOrtho(-2,2,-2,2,-2,2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gama,0,0,1); glRotatef(phi,1,0,0); glRotatef(theta,0,0,1); } void display() { glClearColor(1,1,1,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); eixos(); // I.light_on(); glColor3f(1,0,0); T.texture_on(); p.draw_parametrico_textura1(); // T.draw_imagem(); // I.light_off(); T.texture_off(); glFlush(); glutSwapBuffers(); } void rotaciona() { if (m == 1) { I.rot_light(0.003); glutPostRedisplay(); } } void botao(int b,int state,int x,int y) { if (b == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { xi = x; yi = y; } } } void botao_movimento(int x,int y) { theta = theta + (xi - x); phi = phi + (yi - y); xi = x; yi = y; inicia(); glutPostRedisplay(); } void teclado(unsigned char b,int x,int y) { if (b == 'r') m = (m+1)%2; } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(512,512); glutCreateWindow("Cubo");

Page 130: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

47

glutDisplayFunc(display); inicia(); T.init(); glutIdleFunc(rotaciona); glutKeyboardFunc(teclado); glutMouseFunc(botao); glutMotionFunc(botao_movimento); glutMainLoop(); }

parametrico.h class parametrico { float umin,umax,vmin,vmax; int pontos; public: parametrico(float um = -1, float uM = 1, float vm = -1, float vM = 1, int p = 10) { umin = um; umax = uM; vmin = vm; vmax = vM; pontos = p; } void normal(float u,float v,float *n); void p (float u,float v,float *f); void draw_parametrico(); void draw_parametrico_textura(); void draw_parametrico_textura1(); };

parametrico.cpp #include <gl/glut.h> #include <cmath> #include "parametrico.h" void parametrico::normal(float u,float v,float *n) { float d1[3]; float d2[3]; float p1[3]; float p2[3]; float p3[3]; float du = (umax - umin) / pontos; float dv = (vmax - vmin) / pontos; p(u ,v ,p1); p(u+du,v ,p2); p(u ,v+dv,p3); for(int i = 0;i<3;i++) { d1[i] = p2[i] - p1[i]; d2[i] = p3[i] - p1[i]; } n[0] = d1[1]*d2[2] - d1[2]*d2[1];

Page 131: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

48

n[1] = -d1[0]*d2[2] + d1[2]*d2[0]; n[2] = d1[0]*d2[1] - d1[1]*d2[0]; } void parametrico::p (float u,float v,float *f) { f[0] = u; f[1] = v; f[2] = u*u-v*v; // f[0] = (2+0.5*cos(v)) * cos(u); // f[1] = (2+0.5*cos(v)) * sin(u); // f[2] = 0.5*sin(v); // f[0] = cos(u) * sin(v); // f[1] = sin(u) * sin(v); // f[2] = cos(v); // f[0] = cos(u) + v * cos(u/2) * cos(u); // f[1] = sin(u) + v * cos(u/2) * sin(u); // f[2] = v * sin(u/2); } void parametrico::draw_parametrico() { float u,v; float du,dv; float f[3]; float n[3]; du = (umax - umin) / pontos; dv = (vmax - vmin) / pontos; glColor3f(1,0,0); u = umin; for(int i = 0; i< pontos; i++) { v = vmin; for(int j = 0; j < pontos; j++) { glBegin(GL_QUADS); normal(u ,v ,n); p (u ,v ,f); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); normal(u+du,v ,n); p (u+du,v ,f); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); normal(u+du,v+dv,n); p (u+du,v+dv,f); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); normal(u ,v+dv,n); p (u ,v+dv,f); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); glEnd(); v += dv; } u += du; } glColor3f(0,1,0); u = umin;

Page 132: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

49

for(int i = 0; i< pontos; i++) { v = vmin; for(int j = 0; j < pontos; j++) { glBegin(GL_LINES); normal(u ,v ,n); p (u ,v ,f); float norma = 5*sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); n[0] = n[0] / norma; n[1] = n[1] / norma; n[2] = n[2] / norma; glVertex3f(f[0],f[1],f[2]); glVertex3f(f[0]+n[0],f[1]+n[1],f[2]+n[2]); glEnd(); v += dv; } u += du; } } void parametrico::draw_parametrico_textura() { glColor3f(1,0,0); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(0,0,0); glTexCoord2f(1.0, 0.0); glVertex3f(1,0,0); glTexCoord2f(1.0, 1.0); glVertex3f(1,1,0); glTexCoord2f(0.0, 1.0); glVertex3f(0,1,0); glEnd(); } void parametrico::draw_parametrico_textura1() { float u,v; float du,dv; float f[3]; float n[3]; du = (umax - umin) / pontos; dv = (vmax - vmin) / pontos; glColor3f(1,0,0); u = umin; for(int i = 0; i< pontos; i++) { v = vmin; for(int j = 0; j < pontos; j++) { glBegin(GL_QUADS); normal(u ,v ,n); p (u ,v ,f); // glTexCoord2f(0.0, 0.0); // glTexCoord2f(u/umax, v/vmax); glTexCoord2f(u, v);

Page 133: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

50

glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); normal(u+du,v ,n); p (u+du,v ,f); // glTexCoord2f(1.0, 0.0); // glTexCoord2f((u+du)/umax, v/vmax); glTexCoord2f((u+du), v); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); normal(u+du,v+dv,n); p (u+du,v+dv,f); // glTexCoord2f(1.0, 1.0); // glTexCoord2f((u+du)/umax, (v+dv)/vmax); glTexCoord2f((u+du), (v+dv)); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); normal(u ,v+dv,n); p (u ,v+dv,f); // glTexCoord2f(0.0, 1.0); // glTexCoord2f(u/umax, (v+dv)/vmax); glTexCoord2f(u, (v+dv)); glNormal3f(n[0],n[1],n[2]); glVertex3f(f[0],f[1],f[2]); glEnd(); v += dv; } u += du; } }

6- Curvas de Bezier 6.1 – Introdução

Aproximadamente na década de 50, começaram a surgir as primeiras máquinas capazes de confeccionar formas sólidas de madeira ou aço partindo de um modelo. Para que isso fosse possível, tornou-se necessário produzir uma descrição computacional desses modelos compatível com as formas desejadas. Na indústria automobilística por exemplo, o capô de um carro não é perfeitamente descrito por uma única superfície paramétrica e nem sempre uma boa aproximação pode ser feita através de funções conhecidas(Superfícies quádricas, cilindros,etc..) sem um grande esforço. Assim surgiu a necessidade de curvas e superfícies que representassem com alguma facilidade formas livres. Foi na indústria automobilística que surgiu o primeiro modelo: As curvas de Bézier.

As curvas de Bézier foram desenvolvidas independentemente por P. de Casteljau na empresa automobilística Citröen e por P. Bézier na Renault em torno de 1959. Enquanto Bézier usou diretamente os polinômios de Bernstein, de Casteljau utilizou uma formulação recursiva, sendo que posteriormente provou-se que as duas formulações são equivalentes do ponto de vista matemático. Entretanto os trabalhos de P. de Casteljau só vieram a ser descobertos por W. Boehm em 1975, razão pela qual hoje o nome Bézier é extremamente difundido na nomenclatura de curvas e superfícies.

A partir da teoria das curvas de Bézier e mais tarde combinadas com os métodos B-Splines (As curvas B-Splines podem ser vistas de forma simplificada como generalização das curvas de Bézier), o design através da computacão gráfica tomou grande força, resultando nos avançados sistemas atuais em CAD/CAM. A curva de Bézier é uma alternativa para o design de formas livres. Apresentaremos em seguida a versão de de Casteljau para a geração da curva de Bézier. O algorítmo descrito nesta seção é considerado o algoritmo fundamental no campo do design de curvas e superfícies. Sua principal característica é a construção geométrica associada.

Page 134: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

51

Historicamente foi com este algoritmo que de Casteljau iniciou seu trabalho em 1959. Os únicos registros sobre este assunto feitos por de Casteljau são de difícil acesso, e sua divulgação só foi possível quando W.Boehm obteve cópias destes registros em 1975. Bezier.cpp #include <gl/glut.h> #include "bezier.h" void bezier::insert(float x,float y) { p[++n][0] = x; p[n][1] = y; } void bezier::remove(float x,float y) { } float bezier::bernstein(int n,int i,float t) { float ti = 1; float ti1 = 1; float s = 1; for (int j = 0;j < i ; j++) { s *= (n-j)/(float)(i-j); ti *= t; } for(int j = 0; j < n-i; j++) { ti1 *= (1-t); } return(s * ti * ti1); } void bezier::draw_bezier() { float t; float x,y; float dt = 1.0/pontos; if (n < 1) return; t = 0; glColor3f(1,0,0); glBegin(GL_LINE_STRIP); for (int i = 0;i <= pontos; i++) { x = 0; y = 0; for(int j=0; j <= n;j++) { x += p[j][0] * bernstein(n,j,t); y += p[j][1] * bernstein(n,j,t); } glVertex3f(x,y,0); t += dt; } glEnd(); }

Page 135: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

52

void bezier::draw_casteljau() { float t; float x,y; float dt = 1.0/pontos; if (n < 1) return; t = 0.0; glColor3f(1,0,0); glBegin(GL_LINE_STRIP); for (int i = 0;i <= pontos; i++) { x = casteljau(t,n,0,0); y = casteljau(t,n,0,1); glVertex3f(x,y,0); t += dt; } glEnd(); } void bezier::draw_method_casteljau() { float t; float x1,y1,x2,y2; int d = 5; float dt = 1.0/d; if (n < 1) return; t = 0; glColor3f(0,0,1); glBegin(GL_LINES); for(int k = 0; k <= d; k++) { for(int r = 1; r <= n; r++) { for (int i = 0;i <= n-r; i++) { x1 = casteljau(t,r-1,i,0); y1 = casteljau(t,r-1,i,1); x2 = casteljau(t,r-1,i+1,0); y2 = casteljau(t,r-1,i+1,1); glVertex3f(x1,y1,0); glVertex3f(x2,y2,0); } } t += dt; } glEnd(); } float bezier::casteljau(float t,int r,int i,int j) { if (r == 0) return( p[i][j] ); else return((1-t) * casteljau(t,r-1,i ,j) + t * casteljau(t,r-1,i+1,j));

Page 136: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

53

} void bezier::draw_poligono() { glColor3f(1,1,0); glPointSize(5.0); glBegin(GL_POINTS); for(int i =0;i <= n; i++) glVertex3f(p[i][0],p[i][1],0); glEnd(); glPointSize(1.0); if (n < 1) return; glColor3f(0.7,0.7,0); glBegin(GL_LINE_STRIP); for(int i=0; i<= n;i++) glVertex3f(p[i][0],p[i][1],0); glEnd(); } Bezier.h class bezier { float p[20][2]; int n ; int pontos ; public: bezier(int p = 10) { n = -1; pontos = p; } void insert(float x,float y); void remove(float x,float y); float bernstein(int n,int i,float t); void draw_bezier(); float casteljau(float t,int r,int i,int j); void draw_casteljau(); void draw_poligono(); void draw_method_casteljau(); }; main.cpp #include<gl\glut.h> #include "bezier.h" #include <iostream> using namespace std; bezier C(20);

Page 137: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

54

int m = 0; float phi = 0; //235 float theta = 0; //42 float gama = 0; int xi,yi,xf,yf; void inicia() { glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5,5,-5,5,-5,5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gama,0,0,1); glRotatef(phi,1,0,0); glRotatef(theta,0,0,1); } void display() { glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); C.draw_method_casteljau(); C.draw_poligono(); C.draw_casteljau(); glFlush(); glutSwapBuffers(); } void botao(int b,int state,int x,int y) { if (b == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { xi = x; yi = y; } } if (b == GLUT_RIGHT_BUTTON) { if (state == GLUT_DOWN) { float xb = -5 + x/400.0 * 10; float yb = -5 + (400-y)/400.0 * 10; C.insert(xb,yb); glutPostRedisplay(); } } } void botao_movimento(int x,int y) { theta = theta + (xi - x); phi = phi + (yi - y); xi = x; yi = y; inicia();

Page 138: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

55

glutPostRedisplay(); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutCreateWindow("Bezier"); glutDisplayFunc(display); inicia(); glutMouseFunc(botao); glutMotionFunc(botao_movimento); glutMainLoop(); } superficies class bezier { float p[20][2]; float S[20][20][3]; int n ; int m ; int pontos ; public: bezier(int p = 10) { n = -1; m = -1; pontos = p; } bezier(int p = 10,int i = -1,int j = -1) { n = i; m = j; pontos = p; } void insert(float x,float y); void insert(float x,float y,float z,int i,int j); void remove(float x,float y); float bernstein(int n,int i,float t); void draw_bezier(); void draw_sup_bezier(); float casteljau(float t,int r,int i,int j); void draw_casteljau(); void draw_poligono(); void draw_poliedro(); void draw_method_casteljau(); };

Page 139: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

56

#include <gl/glut.h> #include "bezier.h" void bezier::insert(float x,float y) { p[++n][0] = x; p[n][1] = y; } void bezier::insert(float x,float y,float z,int i,int j) { S[i][j][0] = x; S[i][j][1] = y; S[i][j][2] = z; } void bezier::remove(float x,float y) { } float bezier::bernstein(int n,int i,float t) { float ti = 1; float ti1 = 1; float s = 1; for (int j = 0;j < i ; j++) { s *= (n-j)/(float)(i-j); ti *= t; } for(int j = 0; j < n-i; j++) { ti1 *= (1-t); } return(s * ti * ti1); } void bezier::draw_bezier() { float t; float x,y; float dt = 1.0/pontos; if (n < 1) return; t = 0; glColor3f(1,0,0); glBegin(GL_LINE_STRIP); for (int i = 0;i <= pontos; i++) { x = 0; y = 0; for(int j=0; j <= n;j++) { x += p[j][0] * bernstein(n,j,t); y += p[j][1] * bernstein(n,j,t); } glVertex3f(x,y,0); t += dt; } glEnd(); }

Page 140: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

57

void bezier::draw_sup_bezier() { float u,v; float x,y,z; float du = 1.0/pontos; float dv = 1.0/pontos; if (n < 1) return; glColor3f(1,0,0); u = 0; for (int a = 0; a <= pontos; a++) { v = 0; glBegin(GL_LINE_STRIP); for (int b = 0; b <= pontos; b++) { x = 0; y = 0; z = 0; for(int i=0; i <= n; i++) { for(int j=0; j <= m; j++) { float bu = bernstein(n,i,u); float bv = bernstein(m,j,v); x += S[i][j][0] * bu * bv; y += S[i][j][1] * bu * bv; z += S[i][j][2] * bu * bv; } } glVertex3f(x,y,z); v += dv; } glEnd(); u += du; } v = 0; for (int a = 0; a <= pontos; a++) { u = 0; glBegin(GL_LINE_STRIP); for (int b = 0; b <= pontos; b++) { x = 0; y = 0; z = 0; for(int i=0; i <= n; i++) { for(int j=0; j <= m; j++) { float bu = bernstein(n,i,u); float bv = bernstein(m,j,v); x += S[i][j][0] * bu * bv; y += S[i][j][1] * bu * bv; z += S[i][j][2] * bu * bv; } } glVertex3f(x,y,z);

Page 141: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

58

u += du; } glEnd(); v += dv; } } void bezier::draw_casteljau() { float t; float x,y; float dt = 1.0/pontos; if (n < 1) return; t = 0.0; glColor3f(1,0,0); glBegin(GL_LINE_STRIP); for (int i = 0;i <= pontos; i++) { x = casteljau(t,n,0,0); y = casteljau(t,n,0,1); glVertex3f(x,y,0); t += dt; } glEnd(); } void bezier::draw_method_casteljau() { float t; float x1,y1,x2,y2; int d = 5; float dt = 1.0/d; if (n < 1) return; t = 0; glColor3f(0,0,1); glBegin(GL_LINES); for(int k = 0; k <= d; k++) { for(int r = 1; r <= n; r++) { for (int i = 0;i <= n-r; i++) { x1 = casteljau(t,r-1,i,0); y1 = casteljau(t,r-1,i,1); x2 = casteljau(t,r-1,i+1,0); y2 = casteljau(t,r-1,i+1,1); glVertex3f(x1,y1,0); glVertex3f(x2,y2,0); } } t += dt; } glEnd(); }

Page 142: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

59

float bezier::casteljau(float t,int r,int i,int j) { if (r == 0) return( p[i][j] ); else return((1-t) * casteljau(t,r-1,i ,j) + t * casteljau(t,r-1,i+1,j)); } void bezier::draw_poligono() { glColor3f(1,1,0); glPointSize(5.0); glBegin(GL_POINTS); for(int i =0;i <= n; i++) glVertex3f(p[i][0],p[i][1],0); glEnd(); glPointSize(1.0); if (n < 1) return; glColor3f(0.7,0.7,0); glBegin(GL_LINE_STRIP); for(int i=0; i<= n;i++) glVertex3f(p[i][0],p[i][1],0); glEnd(); } void bezier::draw_poliedro() { glColor3f(1,1,0); glPointSize(5.0); glBegin(GL_POINTS); for(int i =0;i <= n; i++) for(int j =0;j <= m; j++) glVertex3f(S[i][j][0],S[i][j][1],S[i][j][2]); glEnd(); glPointSize(1.0); if (n < 1) return; glColor3f(0.7,0.7,0); for(int i =0;i <= n; i++) { glBegin(GL_LINE_STRIP); for(int j =0;j <= m; j++) { glVertex3f(S[i][j][0],S[i][j][1],S[i][j][2]); } glEnd(); } for(int j =0;j <= m; j++) { glBegin(GL_LINE_STRIP); for(int i =0;i <= n; i++) { glVertex3f(S[i][j][0],S[i][j][1],S[i][j][2]); } glEnd(); } }

Page 143: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

60

#include<gl\glut.h> #include "bezier.h" #include <iostream> using namespace std; bezier S(20,3,2); int m = 0; float phi = 0; //235 float theta = 0; //42 float gama = 0; int xi,yi,xf,yf; void inicia() { glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5,5,-5,5,-5,5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(gama,0,0,1); glRotatef(phi,1,0,0); glRotatef(theta,0,0,1); } void display() { glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); // C.draw_method_casteljau(); // C.draw_poligono(); // C.draw_casteljau(); S.draw_poliedro(); S.draw_sup_bezier(); glFlush(); glutSwapBuffers(); } void botao(int b,int state,int x,int y) { if (b == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { xi = x; yi = y; } } if (b == GLUT_RIGHT_BUTTON) { if (state == GLUT_DOWN) { float xb = -5 + x/400.0 * 10; float yb = -5 + (400-y)/400.0 * 10; // C.insert(xb,yb); glutPostRedisplay(); }

Page 144: Capítulo I – Introdução a Linguagem C++ 3sinesio/Apostila_C++.pdf · boolean 1-bit (TRUE ou FALSE) ... /** Testa se um numero e par ou impar */ int main() { ... /** Gera a sequencia

61

} } void botao_movimento(int x,int y) { theta = theta + (xi - x); phi = phi + (yi - y); xi = x; yi = y; inicia(); glutPostRedisplay(); } void main(int argc,char **argv) { S.insert(1,0,1,0,0); S.insert(2,-1,2,1,0); S.insert(3,0,2,2,0); S.insert(4,0,1,3,0); S.insert(1,1,0,0,1); S.insert(2,1,2,1,1); S.insert(3,1,0,2,1); S.insert(4,1,1,3,1); S.insert(1,2,1,0,2); S.insert(2,3,3,1,2); S.insert(3,2,2,2,2); S.insert(4,2,1,3,2); glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(400,400); glutCreateWindow("Bezier"); glutDisplayFunc(display); inicia(); glutMouseFunc(botao); glutMotionFunc(botao_movimento); glutMainLoop(); }