1 Capítulo I – Introdução a Linguagem JAVA ____________________________3 1. Estrutura Básica de um Programa em Java ______________________________ 3 1.1 - Primeiro Programa ______________________________________________________ 3 1.2 - Variáveis _____________________________________________________________ 4 1.3 - Operadores ___________________________________________________________ 5 1.4 - Constantes ____________________________________________________________ 6 1.5 - Comentários___________________________________________________________ 7 1.6 - Fluxo de Controle_______________________________________________________ 7 Comando if () {} __________________________________________________________ 8 Comando for( ; ; ) {} _______________________________________________________ 9 O método de Simpson ____________________________________________________ 11 Comando break e continue ________________________________________________ 13 2 - VETORES E MATRIZES _____________________________________________ 14 2.1 - Vetores______________________________________________________________ 2.2 - Declaração ___________________________________________________________ 2.3 - Inicializando vetores____________________________________________________ 2.4 – Exemplo: Método de Ordenação__________________________________________ 2.5 - Matrizes _____________________________________________________________ 2.6 – Exemplo: Produto de uma matriz por um vetor_______________________________ 14 16 16 16 18 18 3 – OBJETOS E CLASSES _____________________________________________ 19 3.1 – Membros da Classe ___________________________________________________ 3.2 – Construtores _________________________________________________________ 3.3 – Métodos_____________________________________________________________ 3.3.1 - Introdução ________________________________________________________ 3.3.2 – Modificadores do Método____________________________________________ 3.3.3 – Campos Static ____________________________________________________ 3.3.4 – Exemplo de uma Classe Vetor________________________________________ 19 21 23 23 24 24 27 2 Capítulo I – Introdução a Linguagem JAVA Java é uma linguagem de programação orientada a objeto com grande popularidade entre os usuários de internet. Uma das razões de sua popularidade na web é que o Java gera applets para a web. Um applet é um aplicativo para ser executado nas páginas web. Porém o Java também é amplamente utilizado em outros domínios além da internet principalmente por sua característica multi-plataforma e no aspecto segurança. 1. Estrutura Básica de um Programa em Java A linguagem Java tem uma estrutura muito semelhante a C++ e por esta razão os usuários que aprendem Java como primeira linguagem de programação não tem dificuldades de futuramente programar em C++ também. 1.1 - Primeiro Programa Em Java os programas são escritos utilizando-se classes. Inicialmente vamos aprender os comandos básicos do Java e na seção 4 discutiremos o funcionamento das classes e a orientação a objeto. Como primeiro exemplo, consideremos o programa: HelloWorld.java class Hello { public static void main(String[] args) { System.out.println("Ola"); } } Para compilar execute: javac HelloWorld.java O resultado será a geração do arquivo: Hello.class Observe que o nome do arquivo gerado tem extensão .class e o nome corresponde ao nome da classe (Hello.class), e não ao original nome do arquivo compilado (HelloWorld.java) 3 E finalmente para executar: java Hello O resultado será a exibição da mensagem: “Hello”. Possíveis problemas: 1) Se na compilação ocorrer o seguinte erro: 'javac' is not recognized as an internal or external command, operable program or batch file. solução: verifique se o java está instalado e acrescente no path do windows o diretório C:\jdk5.0\bin. Para alterar o path vá para: Control Panel-> System -> Advanced -> Environment Variables. No primeiro quadro, User variables for ... edit a variável path e acrescente o diretório do java. 2) Se na compilação ocorrer o seguinte erro: Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorldApp solução: vá para: Control Panel-> System -> Advanced -> Environment Variables. No primeiro quadro, User variables for ... pressione new e acrescente: variable name: CLASSPATH variable value: . (obs:apenas um ponto) 1.2 - Variáveis O programa a seguir exibe como é feita a declaração de algumas variáveis e sua utilização. public class Input { public static void main(String[] args) { int n = 1; float a = 2.3e10f; double b = 34.5e200; } System.out.println("n = " + n + " a = " + a + " b = " + b); } 4 As primeiras linhas declaram as variáveis e os tipos: int Tipo da variável n; Nome da variável Em seguda atribuimos o valor 1 para a variável: n = 1; O Java tem diferentes tipos de variáveis: boolean char byte short int long float double TRUE ou FALSE 16-bit Unicode 2.1 character 8-bit inteiro (signed) 16-bit inteiro (signed) 32-bit inteiro (signed) 64-bit inteiro (signed) 32-bit floating-point 64-bit floating point 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; E é 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: 5 Raizes.java class Raizes { public static void main(String[] args) { double a,b,c; double x1,x2; a = 1; b = -5; c = 6; x1 = (-b + Math.sqrt(b*b - 4*a*c)) / (2 * a); x2 = (-b - Math.sqrt(b*b - 4*a*c)) / (2 * a); System.out.println("x1 = " + x1 + " x2 = " + x2); } } 1.4 - Constantes Uma constante é um valor constante que é definido no programa de forma que não será alterado durante toda a execução. Assim por exemplo, no programa anterior não pretendemos alterar os valores de a, b e c, e gostaríamos que estes valores ficassem registrados por alguma referência que pudesse auxiliar futuramente seu significado. Para declararmos uma constante utilizamos o prefixo final, como no exemplo: Raizes.java class Raizes { public static void main(String[] args) { final double a = 1; final double b = -5; final double c = 6; double x1,x2; x1 = (-b + Math.sqrt(b*b - 4*a*c)) / (2 * a); x2 = (-b - Math.sqrt(b*b - 4*a*c)) / (2 * a); System.out.println("x1 = " + x1 + " x2 = " + x2); } } 6 1.5 - Comentários É possível introduzir comentários dentro de um programa em Java, bastando para isso colocá-los nos seguintes formatos: /* Comentario pode prosseguir por varias linhas e so termina ao encontar a marca de fim de comentario */ /** Normalmente usado no inicio das classes */ // Comentario somente até o final da linha Observe o exemplo abaixo: class Raizes { /** Soluções reais da equação ax*x + b*x + c = 0 public static void main(String[] args) { double a,b,c; double x1,x2; */ a = 1; // Valores arbitrarios para a,b, e c b = -5; c = 6; x1 = (-b + Math.sqrt(b*b - 4*a*c)) / (2 * a); x2 = (-b - Math.sqrt(b*b - 4*a*c)) / (2 * a); System.out.println("x1 = " + x1 + " x2 = " + x2); } } 1.6 - Fluxo de Controle O comando principal de decisão é o if() { }. Os dois dos formatos mais utilizados de laços são: while() {} for( ; ;) { } 7 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: class ExemploIf { /** Testa se um numero e par ou impar */ public static void main(String[] args) { int i,n; n = 7; // Entre com n i = n % 2; if (i == 0) { System.out.println("\n n e um numero par\n"); } else { System.out.println("\n 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 println("\n n e um numero par\n"). Se a condição falha, o comando else indica que o programa deve executar o comando println("\n 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 8 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: Fibonacci2.java class Fibonacci2 { public static void main(String[] args) { int n; int lo = 1; int hi = 1; final int MAX = 10; System.out.println("1: 1"); for(n = 2;n <= MAX; n++) { System.out.println(n + ": " + hi); 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 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 . class Integral { /** Integracao Numerica: Ponto a Esquerda */ public static void main(String[] args) { int i; int n; double x,dx ; double a,b ; double soma; 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; for(i=0; i < n; i++) { soma = soma + Math.sqrt(1-x*x) * dx; x = x + dx; } System.out.println("\nIntegral = "+ 2*soma); } 10 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. import java.util.*; public class MonteCarlo { public static void main(String[] args) { Random rn = new Random(); double x,y,f; long cont = 0; final long points = 500000; for (long i = 0; i < points; i++) { x = rn.nextDouble(); y = rn.nextDouble(); if ((x*x+y*y-1) < 0) cont++; } f = 4.0*cont/points; System.out.println("Pi = "+ String.valueOf(f) } } 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]. public class Simpson { public static void main(String[] args) { int i; int n; double x,dx ; double a,b ; double soma; 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 = Math.sqrt(1-x*x); for(i=1; i < n; i++) { x = x + dx; if (i % 2 == 0) soma = soma + 2 * Math.sqrt(1-x*x); 11 else soma = soma + 4 * Math.sqrt(1-x*x); } x = b; soma = soma + Math.sqrt(1-x*x); soma = soma * dx/3; System.out.println("\nIntegral = "+ 2*soma); System.out.println("\nErro = " + (2*soma-Math.PI)); } } Comando 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. Neste exemplo, primeiro é feito o teste: while (n < 10) e somente em caso verdadeiro os comando dentro do while são executados. Assim se a condição for falsa a primeira vez, em nenhum momento os comandos dentro do laço serão executados. O exemplo abaixo ilustra a utilização do comando: Exemplo: Método de Newton O programa abaixo determina as raízes da função: utilizando o método de Newton, ou seja, dada uma condição inicial x0, e um erro máximo, a seqüência abaixo pode convergir para uma das raízes: class Newton { /** Metodo de Newton */ public static void main(String[] args) { int i = 0 ; double xn,x0,xn_1 ; double erro ; x0 = 2; // Condicao inicial erro = 0.0000001; // Erro maximo xn = x0; xn_1 = xn + 2 * erro; // Garante a entrada no while 12 while (Math.abs(xn - xn_1) > erro) { xn_1 = xn; xn = xn_1 - (xn_1 * xn_1 - 2) / (2 * xn_1); i++; System.out.println("\nx[" + i + "] =" + xn); } System.out.println("\n A raiz obtida: "+ xn + "\n"); } } Comando break e continue Estes dois comando sservem 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.java class Exemplobreak { public static void main(String[] args) { int n = 0; while (n < 10) { System.out.println("n = " + n); if (n > 3) break; n++; } System.out.println("Fim do programa \n"); } } O resultado deste programa será: n = n = n = n = n = Fim 0 1 2 3 4 do programa - O comando continue; transfere a execução do programa para o teste do laço, que pode ou não prosseguir caso a condição seja verdadeira ou falsa. Exemplo: Método da Bisseção 13 O programa abaixo determina as solucoes da equacao: Para isso utilizaremos o método da bisseção. No método da bisseção procuramos uma raiz contida em certo intervalo [a,b] dado. A raiz 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.java class Bissecao { public static void main(String[] args) { double a,b,c; double fa,fb,fc; final double erro = 0.0000001; a = 0; // Entre com o extremo a b = 2; // Entre com o extremo b fa = a*a - 2; fb = b*b - 2; c=0; if ((fa * fb) > 0) { System.out.println("\nCondicao inicial nao contem raiz !\n"); return; } while(Math.abs(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; } System.out.println("\n Raiz parcial = " + c); } System.out.println("\n\n Raiz obtida = " + c); return; } } 2 - VETORES E MATRIZES 2.1 - Vetores 14 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 15 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 15 variáveis, utilizamos uma variável do tipo vetor, definida como abaixo: float notas[15]; o programa completo seria: public class notas { public static void main(String[] args) { int i ; float media ; float soma = 0 ; float[] notas = new float[5]; for(i=0;i < 15;i++) { System.out.println(" Aluno " + (i+1)2 + ":"); notas[i] = TextIO.getlnFloat();; } for(i=0;i<15;i++) soma = soma + notas[i]; media = soma / 15; System.out.println("\n A media final foi: " + media); } } Nós podemos melhorar o programa anterior, solicitando ao usuário o número de alunos da turma e só então alocando o vetor de notas. Veja abaixo: public class notas1 { public static void main(String[] args) { int i,n float media float soma = 0 float[] notas ; ; ; ; System.out.println("Numero de alunos:"); n = TextIO.getInt(); notas = new float[n]; for(i=0; i < notas.length ;i++) { System.out.println(" Aluno " + (i+1) + ":"); notas[i] = TextIO.getlnFloat();; 15 } for(i=0;i< notas.length;i++) soma = soma + notas[i]; media = soma / notas.length; } System.out.println("\n A media final foi: " + media); } 2.2 - Declaração Um vetor é uma coleção de variáveis de certo tipo, alocadas seqüencialmente na memória. Para Java um declaração de variável vetor do tipo: int[] n = new int[5]; reserva o espaço de 5 variáveis do tipo inteira, onde cada variável pode ser referenciada conforme abaixo: 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 atribui um valor a um dos componentes do vetor basta referenciá-lo: n[3] = 29; resulta em: 29 n[0] n[1] n[2] n[3] n[4] 2.3 - Inicializando vetores 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 = {23, 3, -7, 288, 14}; 2.4 – Exemplo: Método de Ordenação 16 Como exemplo vamos apresentar um programa que ordena uma seqüência de 10 números reais. public class Bolha { /* * * * * * * * * * * * * * * * * * * * * */ /* Metodo da Bolha (ordenacao de um vetor) */ /* * * * * * * * * * * * * * * * * * * * * */ public static void main(String[] args) { int i,n ; int flag; double swap; double[] x; /* Entrada de Dados */ System.out.println("Numero de elementos:"); n = TextIO.getInt(); x = new double[n]; System.out.println("Entre com os numeros para ordenacao"); for(i=0;i<n;i++) { System.out.println("x[" + i + "]: "); x[i] = TextIO.getDouble(); } /* 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] ; x[i] = x[i+1]; x[i+1] = swap ; flag = 1 ; } } } /* Imprime a sequencia de numeros ordenada */ System.out.println("Sequencia ordenada : "); for(i=0; i<x.length; i++) System.out.println(" " + x[i]); } } 17 2.5 - Matrizes Para representar uma matriz 3x4 (3 linha e 4 colunas) de números reais utilizamos a seguinte declaração: float[][] A = new float[3][4]; Assim fica reservado um espaço de memória conforme a figura abaixo: A[0][0] A[1][0] A[2][0] A[0][1] A[1][1] A[2][1] A[0][2] A[1][2] A[2][2] A[0][3] A[1][3] A[2][3] 2.6 – Exemplo: Produto de uma matriz por um vetor Vamos montar um programa que multiplica um vetor por uma matriz. public class produto { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int i,j; double[][] A = {{ 1.0, 1.5, 2.1}, { 3.4, 2.2, 9.1}, {-1.2, -3.4, 0.9}}; double[] v = {2.0, 1.0, 0.5}; double[] p = new double[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++) { System.out.print("["); for(j=0;j<3;j++) System.out.print(" " + A[i][j]); System.out.print(" ] "); System.out.println(" [" + v[i] + "]"); } for(i=0;i<3;i++) System.out.println(" p[" + i + "] =" + p[i]); } } 18 3 – OBJETOS E CLASSES 3.1 – Membros da Classe Uma classe tem dois tipos principais de membros: 1. Campos: correspondem aos dados, representados pelas variáveis da classe. 2. Métodos: contêm o código executável e define o comportamento dos objetos. Vamos iniciar com um exemplo, definindo um círculo: circulo.class public class circulo { public double raio; public double centrox,centroy; } O programa abaixo utiliza a classe circulo: main.class public class main { public static void main(String[] args) { circulo A; A = new circulo(); A.raio = 2.5; A.cx = 1.0; A.cy = 1.0; System.out.println("Circulo de Raio = " + A.raio); System.out.println("Circulo e Centro = ( " + A.cx + " , " + A.cy + " )"); } } 19 Inicialização da classe A declaração feita no programa main: circulo A; não cria o objeto círculo, apenas estabelece que a variável “A” será uma referência para um objeto do tipo circulo. Somente com o comando: A = new circulo(); foi criado o objeto círculo. Modificadores da Classe Na definição da classe podemos definir quatro modificadores da classe: 1) public: a classe tem acesso público 2) abstract: é uma classe incompleta, que possui abstract métodos que necessitam ser implementados por alguma subclasse. 3) final: não pode seu um asubclasse. 4) strict floating point: strictfp tem todas as operações aritméticas em ponto flutuante definidas dentro da classe. Controle de Acesso aos Campos Observe que todos os campos definidos na classe círculo possuem o prefixo public. Este elemento define o controle de acesso ao campo, definindo assim se um dado campo da classe pode ou não ser alterado por outra classe. Existem quatro modificadores de acesso: 1) private: campos definidos private somente são acessíveis na própria classe. 2) public: são acessíveis por qualquer classe. 3) package: acessíveis em classe do mesmo pacote (será definido posteriormente). 4) protected: são acessíveis em subclasses, classes do mesmo pacote e na própria classe. Modificadores de Campo Observe que todos os campos definidos na classe círculo possuem o prefixo public. Este elemento define o controle de acesso ao campo, definindo assim se um dado campo da classe pode ou não ser alterado por outra classe. Além dos quatro modificadores de acesso, temos também modificadores de acesso: 1) static: o campo static é instanciado somente uma vez para todos os objetos da classe. 2) final: não pode ser trocado após a inicialização. 3) transient. 4) volatile. 20 3.2 – Construtores Quando um objeto é criado pelo comando new, seus campos são iniciados com valores default. Muitas vezes gostaríamos de definir como os campos devem ser iniciados, e possivelmente executar alguns comandos específicos da criação do objeto. Neste caso utilizamos os construtores. 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). Exemplo 1 (Construtor sem parâmetros): public class circulo { public double raio; public double cx,cy; } circulo() { raio = 1.0; cx = 0; cy = 0; } public class main { public static void main(String[] args) { circulo A,B; A = new circulo(); B = new circulo(); A.raio = 2.5; A.cx = 1.0; A.cy = 1.0; System.out.println("Circulo A de Raio = " + A.raio); System.out.println("Circulo A de Centro = ( " + A.cx + " , " + A.cy + " )"); System.out.println("Circulo B de Raio = " + B.raio); System.out.println("Circulo B de Centro = ( " + B.cx + " , " + B.cy + " )"); } } 21 Exemplo 2 (com parâmetros): public class circulo { public double raio; public double cx,cy; circulo() { raio = 1.0; cx = 0; cy = 0; } } circulo(double r,double x,double y) { raio = r; cx = x; cy = y; } public class main { public static void main(String[] args) { circulo A,B,C; A = new circulo(); B = new circulo(); C = new circulo(5, -1, 2.34); A.raio = 2.5; A.cx = 1.0; A.cy = 1.0; System.out.println("Circulo A de Raio = " + A.raio); System.out.println("Circulo A de Centro = ( " + A.cx + " , " + A.cy + " )"); System.out.println("Circulo B de Raio = " + B.raio); System.out.println("Circulo B de Centro = ( " + B.cx + " , " + B.cy + " )"); System.out.println("Circulo C de Raio = " + C.raio); System.out.println("Circulo C de Centro = ( " + C.cx + " , " + C.cy + " )"); } } 22 3.3 – Métodos 3.3.1 - Introdução Um método 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. Exemplo 3 (metodo area): public class circulo { public double raio; public double cx,cy; circulo() { raio = 1.0; cx = 0; cy = 0; } circulo(double r,double x,double y) { raio = r; cx = x; cy = y; } public double area() { double a; } a = Math.PI * raio * raio; return(a); } public class main { public static void main(String[] args) { circulo A,B,C; A = new circulo(); B = new circulo(); C = new circulo(5, -1, 2.34); A.raio = 2.5; A.cx = 1.0; A.cy = 1.0; System.out.println("Circulo A de Raio = " + A.raio); System.out.println("Circulo A de Centro = ( " + A.cx + " , " + A.cy + " )"); System.out.println("Circulo A de Area = " + A.area()); System.out.println("Circulo B de Raio = " + B.raio); 23 System.out.println("Circulo B de Centro = ( " + B.cx + " , " + B.cy + " )"); System.out.println("Circulo B de Area = " + B.area()); System.out.println("Circulo C de Raio = " + C.raio); System.out.println("Circulo C de Centro = ( " + C.cx + " , " + C.cy + " )"); System.out.println("Circulo C de Area = " + C.area()); } } 3.3.2 – Modificadores do Método Observe que na definição de nosso método: public double area() { existem dois elementos a serem destacados: 1) public double area() O elemento double indica que nosso método retorna um campo double, pois estamos retornando um valor no double no comando: return(a) 2) public double area() O elemento public é denominado modificador do método e é semelhante aos modificadores de campo. Para o método existem os seguintes modificadores: • private: métodos definidos private somente são acessíveis na própria classe. • public: são acessíveis por qualquer classe. • package: acessíveis em classe do mesmo pacote (será definido posteriormente). • protected: são acessíveis em subclasses, classes do mesmo pacote e na própria • • • • • • abstract: o corpo do método não é definido nesta classe. Uma subclasse fica responsável pela implementação do método. static: veja na próxima seção. final: não permite ser sobreposto por uma subclasse. synchronized: será discutido em outras seções. native: será discutido em outras seções. strictfp: strict floating point tem todas as operações de ponto flutuante avalias estritamente. 3.3.3 – Campos Static 24 O exemplo abaixo ilustra a utilização de um campo static. Exemplo 4: (static) public class circulo { public double raio; public double cx,cy; private static long Id = 0; circulo() { raio = 1.0; cx = 0; cy = 0; Id++; } circulo(double r,double x,double y) { raio = r; cx = x; cy = y; Id++; } public double area() { double a; } } a = Math.PI * raio * raio; return(a); public long getId() { return Id; } public class main { public static void main(String[] args) { circulo A,B,C; A = new circulo(); B = new circulo(); C = new circulo(5, -1, 2.34); A.raio = 2.5; A.cx = 1.0; A.cy = 1.0; System.out.println("Circulo System.out.println("Circulo + A.cy + " )"); System.out.println("Circulo System.out.println("Circulo A de Raio = " + A.raio); A de Centro = ( " + A.cx + " , " A de Area = " + A.area()); No = " + A.getId()); 25 System.out.println("Circulo System.out.println("Circulo + B.cy + " )"); System.out.println("Circulo System.out.println("Circulo B de Raio = " + B.raio); B de Centro = ( " + B.cx + " , " System.out.println("Circulo System.out.println("Circulo + C.cy + " )"); System.out.println("Circulo System.out.println("Circulo } C de Raio = " + C.raio); C de Centro = ( " + C.cx + " , " B de Area = " + B.area()); No = " + B.getId()); C de Area = " + C.area()); No = " + C.getId()); } Por que todos os Id são iguais ? Porque Id é static ! Para enumerarmos as esferas será necessário criar um campo não static na classe. Exemplo 5: (enumerando cada esfera) public class circulo { public double raio; public double cx,cy; private static long Id = 0; private long MyId; circulo() { raio = 1.0; cx = 0; cy = 0; MyId = Id++; } circulo(double r,double x,double y) { raio = r; cx = x; cy = y; MyId = Id++; } public double area() { double a; } } a = Math.PI * raio * raio; return(a); public long getId() { return Id; } public long getMyId() { return MyId; } public class main { 26 public static void main(String[] args) { circulo A,B,C; A = new circulo(); B = new circulo(); C = new circulo(5, -1, 2.34); A.raio = 2.5; A.cx = 1.0; A.cy = 1.0; System.out.println("Circulo System.out.println("Circulo + A.cy + " )"); System.out.println("Circulo System.out.println("Circulo A de Raio = " + A.raio); A de Centro = ( " + A.cx + " , " System.out.println("Circulo System.out.println("Circulo + B.cy + " )"); System.out.println("Circulo System.out.println("Circulo B de Raio = " + B.raio); B de Centro = ( " + B.cx + " , " System.out.println("Circulo System.out.println("Circulo + C.cy + " )"); System.out.println("Circulo System.out.println("Circulo C de Raio = " + C.raio); C de Centro = ( " + C.cx + " , " A de Area = " + A.area()); No = " + A.getMyId()); B de Area = " + B.area()); No = " + B.getMyId()); C de Area = " + C.area()); No = " + C.getMyId()); System.out.println("Total de círculos = " + A.getId()); } } 3.3.4 – Exemplo de uma Classe Vetor O exemplo abaixo ilustra a implementação de uma classe vetor de double. Exemplo 6: Vetores public class Vetor { private double[] v; private int dim; Vetor(int n){ dim = n; v = new double[n]; } 27 Vetor(double[] C){ dim = C.length; v = new double[dim]; for(int j=0;j<dim;j++) v[j]=C[j]; } // Metodos de Acesso public void set(int i,double x){ if ((i >= 0) && (i<dim)) v[i]=x; } public double get(int i) { if ((i >= 0) && (i<dim)) return (v[i]); else return 0; } } public class main { public static void main(String[] args) { Vetor x = new Vetor(4); x.set(0,1.2); x.set(1,-2); x.set(2,-4); x.set(3,3.2); x.get(i)); } for(int i=0;i<4;i++){ System.out.println("v[" + i + "]= " + } } 28 CAPÍTULO II – VISUALIZAÇÃO E APLICAÇÕES GRÁFICAS 2D __________ 3 1 - PONTOS E RETAS NO OPENGL ______________________________________ 3 1.1 – A Tela do Computador ___________________________________________ 3 1.2 – Cores_________________________________________________________ 3 1.3 – Introdução ao JoGL______________________________________________ 4 1.3.1 – Apresentação______________________________________________________ 4 1.3.2 – Instalação_________________________________________________________ 4 1.4 – Exemplo: Criando a janela OpenGL _________________________________ 6 1.5 – Exemplo: Plotar um ponto na tela utilizando as bibliotecas do OpenGl ______ 6 1.5 – Comando: gluOrtho2D ___________________________________________ 9 1.6 – Exemplo: Plotar uma reta unindo dois pontos ________________________ 10 1.6.1 – Algoritmo ingênuo _________________________________________________ 10 1.6.3 – Retas no Opengl __________________________________________________ 12 1.7 – Exemplo: Plotar o gráfico de uma função ____________________________ 12 2 – TECLADO E MOUSE (Callbacks) ____________________________________ 19 2.1 – Introdução ____________________________________________________ 19 2.2 – Teclado ______________________________________________________ 19 2.3 – Exemplo: Utilização do teclado no programa funções. __________________ 19 2.4 – Mouse _______________________________________________________ 21 2.4.1- Interrupções a partir do mouse ________________________________________ 21 2.4.2- Aplicações: Realizando o “zoom” do gráfico ______________________________ 26 3 – CURVAS PARAMÉTRICAS _________________________________________ 32 3.1 – Introdução ____________________________________________________ 32 3.2 – Exemplo: Visualização de Curvas Paramétricas ______________________ 32 3.2.1 – Módulo main.java__________________________________________________ 32 3.2.2 – Módulo curva _____________________________________________________ 35 3.2.4 –Exercício _________________________________________________________ 37 3.3 – Curvas na forma Polar __________________________________________ 37 3.4 – Exemplo: Visualização de Curvas Polares ___________________________ 38 3.5 – Exercícios ____________________________________________________ 39 4 – CURVAS IMPLÍCITAS _____________________________________________ 40 4.1 – Introdução ____________________________________________________ 40 4.2 – Visualização de Curvas Implícitas _________________________________ 40 4.3 – Programa Curva Implícita ________________________________________ 41 4.4 –Exercício _____________________________________________________ 42 5 – RETAS E POLÍGONOS NO OPENGL _________________________________ 43 5.1 – Retas e Polígonos______________________________________________ 43 5.2 – Exemplo: Visualização dos Métodos Numéricos de Integração ___________ 44 6 – PROCESSAMENTO DE IMAGEM ____________________________________ 46 6.1 – Introdução ____________________________________________________ 46 7 – FRACTAIS ______________________________________________________ 53 1 7.1 – Conjuntos auto-semelhantes _____________________________________ 53 7.2 – Dimensão Hausdorff e o conceito de fractal __________________________ 54 7.3 – Exemplos de fractais ____________________________________________ 54 7.3.1- Triângulo de Sierpinski ______________________________________________ 7.3.2- Triângulo de Sierpinski utilizando Monte Carlo ____________________________ 7.3.3- “Fern” ____________________________________________________________ 7.4 – Conjunto de Julia ___________________________________________________ 55 61 62 65 2 CAPÍTULO II – VISUALIZAÇÃO E APLICAÇÕES GRÁFICAS 2D 1- PONTOS E RETAS NO OPENGL 1.1 – A Tela do Computador A tela do computador pode ser considerada uma matriz de células discretas (Pixels), cada qual pode estar acesa ou apagada. 0,1 1,1 2,1 … 0,0 1,0 2,0 … A definição da tela varia conforme o monitor e a placa gráfica. As definições básicas encontradas na maioria dos monitores são: 640 x 480 800 x 600 1024 x 768 1280 x 1024 1.2 – Cores A cada pixel associamos uma cor. Para obter uma cor, o monitor envia certa combinação de vermelho, verde e azul (RGB). 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. O tamanho deste buffer é usualmente medido em bits. 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ásica 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 desejadas. 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 Verde Azul Amarelo Cyan Magenta Branco Preto 1.0 0.0 0.0 1.0 0.0 1.0 1.0 0.0 0.0 1.0 0.0 1.0 1.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 1.0 1.0 1.0 0.0 3 1.3 – Introdução ao JoGL 1.3.1 – Apresentação O sistema gráfico OpenGL (GL significa Graphics Library) é uma biblioteca (de aproximadamente 350 comandos) 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 rotinas permitem gerar primitivas (pontos, linhas, polígonos, etc) e utilizar recursos de iluminação 3D. 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: X Window System (Unix), Windows 95 e NT, OS/2 , Macintosh, etc. Várias tentativas foram feitas no sentido de desenvolver uma versão do OpenGL para Java com algum sucesso, mas somente agora com a parceria entre a Sun (criadora do Java) e a Silicon Graphics (criadora do OpenGL) esta sendo desenvolvido uma versão oficial. 1.3.2 – Instalação Inicialmente você deve obter duas bibliotecas na internet, no link: https://jogl.dev.java.net/servlets/ProjectDocumentList?folderID=3631&expandFolder=3631&folderID=4 843 Os programa executados e testados nestas notas de aulas foram feitos utilizando-se: Release Builds2005(0) - > 1.1 – June 24 (12) (veja abaixo) jogl (0)/ • Release Builds 2003 (6)/ • Release Builds 2004 (0)/ • Release Builds 2005 (0)/ o 1.1.1 - July 12 (12)/ o 1.1b08 - February 7 (11)/ o 1.1b09 - February 15 (11)/ o 1.1b10 - February 27 (11)/ o 1.1b11 - May 11 (12)/ o 1.1 b12 - May 27 (12)/ o 1.1 - June 24 (12)/ o JSR-231 beta 01 - October 27 (11)/ • Release Builds 2006 (0)/ • Temporary Files (4 4 São necessários dois pacotes (em destaque na tabela abaixo): 1. jogl.jar 2. jogl-natives-win32.jar (para usuários do windows XP) 1.1 - June 24 JOGL 1.1 release build Filter this list Name Status Modified by Size Reservations Description javadoc_public.zip Draft kbr on Friday, June 1004.52 24, 2005 at 5:01:27 kB PM JOGL Javadoc Info jogl.jar Draft kbr on Friday, June 24, 2005 at 5:02:02 1.12 mB PM JOGL classes Info jogl-demos.jar Draft kbr on Friday, June 258.32 24, 2005 at 5:06:43 kB PM JOGL demo classes Info jogl-demos-data.jar Draft kbr on Friday, June 24, 2005 at 5:07:13 7.49 mB PM JOGL demo data files Info jogl-demos-src.zip Draft kbr on Friday, June 24, 2005 at 5:07:43 7.8 mB PM JOGL demo source code Info jogl-demos-util.jar Draft kbr on Friday, June 139.06 24, 2005 at 7:03:14 kB PM JOGL demo utility classes Info jogl-nativeslinux.jar Draft kbr on Friday, June 300.06 24, 2005 at 5:03:22 kB PM JOGL native libraries for Linux/x86 Info jogl-nativesmacosx.jar Draft kbr on Friday, June 146.79 24, 2005 at 5:03:49 kB PM JOGL native libraries for Mac OS X 10.3+ Info jogl-nativessolsparc.jar Draft kbr on Friday, June 268.07 24, 2005 at 5:04:18 kB PM JOGL native libraries Info for Solaris/SPARC 2.8+ jogl-nativessolx86.jar Draft kbr on Friday, June 241.16 24, 2005 at 5:04:58 kB PM JOGL native libraries for Solaris/x86 2.9+ Info jogl-nativeswin32.jar Draft kbr on Friday, June 24, 2005 at 5:05:26 60.1 kB PM JOGL native libraries for Windows/x86 Info jogl-src.zip Draft kbr on Friday, June 24, 2005 at 5:05:56 1.09 mB PM JOGL source code Info 5 Passos para a instalação (usando o Eclipse): 1) Dê download nos dois arquivos citados. 2) Copie o arquivo jogl.jar para o diretório: C:\Programs Files\Java\j2re1.4.2_10\lib\ext 3) Utilizando o WinRAR (por exemplo), descomprima o arquivo jogl-natives-win32.jar (o resultado serão dois arquivos: jogl.dll e jogl_cg.dll e o diretorio META-INF. Copie estes arquivos para o diretório: C:\Programs Files\Java\j2re1.4.2_10\bin OBS: O diretorio .../j2re1.4.2_10/... pode ser diferente conforme a versão do java. Voce pode verificar executando o Eclipse e verificando o campo JRE_System Library que aparece em qualquer dos projetos. 1.4 – Exemplo: Criando a janela OpenGL import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class canvas { /** * @param args */ public static void main(String[] args) { Frame frame = new Frame("Hello World"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); frame.add(canvas); frame.setSize(300, 300); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.show(); } } 1.5 – Exemplo: Plotar um ponto na tela utilizando as bibliotecas do OpenGl import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class ponto { public static void main(String[] args) { Frame frame = new Frame("Ponto"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(300, 300); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } 6 }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GLU glu = drawable.getGLU(); glu.gluOrtho2D(0,399,0,399); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glClearColor(1.0f,1.0f,1.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_POINTS); gl.glVertex2f(200.0f,200.0f); gl.glEnd(); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } } Vamos comentar alguns comandos: Frame frame = new Frame("Ponto"); A classe Frame somente cria uma janela. Este é um recurso do Java e é fornecido pelo pacote java.awt GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); Cria a área de rendering do OpenGL no frame anteriormente criado. canvas.addGLEventListener( new JoglRender() ); Interrupção quando ocorre um evento no canvas do OpenGL frame.add(canvas); Adiciona o canvas do OpenGL no frame do java frame.setSize(300, 300); frame.setLocation(50,50); Define parâmetros de inicialização do frame frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); Interrupção do frame do Java. Existem outras interrupções além do windowClosing. static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { Esta a função será executada sempre que a janela for criada. GLU glu = drawable.getGLU(); glu.gluOrtho2D(0,399,0,399); Este comando estabelece a escala da tela. Sua sintaxe é: gluOrtho2D(GLdouble left, Gldouble right, Gldouble bottom, Gldouble top); } public void display(GLDrawable drawable) { Esta a função será executada sempre que a janela necessita ser redesenhada. GL gl = drawable.getGL(); 7 gl.glClearColor(1.0f,1.0f,1.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_POINTS); gl.glVertex2f(200.0f,200.0f); gl.glEnd(); gl.glFlush(); } Quando a função display é executada temos o seguinte resultado: gl.glClearColor(1.0f,1.0f,1.0f,1.0f); Indica cor para ser utilizada no fundo da tela. gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); Pinta os buffers indicados com a cor do glClearColor() glColor3f(1.0,0.0,0.0); Define o vermelho como cor atual. glBegin(GL_POINTS); glVertex2f(200.0f,200f.0); glEnd(); Plota um ponto na posição (200,200) na tela. glFlush(); Imprime o conteúdo do buffer na tela. public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} Métodos que não foram implementados e correspondem respectivamente as interrupções de alteração do display e mudança de dimensão da tela. Exercícios: 1) Acrescente um contador para verificar quantas vezes a função display é chamada. static class JoglRender implements GLEventListener { static int i = 0; public void init(GLDrawable drawable) { GLU glu = drawable.getGLU(); glu.gluOrtho2D(0,399,0,399); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glClearColor(1.0f,1.0f,1.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glPointSize(5.0f); gl.glBegin(GL.GL_POINTS); gl.glVertex2f(200.0f,200.0f); gl.glEnd(); gl.glFlush(); 8 } System.out.println(i); i++; public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } 1.5 – Comando: gluOrtho2D Na maioria de nossas aplicações desejamos nos referenciar a um ponto na tela, não por coordenadas correspondendo as dimensões informadas no comando frame.setSize(300, 300), mas sim levando-se em conta o domínio de visualização relacionado ao problema. Para isso, o comando 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. import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class ortho { public static void main(String[] args) { Frame frame = new Frame("Ortho"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(300, 300); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GLU glu = drawable.getGLU(); glu.gluOrtho2D(0,300,0,300); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); float x = -0.5f; 9 float float float float float y L R T B = 0.5f; = -1.0f; = 1.0f; = 1.0f; = -1.0f; gl.glClearColor(1.0f,1.0f,1.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glPointSize(4.0f); float xo = float yo = ((x - L)/(R-L)*(299)); ((y - B)/(T-B)*(299)); gl.glBegin(GL.GL_POINTS); gl.glVertex2f(xo,yo); gl.glEnd(); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } } 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 ingênuo de como plotar a reta definida por dois pontos */ /* -------------------------------------------------------------- */ import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class reta { public static void main(String[] args) { Frame frame = new Frame("Reta"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(300, 300); frame.setLocation(50,50); 10 frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GLU glu = drawable.getGLU(); glu.gluOrtho2D(-3,3,-3,3); } public void display(GLDrawable drawable) { double y; GL gl = drawable.getGL(); gl.glClearColor(1.0f,1.0f,1.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_POINTS); for (double x = -3;x <= 3;x+=0.001) { y = 2*x - 1; gl.glVertex2f((float)x,(float)(y)); } gl.glEnd(); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } } 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. Exercício: Desenhe várias retas preeenchendo a tela e teste a velocidade, como por exemplo: ... gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_POINTS); for (double b = -10; b <= 10; b+=0.01) { for (double x = -3;x <= 3; x+=0.001) { y = 2*x + b; 11 gl.glVertex2f((float)x,(float)(y)); } } gl.glEnd(); gl.glFlush(); ... 1.6.2 – Retas no Opengl O OpenGL dispõe em sua biblioteca interna de um comando que plota uma reta por dois pontos dados P0(x0,y0) e P1(x1,y1): gl.glBegin(GL.GL_LINES); gl.glVertex2f(x0, y0)); gl.glVertex2f(x1, y1); gl.glEnd(); Compare a velocidade com o exercício anterior:: public void display(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glClearColor(1.0f,1.0f,1.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); for (double b = -10; b<= 10;b+=0.01) { gl.glBegin(GL.GL_LINES); gl.glVertex2f(-3.0f,(float)(-6f+b)); gl.glVertex2f( 3.0f,(float)( 6f+b)); gl.glEnd(); } gl.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). import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class funcao { public static void main(String[] args) { 12 Frame frame = new Frame("Funcao"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GLU glu = drawable.getGLU(); glu.gluOrtho2D(-3,3,-3,3); } public void display(GLDrawable drawable) { double y; GL gl = drawable.getGL(); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_POINTS); for (double x = -3; x<= 3;x+=0.01) { y = x*x; // Esta é a funcao gl.glVertex2f((float)x,(float)(y)); } gl.glEnd(); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } } Vamos aprimorar nosso código: 1) Acrescentando os eixos. 2) Criando uma variável pontos que permita selecionar a discretização. 3) Criar uma classe funcao que trate da definição da função e das tarefas específicas de plotar o gráfico da função. main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static funcao f; 13 public static void main(String[] args) { Frame frame = new Frame("Funcao"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { f = new funcao(400,-3.0f,-3.0f,3.0f,3.0f); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(f.get_xmin(),f.get_xmax(),f.get_ymin(),f.get_ymax()); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); f.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } } /* * * * * * * * * * * * * * * */ /* Modulo: funcao.java */ /* * * * * * * * * * * * * * * */ import net.java.games.jogl.*; public class funcao { int pontos; float xmin,xmax,ymin,ymax; funcao() pontos xmin = xmax = } { = 300; ymin = -1; ymax = 1; funcao(int p) { pontos = p; 14 xmin = ymin = -1; xmax = ymax = 1; } funcao(int p,float xm,float ym,float xM,float yM) { pontos = p; xmin = xm; ymin = ym; xmax = xM; ymax = yM; } public public public public float float float float get_xmin() get_ymin() get_xmax() get_ymax() { { { { return return return return xmin; ymin; xmax; ymax; } } } } public float f(float x) { return (float) Math.sin((double)x); } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); } gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex2f (xmin,0); gl.glVertex2f (xmax,0); gl.glVertex2f (0,ymin); gl.glVertex2f (0,ymax); gl.glEnd(); public void plota_funcao(GLDrawable drawable) { GL gl = drawable.getGL(); int i; float dx; float x, y; dx = (xmax - xmin)/pontos; gl.glColor3f (1.0f, 0.0f, 0.0f); } x = xmin; for (i = 0; i < pontos; i++) { y = f(x); gl.glBegin (GL.GL_POINTS); gl.glVertex2f (x,y); gl.glEnd(); x = x + dx; } } Nossa próxima etapa é permitir que o usuário possa alterar o domínio de visualização da função interativamente. Na próxima sessão apresentamos algumas das principais interrupções usando o mouse que nos permitirão executar esta tarefa. Exercício: Entre com o domínio através do teclado. 15 main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static funcao f; public static void main(String[] args) { Frame frame = new Frame("Funcao"); GLCanvas canvas GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); = frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GLU glu = drawable.getGLU(); GL gl = drawable.getGL(); f = new funcao(400); f.dominio(); gl.glLoadIdentity(); double a,b,c,d; a = (double)(f.get_xmin()); b = (double)(f.get_xmax()); c = (double)(f.get_ymin()); d = (double)(f.get_ymax()); glu.gluOrtho2D(a,b,c,d); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.LoadIdentity(); glu.gluOrtho2D(f.get_xmin(),f.get_xmax(),f.get_ymin(),f.get_ymax()); f.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable modeChanged, boolean deviceChanged) {} drawable, boolean public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } 16 } funcao.java import net.java.games.jogl.*; public class funcao { int pontos; float xmin,xmax,ymin,ymax; funcao() { pontos = 300; xmin = ymin = -1; xmax = ymax = 1; } funcao(int pontos xmin = xmax = } p) { = p; ymin = -1; ymax = 1; funcao(int pontos xmin = ymin = xmax = ymax = } p,float xm,float ym,float xM,float yM) { = p; xm; ym; xM; yM; public public public public // float float float float get_xmin() get_ymin() get_xmax() get_ymax() { { { { return return return return xmin; ymin; xmax; ymax; } } } } public float f(float x) { return x*x; return (float) Math.sin((double)x); } public void dominio() { System.out.print("xmin = "); xmin = TextIO.getFloat(); System.out.print("ymin = "); ymin = TextIO.getFloat(); System.out.print("xmax = "); xmax = TextIO.getFloat(); System.out.print("ymax = "); ymax = TextIO.getFloat(); } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex2f (xmin,0); gl.glVertex2f (xmax,0); gl.glVertex2f (0,ymin); gl.glVertex2f (0,ymax); gl.glEnd(); } public void plota_funcao(GLDrawable drawable) { GL gl = drawable.getGL(); int i; float dx; float x, y; 17 dx = (xmax - xmin)/pontos; gl.glColor3f (1.0f, 0.0f, 0.0f); x = xmin; for (i = 0; i < pontos; i++) { y = f(x); gl.glBegin (GL.GL_POINTS); gl.glVertex2f (x,y); gl.glEnd(); x = x + dx; } } } 18 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 Jogl 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 Jogl dispõe da função: canvas.addKeyListener ( new JoglKey() ); Esta função determina que quando uma tecla for pressionada, o controle do programa deve passar a classe JoglKey que reimplementa três métodos: public void keyPressed (KeyEvent e) public void keyReleased(KeyEvent e) public void keyTyped (KeyEvent e) O exemplo abaixo exemplifica uma aplicação para o programa funções. 2.3 – 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 na janela de concole do Eclipse as novas informações sobre o domínio da função. A unica alteração ocorre no main. import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { public static void main(String[] args) { Frame frame = new Frame("Funcao"); GLCanvas canvas GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); canvas.addKeyListener ( new JoglKey() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); = frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static funcao f; static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { f = new funcao(400); f.dominio(); } 19 public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glLoadIdentity(); glu.gluOrtho2D(f.get_xmin(),f.get_xmax(),f.get_ymin(),f.get_ymax()); f.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } static class JoglKey implements KeyListener { public void keyPressed (KeyEvent e) { if (e.getKeyChar() == 'd' || e.getKeyChar() == 'D') f.dominio(); } public void keyReleased(KeyEvent e) {} public void keyTyped (KeyEvent e) { } } } 20 2.4 – Mouse O Jogl é 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.4.1- Interrupções a partir do mouse a) MouseListener Este evento contém cinco métodos básicos de controle do mouse: void mouseClicked(MouseEvent e) Registra quando um botào for pressionado e solto. void mouseEntered(MouseEvent e) Registra quando o mouse entra no componente. void mouseExited(MouseEvent e) Registra quando o mouse sai do componente. void mousePressed(MouseEvent e) Registra quando um botào do mouse é pressionado. void mouseReleased(MouseEvent e) Registra quando o botào do mouse é solto sobre o componente. Para testar qual botão foi pressionado: Primeiro botão: e.getButton() == 1 Segundo botão: e.getButton() == 2 Terceiro botão: e.getButton() == 3 Como exemplo, vamos alterar o programa função anterior, e acrescentar 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. Para implementar esta alteração só precisamos mudar o programa main.java. Seu novo código é apresentado a seguir: main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static funcao f; public static void main(String[] args) { Frame frame = new Frame("Funcao"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); canvas.addKeyListener ( new JoglKey() ); canvas.addMouseListener ( new JoglMouse() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); 21 frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { f = new funcao(400,-1,-1,1,1); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(f.get_xmin(),f.get_xmax(), f.get_ymin(),f.get_ymax()); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); f.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } static class JoglKey implements KeyListener { public void keyPressed (KeyEvent e) { if (e.getKeyChar() == 'd' || e.getKeyChar() == 'D') f.dominio(); System.out.println("Pressed"); } public void keyReleased(KeyEvent e) { System.out.println("Released"); } public void keyTyped (KeyEvent e) { System.out.println("Typed"); } } static class JoglMouse implements MouseListener { 22 public void mouseEntered(MouseEvent e) { System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==3) { f.dominio(); } } public void mouseReleased(MouseEvent e) { if (e.getButton()==1) { System.out.print("x = "); System.out.print(e.getX()); System.out.print(" y = "); System.out.println(e.getY()); } } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } b) MouseMotionListener Este evento detecta o movimento do mouse em dois casos: void mouseDragged(MouseEvent e) Quando o botão do mouse está pressionado e em movimento sobre a componente. void mouseMoved(MouseEvent e) Quando o mouse é movimentado sobre a componente. c) MouseWheelListener void mouseWheelMoved(MouseWheelEvent e) main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static funcao f; /** Main Class **/ 23 public static void main(String[] args) { Frame frame = new Frame("Funcao"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); canvas.addGLEventListener( new JoglRender() ); canvas.addKeyListener ( new JoglKey() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addMouseWheelListener( new JoglMouseWheel() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } /** OpenGL Eventos **/ static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { f = new funcao(400,-1,-1,1,1); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(f.get_xmin(),f.get_xmax(),f.get_ymin(),f.get_ymax()); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); f.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } /** Teclado Eventos static class JoglKey implements **/ KeyListener { public void keyPressed (KeyEvent e) { if (e.getKeyChar() == 'd' || e.getKeyChar() == 'D') f.dominio(); 24 System.out.println("Pressed"); } public void keyReleased(KeyEvent e) { System.out.println("Released"); } public void keyTyped (KeyEvent e) { System.out.println("Typed"); } } /** Mouse Eventos **/ static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==2) { f.dominio(); } } public void mouseReleased(MouseEvent e) { if (e.getButton()==3) { System.out.print("x = "); System.out.print(e.getX()); System.out.print(" y = "); System.out.println(e.getY()); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } /** Movimento do Mouse Eventos static class JoglMouseMotion implements **/ MouseMotionListener { public void mouseDragged(MouseEvent e) { System.out.println("Dragged: " + e.getX() + "," + e.getY()); } public void mouseMoved(MouseEvent e) { System.out.println("Moved: " + e.getX() + "," + e.getY()); } } /** Mouse Eventos **/ 25 static class JoglMouseWheel implements MouseWheelListener { public void mouseWheelMoved(MouseWheelEvent e) { System.out.println("Wheel Moved: " + e.getX() + "," + e.getY()); } } } 2.4.2- Aplicações: Realizando o “zoom” do gráfico Versão Inicial 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 pelo eventos do mouse precisam ser convertidas para o sistema de coordendas indicado nos parâmetros do gluOrtho2D. Para isso, basta considerarmos a transformação inversa a aplicada na seção 1.5: e segue que e identicamente para a coordenada y. main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static funcao f; static int mov = 0; /* Detecta movimento do mouse */ static int xv1, yv1, xv2, yv2; /* Domínio da nova janela */ static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Funcao"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } 26 }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { f = new funcao(400,-1,-1,1,1); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(f.get_xmin(),f.get_xmax(),f.get_ymin(),f.get_ymax()); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); if (mov == 1) { System.out.println("mov = 1"); f.plota_retangulo (drawable, xv1,yv1,xv2,yv2); } f.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==3) { System.out.println("Entra"); xv1 = e.getX(); yv1 = e.getY(); mov = 1; } } public void mouseReleased(MouseEvent e) { if (e.getButton()==3) { System.out.println("Sai"); xv2 = e.getX(); yv2 = e.getY(); mov = 0; f.recalcula_dominio (xv1,yv1,xv2,yv2); canvas.display(); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); 27 } } static class JoglMouseMotion implements MouseMotionListener { public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { xv2 = e.getX(); yv2 = e.getY(); System.out.println("Dragged: " + e.getX() + "," + e.getY()); canvas.display(); } } public void mouseMoved(MouseEvent e) { System.out.println("Moved: " + e.getX() + "," + e.getY()); } // } } funcao.java import net.java.games.jogl.*; public class funcao { int pontos; float xmin,xmax,ymin,ymax; funcao() { pontos = 300; xmin = ymin = -1; xmax = ymax = 1; } funcao(int pontos xmin = xmax = } p) { = p; ymin = -1; ymax = 1; funcao(int pontos xmin = ymin = xmax = ymax = } p,float xm,float ym,float xM,float yM) { = p; xm; ym; xM; yM; public public public public // float float float float get_xmin() get_ymin() get_xmax() get_ymax() { { { { return return return return xmin; ymin; xmax; ymax; } } } } public float f(float x) { return x*x; return (float) Math.sin((double)x); } public void dominio() { System.out.print("xmin = "); 28 xmin = TextIO.getFloat(); System.out.print("ymin = "); ymin = TextIO.getFloat(); System.out.print("xmax = "); xmax = TextIO.getFloat(); System.out.print("ymax = "); ymax = TextIO.getFloat(); } public float converte(float p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); } public xv_2,float yv_2) { void recalcula_dominio (float xv_1,float yv_1,float float xmin1,xmax1; float ymin1,ymax1; xmin1 = converte(xv_1,xmin,xmax,600); xmax1 = converte(xv_2,xmin,xmax,600); xmin = xmin1; xmax = xmax1; ymin1 = converte(yv_2,ymax,ymin,600); ymax1 = converte(yv_1,ymax,ymin,600); ymin = ymin1; ymax = ymax1; } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex2f (xmin,0); gl.glVertex2f (xmax,0); gl.glVertex2f (0,ymin); gl.glVertex2f (0,ymax); gl.glEnd(); } public void plota_funcao(GLDrawable drawable) { GL gl = drawable.getGL(); int i; float dx; float x, y; dx = (xmax - xmin)/pontos; System.out.print(xmax + " " + xmin); gl.glColor3f (1.0f, 0.0f, 0.0f); x = xmin; for (i = 0; i < pontos; i++) { y = f(x); gl.glBegin (GL.GL_POINTS); gl.glVertex2f (x,y); gl.glEnd(); x = x + dx; } } public void plota_retangulo (GLDrawable drawable, int x1, int y1, int x2, int y2) { GL gl = drawable.getGL(); 29 float retxmin,retxmax,retymin,retymax; retxmin retxmax retymin retymax = = = = converte converte converte converte (x2,xmin,xmax,600); (x1,xmin,xmax,600); (y1,ymax,ymin,600); (y2,ymax,ymin,600); gl.glColor3f(1.0f,1.0f,1.0f); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(retxmin,retymin); gl.glVertex2f(retxmin,retymax); gl.glVertex2f(retxmax,retymax); gl.glVertex2f(retxmax,retymin); gl.glEnd(); } } Versão 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 Java já dispões desta estrutura, porém podemos montar uma versão ilustrativa da Classe Pilha. Também vamos criar uma classe Window que armazena o domínio de visualização da janela. Windows.java public class Window { float xmin; float xmax; float ymin; float ymax; Window(float xm,float ym,float xM,float yM) { xmin = xm; ymin = ym; xmax = xM; ymax = yM; } } float get_xmin() return xmin; } float get_ymin() return ymin; } float get_xmax() return xmax; } float get_ymax() return ymax; } { { { { Pilha.java public class Pilha { private No topo; 30 private static class No { private Window a ; private No prox; } public void push(Window a) { No novo_topo = new No(); novo_topo.a = a; novo_topo.prox = topo; topo = novo_topo; } public Window pop() { if (Vazia()) throw new RuntimeException("Pilha Vazia"); Window a = topo.a; topo = topo.prox; return a; } public boolean Vazia() { if (topo == null) return (true); else return(false); } } Na classe funcao.java precisamos agora armazenar a cada mudança de janela, o novo dominio. Tambem precisamos inserir um novo metodo que retorna o dominio anterior. funcao.java ... public void recalcula_dominio (float xv_1,float yv_1, float xv_2,float yv_2) { float xmin1,xmax1; float ymin1,ymax1; Window W = new Window(xmin,ymin,xmax,ymax); xmin1 = converte(xv_1,xmin,xmax,600); xmax1 = converte(xv_2,xmin,xmax,600); ymin1 = converte(yv_2,ymax,ymin,600); ymax1 = converte(yv_1,ymax,ymin,600); w.push(W); xmin = xmin1; xmax = xmax1; ymin = ymin1; ymax = ymax1; } public void retorna_dominio () { Window W = w.pop(); xmin = W.get_xmin(); xmax = W.get_xmax(); ymin = W.get_ymin(); ymax = W.get_ymax(); } ... main.java 31 public void mouseReleased(MouseEvent e) { if (e.getButton()==3) { System.out.println("Sai"); xv2 = e.getX(); yv2 = e.getY(); mov = 0; f.recalcula_dominio (xv1,yv1,xv2,yv2); canvas.display(); } } if (e.getButton()==1) { System.out.println("Volta Zoom"); f.retorna_dominio(); canvas.display(); } 3 – CURVAS PARAMÉTRICAS 3.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) 3.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. 3.2.1 – Módulo main.java Este módulo é idêntico ao módulo main.java. A única diferença é que as chamadas são feitas para as novas funções de desenho das curvas. import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static curva c; 32 static int mov = 0; /* Detecta movimento do static int xv1, yv1, xv2, yv2; /* Domínio da nova janela mouse */ */ static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Funcao"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { c = new curva(400,-3.0f,3.0f,3.0f,3.0f,0.0f,(float)(2*Math.PI)); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(c.get_xmin(),c.get_xmax(),c.get_ymin(),c.get_ymax()) ; gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); if (mov == 1) { System.out.println("mov = 1"); c.plota_retangulo (drawable, xv1,yv1,xv2,yv2); } c.plota_eixo(drawable); c.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } 33 public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==3) { System.out.println("Entra"); xv1 = e.getX(); yv1 = e.getY(); mov = 1; } } public void mouseReleased(MouseEvent e) { if (e.getButton()==3) { System.out.println("Sai"); xv2 = e.getX(); yv2 = e.getY(); mov = 0; c.recalcula_dominio (xv1,yv1,xv2,yv2); canvas.display(); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } static class JoglMouseMotion implements MouseMotionListener { public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { xv2 = e.getX(); yv2 = e.getY(); System.out.println("Dragged: " + e.getX() + "," + e.getY()); canvas.display(); } } 34 public void mouseMoved(MouseEvent e) { System.out.println("Moved: " + e.getX() + "," + // e.getY()); } } } 3.2.2 – Módulo curva Neste módulo implementamos a classe curva. import net.java.games.jogl.*; public class curva { int pontos; float xmin,xmax,ymin,ymax; float tmax,tmin; curva() { pontos xmin = xmax = tmin = tmax = } = 300; ymin = -1; ymax = 1; 0.0f; 1.0f; curva(int pontos xmin = xmax = tmin = tmax = } p) { = p; ymin = -1; ymax = 1; 0.0f; 1.0f; curva(int pontos xmin = ymin = xmax = ymax = tmin = tmax = } p,float xm,float ym,float xM,float yM) { = p; xm; ym; xM; yM; 0.0f; 1.0f; curva(int p,float xm,float ym,float xM,float yM,float tm,float tM) { pontos = p; xmin = xm; ymin = ym; xmax = xM; ymax = yM; tmin = tm; tmax = tM; } public float get_xmin() { return xmin; } public float get_ymin() { return ymin; } public float get_xmax() { return xmax; } public float get_ymax() { return ymax; } 35 public float[] c(float t) { float [] v = new float[2]; v[0] = (float)Math.sin(t); v[1] = (float)Math.cos(t); return v; } public void dominio() { System.out.print("xmin = "); xmin = TextIO.getFloat(); System.out.print("ymin = "); ymin = TextIO.getFloat(); System.out.print("xmax = "); xmax = TextIO.getFloat(); System.out.print("ymax = "); ymax = TextIO.getFloat(); } public float converte(float p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); } public void recalcula_dominio (float xv_1,float yv_1,float xv_2,float yv_2) { float xmin1,xmax1; float ymin1,ymax1; xmin1 = converte(xv_1,xmin,xmax,600); xmax1 = converte(xv_2,xmin,xmax,600); xmin = xmin1; xmax = xmax1; ymin1 = converte(yv_2,ymax,ymin,600); ymax1 = converte(yv_1,ymax,ymin,600); ymin = ymin1; ymax = ymax1; } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex2f (xmin,0); gl.glVertex2f (xmax,0); gl.glVertex2f (0,ymin); gl.glVertex2f (0,ymax); gl.glEnd(); } public void plota_funcao(GLDrawable drawable) { GL gl = drawable.getGL(); int i; float t,dt; float[] v; 36 dt = (tmax - tmin)/pontos; gl.glColor3f (1.0f, 0.0f, 0.0f); t = tmin; for (i = 0; i < pontos; i++) { v = c(t); gl.glBegin (GL.GL_POINTS); gl.glVertex2f (v[0],v[1]); gl.glEnd(); t = t + dt; } } public void plota_retangulo (GLDrawable drawable, int x1, int y1, int x2, int y2) { GL gl = drawable.getGL(); float retxmin,retxmax,retymin,retymax; retxmin retxmax retymin retymax = = = = converte converte converte converte (x2,xmin,xmax,600); (x1,xmin,xmax,600); (y1,ymax,ymin,600); (y2,ymax,ymin,600); gl.glColor3f(1.0f,1.0f,1.0f); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(retxmin,retymin); gl.glVertex2f(retxmin,retymax); gl.glVertex2f(retxmax,retymax); gl.glVertex2f(retxmax,retymin); gl.glEnd(); } } 3.2.4 –Exercício Como exercício implemente: 1) Curva ciclóide (t assume qualquer valor real). 2) x(t) = 3*t*t, y(t)=4*t*t*t (t assume qualquer valor real). 3) x(t) = cos(2*t), y(t)= sin(2*t) (0 <= t <= 2*PI) (Qual a diferença para a curva do programa ?) 4) x(t) = cos(t), y(t)= sin(2*t) 5) x(t) = 2 * cos(t), y(t)= 3 * sin(t) (0 <= t <= 2*PI) . 6) 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). 3.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: theta: distância orientada da origem ao ponto P. ângulo entre o eixo polar e o segmento OP. . 37 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 3.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 rotina curva do programa anterior: 38 public float[] c(float t) { float [] v = new float[2]; v[0] = (float) ((1 + Math.cos(t)) * Math.cos(t) ); v[1] = (float) ((1 + Math.cos(t)) * Math.sin(t) ); return v; } 3.5 – 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). 39 4 – CURVAS IMPLÍCITAS 4.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. 4.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 existem ou não pontos da curva nesse domínio). - . no plano como partida (a priori não sabemos se 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 - Para cada triângulo, observamos os sinais calculamos . = 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. 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. 4.3 – Programa Curva Implícita O programa mantém a mesma estrutura do programa curva paramétrica, alterando a classe curva, conforme abaixo. implicito.java import net.java.games.jogl.*; public class Curva { public float f(float x,float y) { return x*x-y*y-1; // return x*x+y*y-1; } public void curva_implicita(GLDrawable drawable, float[] xf,float[] yf) { GL gl = drawable.getGL(); int j; int i = 0; float t; float[] x = new float[3]; float[] y = new float[3]; float[] s = new float[3]; gl.glColor3f(0,0,1); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(xf[0],yf[0]); gl.glVertex2f(xf[1],yf[1]); gl.glVertex2f(xf[2],yf[2]); gl.glEnd(); for(j=0;j<3;j++) s[j] = f(xf[j],yf[j]); if } 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++; ((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++; 41 } 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++; } } if (i == 2) { gl.glLineWidth(2.0f); gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_LINES); gl.glVertex2f(x[0],y[0]); gl.glVertex2f(x[1],y[1]); gl.glEnd(); gl.glLineWidth(1.0f); } } public void plota_curva(GLDrawable drawable) { GL gl = drawable.getGL(); int i,j; float[] tx float[] ty float x,y; float dx = float dy = = new float[3]; = new float[3]; (xmax - xmin)/pontos; (ymax - ymin)/pontos; gl.glColor3f(1.0f,0.0f,0.0f); x = xmin; for(i=0;i<pontos;i++) { y = ymin; for(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; curva_implicita(drawable,tx,ty); tx[0] = x + dx; tx[1] = x; tx[2] = x + dx; ty[0] = y + dy; ty[1] = y + dy; ty[2] = y; curva_implicita(drawable,tx,ty); y += dy; } x += dx; } } } 4.4 –Exercício 1) Como exercício implemente as seguintes curvas implícitas: 42 a) b) . c) . . d) 2) Implemente no programa uma rotina que imprima simultaneamente varias curvas de nivel de uma mesma função , ou seja . Por exemplo, . 5 – RETAS E POLÍGONOS NO OPENGL 5.1 – Retas e Polígonos 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 .gl.glBegin(...) e finalizando com gl.glEnd(...), por exemplo para o GL_LINES temos: gl.glBegin(GL_LINES); gl.glVertex2f(1.0,1.0); gl.glVertex2f(1.0,2.0); gl.glVertex2f(2.0,-2.0); ... gl.glEnd(); GL.GL_POINTS GL.GL_LINES GL.GL_POLYGON GL.GL_TRIANGLES GL.GL_QUADS GL.GL_LINE_STRIP GL.GL_LINE_LOOP GL.GL_TRIANGLE_STRIP GL.GL_TRIANGLE_FAN GL.GL_QUAD_STRIP Pontos individuais. Reta entre dois pontos. Polígono convexo . Tripla de vértices é interpretado como um triângulo. Conjunto de quatro vértices interpretado como quadrilátero. Sequência de retas. Idêntico ao anterior, porém com uma reta unindo o primeiro e último vértice. Lista de triângulos. Lista de triângulos com o primeiro vértice em comum. Lista de quadriláteros. 43 5.2 – Exemplo: Visualização dos Métodos Numéricos de Integração Como exemplo de aplicação dos novos objetos vamos visualizar alguns métodos numéricos de integração apresentados no capitulo 1. Class Integral.java import net.java.games.jogl.GL; import net.java.games.jogl.GLDrawable; public class Integral { float float funcao int int int a; b; f; particao; visual; metodo; // // // // 0 1 2 3 - ponto a esquerda trapezio Simpson Monte Carlo public Integral (float xi,float xf,int part, int met,funcao func) { a = xi; b = xf; particao = part; metodo = met ; f = func; visual = 1; } public void { GL int float float Integral_esquerda(GLDrawable drawable) gl = drawable.getGL(); i ; x,y; dx; dx = (b-a)/particao; x = a; for(i=0; i < particao; i++) { y = f.f(x); gl.glColor3f(1.0f,1.0f,0.0f); if (visual == 0) gl.glBegin(GL.GL_LINE_LOOP); 44 else gl.glBegin(GL.GL_POLYGON); gl.glVertex2f(x,y); gl.glVertex2f(x+dx,y); gl.glVertex2f(x+dx,0); gl.glVertex2f(x,0); gl.glEnd(); x = x+dx; } } } 45 6 – PROCESSAMENTO DE IMAGEM 6.1 – Introdução Filtro da media e Gradiente Imagem.java import net.java.games.jogl.*; import java.io.*; public class Imagem { float xmin,xmax,ymin,ymax; Pilha w; int dimx,dimy,range; int[][] image; String file; Imagem() { xmin = ymin = 0; xmax = ymax = 512; w = new Pilha(); } Imagem(float xm,float ym,float xM,float yM,String file_name) { xmin = xm; ymin = ym; xmax = xM; ymax = yM; w = new Pilha(); file = file_name; } Imagem(String s) { xmin = 0; ymin = 511; xmax = 511; ymax = 0; w = new Pilha(); file = s; try { Reader q = new FileReader(s); int ch; String p; ch = q.read(); p = String.valueOf((char)ch); while(!Character.isWhitespace((char) ch )) { ch = q.read(); if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); } dimx = Integer.parseInt(p); while(Character.isWhitespace((char) ch)) ch = q.read(); p = String.valueOf((char)ch); while(!Character.isWhitespace((char) ch)) { ch = q.read(); 46 if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); } dimy = Integer.parseInt(p); while(Character.isWhitespace((char) ch)) ch = q.read(); p = String.valueOf((char)ch); while(!Character.isWhitespace((char) ch)) { ch = q.read(); if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); } range = Integer.parseInt(p); image = new int[dimx][dimy]; System.out.println(" " + dimx + " " + dimy + " " + range); for (int i = 0; i<dimx; i++) { for(int j = 0; j<dimy; j++) { while(Character.isWhitespace((char) ch)) ch = q.read(); p = String.valueOf((char)ch); while (!Character.isWhitespace((char) ch)) { if ch = q.read(); (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); // } image[i][j] = Integer.parseInt(p); System.out.print(" " + p); } } } catch (Exception e) { e.printStackTrace(); } } public void media() { int i,j; int[][] B = new int[dimx][dimy]; for(i=0;i<dimx;i++) for(j=0;j<dimy;j++) B[i][j] = image[i][j]; for(i=1;i<dimx-1;i++) for(j=1;j<dimy-1;j++) { image[i][j] = (B[i-1][j-1]+B[i-1][j]+B[i1][j+1]+B[i][j-1]+B[i][j]+B[i][j+1]+B[i+1][j1]+B[i+1][j]+B[i+1][j+1])/9; } } public void filtro_gradiente() 47 { int i,j; int[][] B = new int[dimx][dimy]; int[][] C = new int[dimx][dimy]; int[][] D = new int[dimx][dimy]; for(i=0;i<dimx;i++) for(j=0;j<dimy;j++) B[i][j] = image[i][j]; for(i=1;i<dimx-1;i++) for(j=1;j<dimy-1;j++) { C[i][j] = (B[i-1][j-1] -B[i-1][j+1] +2*B[i][j-1] -2*B[i][j+1] +B[i+1][j-1] B[i+1][j+1])/4; D[i][j] = (B[i-1][j-1]+2*B[i-1][j]+B[i-1][j+1] -B[i+1][j-1]-2*B[i+1][j] -B[i+1][j+1])/4; image[i][j] = (int)Math.sqrt(D[i][j] * D[i][j] + C[i][j]*C[i][j]); } } public void { int i,j; int[][] B int[][] C int[][] D filtro_mediana() = new int[dimx][dimy]; = new int[dimx][dimy]; = new int[dimx][dimy]; for(i=0;i<dimx;i++) for(j=0;j<dimy;j++) B[i][j] = image[i][j]; for(i=1;i<dimx-1;i++) for(j=1;j<dimy-1;j++) { C[i][j] = (B[i-1][j-1] -B[i-1][j+1] +2*B[i][j-1] -2*B[i][j+1] +B[i+1][j-1] B[i+1][j+1])/4; D[i][j] = (B[i-1][j-1]+2*B[i-1][j]+B[i-1][j+1] -B[i+1][j-1]-2*B[i+1][j] -B[i+1][j+1])/4; image[i][j] = (int)Math.sqrt(D[i][j] * D[i][j] + C[i][j]*C[i][j]); } } public public public public float float float float get_xmin() get_ymin() get_xmax() get_ymax() { { { { return return return return xmin; ymin; xmax; ymax; } } } } public float converte(float p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); 48 } public void recalcula_dominio (float xv_1,float yv_1,float xv_2,float yv_2) { float xmin1,xmax1; float ymin1,ymax1; Window W = new Window(xmin,ymin,xmax,ymax); xmin1 xmax1 ymin1 ymax1 = = = = converte(xv_1,xmin,xmax,600); converte(xv_2,xmin,xmax,600); converte(yv_2,ymax,ymin,600); converte(yv_1,ymax,ymin,600); w.push(W); xmin xmax ymin ymax = = = = xmin1; xmax1; ymin1; ymax1; } public void retorna_dominio () { Window W = w.pop(); xmin xmax ymin ymax = = = = W.get_xmin(); W.get_xmax(); W.get_ymin(); W.get_ymax(); } public void draw_image(GLDrawable draw) { GL gl = draw.getGL(); for (int i=0;i<dimx;i++) for (int j=0;j<dimy;j++) { gl.glColor3f(image[i][j]/(float)range,image[i][j]/(float)range,i mage[i][j]/(float)range); gl.glBegin(GL.GL_POINTS); gl.glVertex2d(j,i); gl.glEnd(); } } public void plota_retangulo (GLDrawable drawable, int x1, int y1, int x2, int y2) { GL gl = drawable.getGL(); float retxmin,retxmax,retymin,retymax; retxmin retxmax retymin retymax = = = = converte converte converte converte (x2,xmin,xmax,600); (x1,xmin,xmax,600); (y1,ymax,ymin,600); (y2,ymax,ymin,600); gl.glColor3f(1.0f,1.0f,1.0f); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(retxmin,retymin); gl.glVertex2f(retxmin,retymax); gl.glVertex2f(retxmax,retymax); gl.glVertex2f(retxmax,retymin); gl.glEnd(); } } 49 main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; import java.util.*; import java.io.*; public class main { static Imagem g; static int mov = 0; /* Detecta movimento static int xv1, yv1, xv2, yv2; /* Domínio da do mouse */ nova janela */ static GLCanvas canvas GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); = public static void main(String[] args) throws IOException { Frame frame = new Frame("Funcao"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addKeyListener ( new JoglKey() ); frame.add(canvas); frame.setSize(512, 512); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { g = new Imagem("gauss.pgm"); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(g.get_xmin(),g.get_xmax(),g.get_ymin(),g.get_ymax ()); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); g.draw_image(drawable); 50 if (mov == 1) { System.out.println("mov = 1"); g.plota_retangulo (drawable, xv1,yv1,xv2,yv2); } gl.glFlush(); } public void displayChanged(GLDrawable boolean modeChanged, boolean deviceChanged) { } drawable, public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==3) { System.out.println("Entra"); xv1 = e.getX(); yv1 = e.getY(); mov = 1; } } public void mouseReleased(MouseEvent e) { if (e.getButton()==3) { System.out.println("Sai"); xv2 = e.getX(); yv2 = e.getY(); mov = 0; g.recalcula_dominio (xv1,yv1,xv2,yv2); canvas.display(); } if (e.getButton()==1) { System.out.println("Volta Zoom"); g.retorna_dominio(); canvas.display(); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } 51 static MouseMotionListener { class JoglMouseMotion implements public void mouseDragged(MouseEvent e) { if ((e.getModifiers() InputEvent.BUTTON3_MASK) != 0) { xv2 = e.getX(); yv2 = e.getY(); System.out.println("Dragged: e.getX() + "," + e.getY()); canvas.display(); } & " + } public void mouseMoved(MouseEvent e) { System.out.println("Moved: " + e.getX() + "," // + e.getY()); } } static class JoglKey implements KeyListener { public void keyPressed (KeyEvent e) { if (e.getKeyChar() == 'g' || e.getKeyChar() == 'G') { g.filtro_gradiente(); canvas.display(); System.out.println("Gradiente"); } if (e.getKeyChar() == 'm' || e.getKeyChar() == 'M') { System.out.println("Media"); g.media(); canvas.display(); } } public void keyReleased(KeyEvent e) { // System.out.println("Released"); } public void keyTyped (KeyEvent e) { // System.out.println("Typed"); } } } 52 7 – FRACTAIS 7.1 – Conjuntos auto-semelhantes Definição: Um subconjunto fechado e limitado expresso na forma: onde fator de escala , é dito ser auto-semelhante se pode ser são conjuntos não sobrepostos e cada um deles é congruente a ( por mesmo ). Exemplo 1: Um triângulo pode ser expresso como a união de quatro triângulos congruentes e não sobrepostos. Cada um dos triângulos é congruente ao original por um fator e o triângulo é um conjunto auto-semelhante com k = 4. Exemplo 2 (Triângulo de Sierpinski): Este exemplo foi apresentado pelo matemático Waclaw Sierpinski (1882-1969). Neste exemplo, partindo de um triângulo, temos a união de três triângulos não sobrepostos 53 (portanto ), cada um dos quais é congruente ao original com um fator de escala . Em seguida, o processo se repete para cada um dos três triângulos, e assim sucessivamente. 7.2 – Dimensão Hausdorff e o conceito de fractal Definição: A dimensão Hausdorff de um conjunto auto-semelhante é definida por: onde denota a dimensão Hausdorff. Assim, considerando os exemplos anteriores teremos: Exemplo 1: Exemplo 2: Observe que no exemplo 1, a dimensão Hausdorff, coincide com a dimensão topológica usual, uma vez que uma região em tem dimensão 2. Porém no exemplo 2, obtemos uma dimensão não inteira para o triângulo de Sierpinski. Partindo desta observação, Mandelbrot sugeriu em 1977 a seguinte definição: Definição: Um fractal é um subconjunto do espaço euclidiano cuja dimensão Hausdorff é diferente da dimensão topológica. 7.3 – Exemplos de fractais Alguns dos principais exemplos que apresentaremos nesta seção foram gerados utilizando composição de transformações de rotação e escala seguido de uma possível translação. O formato geral da função é dado por: 54 onde 7.3.1- Triângulo de Sierpinski Para obter o triângulo de Sierpinski, utilizaremos uma aplicação que a partir de um triângulo, obtém três novos triângulos conforme a figura abaixo: Assim temos três funções, uma associada a cada triângulo: main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; import java.util.*; import java.io.*; public class main { static Fractal g; static int mov = 0; /* Detecta movimento do mouse */ static int xv1, yv1, xv2, yv2; /* Domínio da nova janela */ static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); 55 public static void main(String[] args) throws IOException { Frame frame = new Frame("Funcao"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addKeyListener ( new JoglKey() ); frame.add(canvas); frame.setSize(600,600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { g = new Fractal(); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(g.get_xmin(),g.get_xmax(),g.get_ymin(),g.get_ymax()) ; gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); g.plota_fractal(drawable); if (mov == 1) { System.out.println("mov = 1"); g.plota_retangulo (drawable, xv1,yv1,xv2,yv2); } gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } 56 public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==3) { System.out.println("Entra"); xv1 = e.getX(); yv1 = e.getY(); mov = 1; } } public void mouseReleased(MouseEvent e) { if (e.getButton()==3) { System.out.println("Sai"); xv2 = e.getX(); yv2 = e.getY(); mov = 0; g.recalcula_dominio (xv1,yv1,xv2,yv2); canvas.display(); } if (e.getButton()==1) { System.out.println("Volta Zoom"); g.retorna_dominio(); canvas.display(); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } static class JoglMouseMotion implements { MouseMotionListener public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { xv2 = e.getX(); yv2 = e.getY(); System.out.println("Dragged: " + e.getX() + "," + e.getY()); canvas.display(); } } public void mouseMoved(MouseEvent e) { } } static class JoglKey implements KeyListener { public void keyPressed (KeyEvent e) { 57 } public void keyReleased(KeyEvent e) { } public void keyTyped (KeyEvent e) { } } } Fractal.java import net.java.games.jogl.*; import java.io.*; public class Fractal { float Pilha int float xmin,xmax,ymin,ymax; w; n; x1,y1,x2,y2,x3,y3; Fractal() { xmin = ymin = 0; xmax = ymax = 1; w = new Pilha(); x1 = 0.0f; y1 = 0.0f; x2 = 0.0f; y2 = 1.0f; x3 = 1.0f; y3 = 0.0f; n = 7; } Fractal(float xm,float ym,float xM,float yM, float _x1, float _y1, float _x2, float _y2, float _x3, float _y3, int iter) { xmin = xm; ymin = ym; xmax = xM; ymax = yM; n = iter; x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2; x3 = _x3; y3 = _y3; } public public public public float float float float get_xmin() get_ymin() get_xmax() get_ymax() { { { { return return return return xmin; ymin; xmax; ymax; } } } } 58 public float converte(float p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); } public void recalcula_dominio (float xv_1,float xv_2,float yv_2) { float xmin1,xmax1; float ymin1,ymax1; Window W = new Window(xmin,ymin,xmax,ymax); xmin1 xmax1 ymin1 ymax1 = = = = yv_1,float converte(xv_1,xmin,xmax,600); converte(xv_2,xmin,xmax,600); converte(yv_2,ymax,ymin,600); converte(yv_1,ymax,ymin,600); w.push(W); xmin xmax ymin ymax = = = = xmin1; xmax1; ymin1; ymax1; } public void retorna_dominio () { Window W = w.pop(); xmin xmax ymin ymax = = = = W.get_xmin(); W.get_xmax(); W.get_ymin(); W.get_ymax(); } public float[] transform(float x,float y,float e,float f) { float[] v = new float[2]; v[0] = x/2 + e; v[1] = y/2 + f; return v; } public void plota_fractal(GLDrawable draw) { plota_auto_semelhante(draw,x1,y1,x2,y2,x3,y3,n); } public void plota_auto_semelhante(GLDrawable draw, float x0,float y0, float x1,float y1, float x2,float y2, int n) { GL gl = draw.getGL(); int i,j; float[][] x = new float[3][3]; float[][] y = new float[3][3]; float[] e = new float[3]; 59 float[] f = new float[3]; float[] v; e[1] = 0.5f; f[2] = 0.5f; for(i=0;i<3;i++) { x[i][0] = y[i][0] = x[i][1] = y[i][1] = x[i][2] = y[i][2] = x0; y0; x1; y1; x2; y2; } for(i=0;i<3;i++) for (j=0;j<3;j++) { System.out.println("antes // y[j][i]); = " + x[j][i] + " " + v = transform(x[j][i],y[j][i],e[j],f[j]); x[j][i] = v[0]; y[j][i] = v[1]; System.out.println("depois = " + x[j][i] + " " + // y[j][i]); } if (n == 0) { for (i=0;i<3;i++) { gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_TRIANGLES); gl.glVertex2f(x[i][0],y[i][0]); gl.glVertex2f(x[i][1],y[i][1]); gl.glVertex2f(x[i][2],y[i][2]); gl.glEnd(); } return; } else { for(i=0;i<3;i++) plota_auto_semelhante(draw,x[i][0],y[i][0],x[i][1],y[i][1], x[i][2],y[i][2],n-1); } } public void plota_retangulo (GLDrawable drawable, int x1, int y1, int x2, int y2) { GL gl = drawable.getGL(); float retxmin,retxmax,retymin,retymax; retxmin retxmax retymin retymax = = = = converte converte converte converte (x2,xmin,xmax,600); (x1,xmin,xmax,600); (y1,ymax,ymin,600); (y2,ymax,ymin,600); gl.glColor3f(1.0f,1.0f,1.0f); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(retxmin,retymin); gl.glVertex2f(retxmin,retymax); gl.glVertex2f(retxmax,retymax); gl.glVertex2f(retxmax,retymin); gl.glEnd(); 60 } } 7.3.2- Triângulo de Sierpinski utilizando Monte Carlo Este método utiliza iterações randômicas para gerar fractais utilizando o seguinte processo: 1- Defina as k transformações (como descrito na seção 6.3) que descrevem o objeto a ser gerado. 2- Escolha um ponto arbitrário . 3- Escolha arbitrariamente uma das k transformações e aplique no ponto escolhido: 4- Prossiga escolhendo aleatoriamente uma das k transformações e aplique no ultimo ponto obtido: O módulo main.java, necessita apenas das alterações no display e no nome da classe. Fractal.java // Monte Carlo import net.java.games.jogl.*; import java.io.*; import java.util.*; public class Fractal { float Pilha int float float float xmin,xmax,ymin,ymax; w; n; x1,y1,x2,y2,x3,y3; x0; y0; Fractal() { xmin = ymin = 0; xmax = ymax = 1; w = new Pilha(); x1 = 0.0f; y1 = 0.0f; x2 = 0.0f; y2 = 1.0f; x3 = 1.0f; y3 = 0.0f; n = 70000; x0 = 0; y0 = 0; } Fractal(float xm,float ym,float xM,float yM, float _x1, float _y1, float _x2, float _y2, float _x3, float _y3, int iter, float _x0,float _y0) { xmin = xm; ymin = ym; 61 xmax = xM; ymax = yM; n = iter; x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2; x3 = _x3; y3 = _y3; x0 = _x0; y0 = _y0; } public float[] transform(float x,float y,float e,float f) { float[] v = new float[2]; v[0] = x/2 + e; v[1] = y/2 + f; return v; } public void plota_fractal(GLDrawable draw) { GL gl = draw.getGL(); int i,j; float[][] x = new float[3][4]; float[][] y = new float[3][4]; Random rn = new Random(); float[] e = new float[3]; float[] f = new float[3]; float[] v; e[1] = 0.5f; f[2] = 0.5f; for(i=0;i<n;i++) { j = (int) (3.0 * rn.nextDouble()); j = ( j > 2) ? 2 : j; v = transform(x0,y0,e[j],f[j]); x0 = v[0]; y0 = v[1]; gl.glColor3f(1.0f,0.0f,0.0f); gl.glBegin(GL.GL_POINTS); gl.glVertex2f(x0,y0); gl.glEnd(); } } ... } 7.3.3- “Fern” import net.java.games.jogl.*; import java.io.*; import java.util.*; 62 public class Fractal { float xmin,xmax,ymin,ymax; Pilha w; int n; Fractal() { xmin = ymin = 0; xmax = ymax = 1; w = new Pilha(); n = 3; } Fractal(float xm,float ym,float xM,float yM, float _x1, float _y1, float _x2, float _y2, float _x3, float _y3, int iter, float _x0,float _y0) { xmin = xm; ymin = ym; xmax = xM; ymax = yM; n = iter; } public float[] transform(float a11,float a12,float a21,float a22,float e,float f,float x1,float y1) { float[] v = new float[2]; v[0] = a11 * x1 + a12 * y1 + e; v[1] = a21 * x1 + a22 * y1 + f; return v; } public void plota_fractal(GLDrawable draw) { float[] x = new float[4]; float[] y = new float[4]; x[1] = x[2] = 1.0f; y[2] = y[3] = 1.0f; plota_auto_semelhante(draw,x,y,n); } public void plota_auto_semelhante(GLDrawable draw,float[] x,float[] y,int ni) { GL gl = draw.getGL(); int i,j; float[][] xx = new float[4][4]; float[][] yy = new float[4][4]; float[] v; 63 for(i=0;i<4;i++) for(j=0;j<4;j++) { xx[i][j] = x[j]; yy[i][j] = y[j]; } if (ni == 0) { gl.glColor3f(0.0f,1.0f,0.0f); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(x[0],y[0]); gl.glVertex2f(x[1],y[1]); gl.glVertex2f(x[2],y[2]); gl.glVertex2f(x[3],y[3]); gl.glEnd(); return; } else { for(i=0;i<4;i++) { v = transform( 0.20f,-0.26f, 0.23f, 0.22f,0.400f, 0.045f,xx[0][i],yy[0][i]); xx[0][i] = v[0]; yy[0][i] = v[1]; v = transform( 0.85f, 0.04f,-0.04f, 0.85f,0.075f, 0.180f,xx[1][i],yy[1][i]); xx[1][i] = v[0]; yy[1][i] = v[1]; v = transform( 0.00f, 0.00f, 0.00f, 0.16f,0.500f, 0.000f,xx[2][i],yy[2][i]); xx[2][i] = v[0]; yy[2][i] = v[1]; v = transform(-0.15f, 0.28f, 0.26f, 0.24f,0.575f,-0.086f,xx[3][i],yy[3][i]); xx[3][i] = v[0]; yy[3][i] = v[1]; } plota_auto_semelhante(draw,xx[0],yy[0],ni-1); plota_auto_semelhante(draw,xx[1],yy[1],ni-1); plota_auto_semelhante(draw,xx[2],yy[2],ni-1); plota_auto_semelhante(draw,xx[3],yy[3],ni-1); } } ... } 64 7.4 – Conjunto de Julia import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class Julia { int DIM; float dx,dy; float xc,yc,xcl,ycl,xc1,yc1; float xminj,yminj,xmaxj,ymaxj; float xminm,yminm,xmaxm,ymaxm; int n; int m; int lk; Pilha w = new Pilha(); int[][] M ; int[][] o ; Julia() { M = new int[600][600]; o = new int[600][600]; DIM = 600; n = 600; xc1 = 1; yc1 = 1; m = 100; xminm = yminm = xminj = yminj = -2; xmaxm = ymaxm = xmaxj = ymaxj = 2; dx=(xmaxj-xminj)/n; dy=(ymaxj-yminj)/n; } public void constant(float x,float y) { float t2; t2=(float)x/DIM; xc1=xminm+t2*(xmaxm-xminm); t2=(float)y/DIM; yc1=(ymaxm-t2*(ymaxm-yminm)); System.out.println("\n\n----------\nConstante Atual: " + xc1 + “ , “ + yc1); } public public public public float float float float get_xmin() get_ymin() get_xmax() get_ymax() { { { { if if if if (lk (lk (lk (lk == == == == 0) 0) 0) 0) return return return return xminj; yminj; xmaxj; ymaxj; else else else else return return return return xminm;} yminm;} xmaxm;} ymaxm;} public void set_m(int i) { if (i == 0) m += 10; else m -= 10; System.out.println("iter = " + m); } public int getDIM() { return DIM; } public double[] cores (float ca){ double[] result = new double[3]; double s=m/5.0; if( ca <= s) { result[0]=1.0; result[1]=ca/s; result[2]=0.0; } else if( ca<=2*s ) { result[0]=1.0-(ca-s)/s; result[1]=1.0; 65 result[2]=0.0; } else if( ca<=3*s ) { result[0]=0.0; result[1]=1.0; result[2]=(ca-2*s)/s; } else if( ca<=4*s ) { result[0]=0.0; result[1]=1.0-(ca-3*s)/s; result[2]=1.0; } else if( ca> 4*s) { result[0]=(ca-4*s)/s; result[1]=0.0; result[2]=1.0; } return result; } public void plota_indicador_constante(GLDrawable draw) { GL gl = draw.getGL(); gl.glColor3f(1,1,1); gl.glLineWidth(2); gl.glBegin(GL.GL_LINES); gl.glVertex2f(xc1,yc1+((ymaxm-yminm)/20)); gl.glVertex2f(xc1,yc1+((ymaxm-yminm)/40)); gl.glVertex2f(xc1,yc1-((ymaxm-yminm)/40)); gl.glVertex2f(xc1,yc1-((ymaxm-yminm)/20)); gl.glVertex2f(xc1-((xmaxm-xminm)/20),yc1); gl.glVertex2f(xc1-((xmaxm-xminm)/40),yc1); gl.glVertex2f(xc1+((xmaxm-xminm)/40),yc1); gl.glVertex2f(xc1+((xmaxm-xminm)/20),yc1); gl.glEnd(); } public void set_lk() { lk = (lk + 1) %2; System.out.print(lk); } public int get_lk() { return lk; } public void init() { if (lk == 0) { dx=Math.abs(xmaxj-xminj)/n; dy=Math.abs(ymaxj-yminj)/n; } else { dx=Math.abs(xmaxm-xminm)/n; dy=Math.abs(ymaxm-yminm)/n; } xc=xc1; yc=yc1; } public void plota_fractal(GLDrawable draw) { float xmin,ymin,xmax,ymax; GL gl = draw.getGL(); int x,y,k; float R; float i,j,xz,yz,temp; 66 double[] cor; for(x=0;x<n;x++) { for(y=0;y<n;y++) { M[x][y] = 0; o[x][y] =0; } } if (lk == 0) { xmin xmax ymin ymax } else { xmin xmax ymin ymax } = = = = xminj; xmaxj; yminj; ymaxj; = = = = xminm; xmaxm; yminm; ymaxm; i = xmin; for(x=0;x<2*n;x++) { i = i+dx/2; j = ymin; for(y=0;y<2*n;y++) { j = j + dy/2; if(lk==0) { xz=i; yz=j; k=0; } else { xz=0; yz=0; k=0; xc=i; yc=j; } if( ((xc*xc) + (yc*yc))>4) { R=(xc*xc) + (yc*yc); } else{ R=4.0f; } for(k=0;k<m;k++) { if((xz*xz)+(yz*yz)>R)/*Verifica se o ponto escapou e plota na cor de acordo com o nË™mero de iteraà ıes necess·rio*/ { M[x/2][y/2] += k; o[x/2][y/2]++; break; } else { temp=((xz*xz) - (yz*yz) + xc); yz=((2*xz*yz) + yc); xz=temp; } 67 } } } for(x=0;x<600;x++) { for(y=0;y<600;y++) { cor = cores((float)M[x][y]/o[x][y]); gl.glColor3d(cor[0],cor[1],cor[2]); gl.glBegin(GL.GL_POINTS); gl.glVertex2i(x,y); gl.glEnd(); } } } public void recalcula_dominio (float xv_1,float yv_1, float xv_2,float yv_2) { float xmin1,xmax1; float ymin1,ymax1; if (lk == 0) { Window W = new Window(xminj,yminj,xmaxj,ymaxj); xmin1 = converte(xv_1,xminj,xmaxj,DIM); xmax1 = converte(xv_2,xminj,xmaxj,DIM); ymin1 = converte(yv_2,ymaxj,yminj,DIM); ymax1 = converte(yv_1,ymaxj,yminj,DIM); w.push(W); xminj = xmin1; xmaxj = xmax1; yminj = ymin1; ymaxj = ymax1; } else { Window W = new Window(xminm,yminm,xmaxm,ymaxm); xmin1 = converte(xv_1,xminm,xmaxm,DIM); xmax1 = converte(xv_2,xminm,xmaxm,DIM); ymin1 = converte(yv_2,ymaxm,yminm,DIM); ymax1 = converte(yv_1,ymaxm,yminm,DIM); w.push(W); xminm = xmin1; xmaxm = xmax1; yminm = ymin1; ymaxm = ymax1; } } public float converte(float p, float min, float max, int dim) { float x; x = min + ( (p * (max-min))/(dim - 1) ); return (x); } public void retorna_dominio () { Window W = w.pop(); if (lk == 0) { xminj = W.get_xmin(); xmaxj = W.get_xmax(); yminj = W.get_ymin(); ymaxj = W.get_ymax(); } else { xminm = W.get_xmin(); xmaxm = W.get_xmax(); yminm = W.get_ymin(); ymaxm = W.get_ymax(); } } 68 } 69 CAPÍTULO III – VISUALIZAÇÃO E APLICAÇÕES GRÁFICAS 3D ____________ 2 1- TRANSFORMAÇÕES DE VISUALIZAÇÃO ________________________________ 2 1.1 - Introdução ____________________________________________________________ 2 1.2 – Transformações _______________________________________________________ 6 1.3 - Comandos de Auxílio ___________________________________________________ 6 1.4- Exemplo: cubo unitário ____________________________________________________ 7 1.5 - Transformações de Modelagem e Visualização_________________________________ 9 1.5.1- Translação ____________________________________________________________________ 9 1.5.2- Rotação ______________________________________________________________________ 9 1.5.3- Escala _______________________________________________________________________ 9 1.5.4-Exemplo _____________________________________________________________________ 10 1.6- Projeção Ortográfica _____________________________________________________ 12 1.7- Projeção Perspectiva ______________________________________________________ 12 1.8- Ângulos de Euler _________________________________________________________ 13 1.8 - Criando um Ambiente de Visualização 3D ___________________________________ 14 1.8.1- Módulo Básico de Visualização __________________________________________________ 14 1.8.2- Alterando os ângulos de Euler ___________________________________________________ 16 1.9 – Visualização de gráfico de funções _______________________________ 19 2- ILUMINAÇÃO _______________________________________________________ 24 2.1– Criando Fontes de Luz ____________________________________________________ 27 2.1.1– Cor ________________________________________________________________________ 27 2.1.2– Posição _____________________________________________________________________ 28 2.2– Selecionando o Modelo de Iluminação _______________________________________ 28 2.2.1- Luz Ambiente Global __________________________________________________________ 2.2.2 – Posição do observador local ou no infinito _________________________________________ 2.2.3 – Iluminação nos dois lados das faces ______________________________________________ 2.2.4 – Habilitando a iluminação_______________________________________________________ 28 28 28 28 2.3– Selecionando as Propriedades do Material ___________________________________ 29 2.4– Exemplo 1 ______________________________________________________________ 29 2.5– Comando glLookAt ______________________________________________________ 34 2.6 – Visualizando as normais __________________________________________________ 36 3- SUPERFÍCIES PARAMETRIZADAS ____________________________________ 37 3.1– Visualização de superfícies na forma paramétrica _____________________________ 37 3.2– Exercícios_______________________________________________________________ 39 4- SUPERFÍCIES IMPLÍCITAS ___________________________________________ 41 5- TEXTURA ___________________________________________________________ 48 1 CAPÍTULO III – VISUALIZAÇÃO E 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 tridimensional. 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 v1 v2 v3 (0,0,0) (1,0,0) (1,1,0) (0,1,0) v4 v5 v6 v7 (0,0,1) (1,0,1) (1,1,1) (0,1,1) Para visualizar este modelo, uma primeira estratégia seria definir uma projeção de nosso modelo 3D para o bidimensional. /* * * * * * * * * * * * * * * * * */ /* Modulo: main.java */ /* * * * * * * * * * * * * * * * * */ import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static cubo Q; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Cubo"); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { Q = new cubo(); } public void display(GLDrawable drawable) { 2 GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glLoadIdentity(); glu.gluOrtho2D(-2,2,-2,2); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); Q.render_cubo(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} public void reshape(GLDrawable drawable, int x, int y, int width, int height) {} } } /* * * * * * * * * * * * * * * * */ /* Modulo: cubo.java */ /* * * * * * * * * * * * * * * * */ import net.java.games.jogl.*; public class cubo { float[][] P; cubo() { P = new float[8][3]; unitario(); } public void unitario() { P[0][0] = 0; P[0][1] = 0; P[0][2] = 0; P[1][0] = 1; P[1][1] = 0; P[1][2] = 0; P[2][0] = 1; P[2][1] = 1; P[2][2] = 0; P[3][0] = 0; P[3][1] = 1; P[3][2] = 0; } P[4][0] P[4][1] P[4][2] P[5][0] P[5][1] P[5][2] P[6][0] P[6][1] P[6][2] P[7][0] P[7][1] P[7][2] = = = = = = = = = = = = 0; 0; 1; 1; 0; 1; 1; 1; 1; 0; 1; 1; public void render_cubo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(P[0][0],P[0][1]); gl.glVertex2f(P[1][0],P[1][1]); gl.glVertex2f(P[2][0],P[2][1]); 3 gl.glVertex2f(P[3][0],P[3][1]); gl.glEnd(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(P[4][0],P[4][1]); gl.glVertex2f(P[5][0],P[5][1]); gl.glVertex2f(P[6][0],P[6][1]); gl.glVertex2f(P[7][0],P[7][1]); gl.glEnd(); gl.glBegin(GL.GL_LINES); gl.glVertex2f(P[0][0],P[0][1]); gl.glVertex2f(P[4][0],P[4][1]); gl.glVertex2f(P[1][0],P[1][1]); gl.glVertex2f(P[5][0],P[5][1]); gl.glVertex2f(P[2][0],P[2][1]); gl.glVertex2f(P[6][0],P[6][1]); gl.glVertex2f(P[3][0],P[3][1]); gl.glVertex2f(P[7][0],P[7][1]); gl.glEnd(); } } Vamos aplicar uma rotação sobre os vértices do cubo e verificar o resultado. Para isso acrescentaremos um método que aplica uma rotação em cada um dos vértices do cubo. import net.java.games.jogl.*; public class cubo { float[][] P; cubo() { P = new float[8][3]; unitario(); } public void P[0][0] = P[0][1] = P[0][2] = P[1][0] = P[1][1] = P[1][2] = P[2][0] = P[2][1] = P[2][2] = P[3][0] = P[3][1] = P[3][2] = } unitario() { 0; P[4][0] 0; P[4][1] 0; P[4][2] 1; P[5][0] 0; P[5][1] 0; P[5][2] 1; P[6][0] 1; P[6][1] 0; P[6][2] 0; P[7][0] 1; P[7][1] 0; P[7][2] = = = = = = = = = = = = 0; 0; 1; 1; 0; 1; 1; 1; 1; 0; 1; 1; public void rotaciona_x(double t) { float y,z; for(int i =0; i < 8 ;i++) { y = P[i][1] * (float)Math.cos(t) – P[i][2] * (float)Math.sin(t); z = P[i][1] * (float)Math.sin(t) + 4 P[i][2] * (float)Math.cos(t); P[i][1] = y; P[i][2] = z; } } public void rotaciona_y(double t) { float x,z; for(int i =0; i < 8 ;i++) { x = P[i][0] * (float)Math.cos(t) – P[i][2] * (float)Math.sin(t); z = P[i][0] * (float)Math.sin(t) + P[i][2] * (float)Math.cos(t); P[i][0] = x; P[i][2] = z; } } public void rotaciona_z(double t) { float x,y; for(int i =0; i < 8 ;i++) { x = P[i][0] * (float)Math.cos(t) – P[i][1] * (float)Math.sin(t); y = P[i][0] * (float)Math.sin(t) + P[i][1] * (float)Math.cos(t); P[i][0] = x; P[i][1] = y; } } public void render_cubo(GLDrawable drawable) { GL gl = drawable.getGL(); unitario(); rotaciona_z(Math.PI / 4); rotaciona_y(Math.PI / 4); rotaciona_z(Math.PI / 6); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(P[0][0],P[0][1]); gl.glVertex2f(P[1][0],P[1][1]); gl.glVertex2f(P[2][0],P[2][1]); gl.glVertex2f(P[3][0],P[3][1]); gl.glEnd(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex2f(P[4][0],P[4][1]); gl.glVertex2f(P[5][0],P[5][1]); gl.glVertex2f(P[6][0],P[6][1]); gl.glVertex2f(P[7][0],P[7][1]); gl.glEnd(); } gl.glBegin(GL.GL_LINES); gl.glVertex2f(P[0][0],P[0][1]); gl.glVertex2f(P[4][0],P[4][1]); gl.glVertex2f(P[1][0],P[1][1]); gl.glVertex2f(P[5][0],P[5][1]); gl.glVertex2f(P[2][0],P[2][1]); gl.glVertex2f(P[6][0],P[6][1]); gl.glVertex2f(P[3][0],P[3][1]); gl.glVertex2f(P[7][0],P[7][1]); gl.glEnd(); 5 } 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); 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. 6 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. main.cpp import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static cubo Q; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Cubo"); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GL gl = drawable.getGL(); 7 Q = new cubo(); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrtho(-2.0,2.0,-2.0,2.0,-2.0,2.0); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glRotatef(30,0,0,1); gl.glRotatef(45,0,1,0); gl.glRotatef(45,0,0,1); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); Q.render_cubo(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } } cubo.java import net.java.games.jogl.*; public class cubo { float[][] P; cubo() { P = new float[8][3]; unitario(); } public void P[0][0] = P[0][1] = P[0][2] = P[1][0] = P[1][1] = P[1][2] = P[2][0] = P[2][1] = P[2][2] = P[3][0] = P[3][1] = P[3][2] = } unitario() { 0; P[4][0] 0; P[4][1] 0; P[4][2] 1; P[5][0] 0; P[5][1] 0; P[5][2] 1; P[6][0] 1; P[6][1] 0; P[6][2] 0; P[7][0] 1; P[7][1] 0; P[7][2] = = = = = = = = = = = = 0; 0; 1; 1; 0; 1; 1; 1; 1; 0; 1; 1; 8 public void render_cubo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(P[0][0],P[0][1],P[0][2]); gl.glVertex3f(P[1][0],P[1][1],P[1][2]); gl.glVertex3f(P[2][0],P[2][1],P[2][2]); gl.glVertex3f(P[3][0],P[3][1],P[3][2]); gl.glEnd(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(P[4][0],P[4][1],P[4][2]); gl.glVertex3f(P[5][0],P[5][1],P[4][2]); gl.glVertex3f(P[6][0],P[6][1],P[4][2]); gl.glVertex3f(P[7][0],P[7][1],P[4][2]); gl.glEnd(); gl.glBegin(GL.GL_LINES); gl.glVertex3f(P[0][0],P[0][1],P[0][2]); gl.glVertex3f(P[4][0],P[4][1],P[4][2]); gl.glVertex3f(P[1][0],P[1][1],P[1][2]); gl.glVertex3f(P[5][0],P[5][1],P[5][2]); gl.glVertex3f(P[2][0],P[2][1],P[2][2]); gl.glVertex3f(P[6][0],P[6][1],P[6][2]); gl.glVertex3f(P[3][0],P[3][1],P[3][2]); gl.glVertex3f(P[7][0],P[7][1],P[7][2]); gl.glEnd(); } } 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 . 1.5.3- Escala 9 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. triangulo.java import net.java.games.jogl.*; public class triangulo { float[][] P; triangulo() { P = new float[3][3]; P[1][0] = 0.5f; P[2][0] = 0.25f; P[2][1] = 0.43f; } public void render_triangulo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glBegin(GL.GL_TRIANGLES); gl.glVertex3f(P[0][0],P[0][1],P[0][2]); gl.glVertex3f(P[1][0],P[1][1],P[1][2]); gl.glVertex3f(P[2][0],P[2][1],P[2][2]); gl.glEnd(); } } main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static triangulo Q; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Cubo V02"); canvas.addGLEventListener( new JoglRender() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { 10 public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); Q = new triangulo(); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); Q.render_triangulo(drawable); gl.glColor3f(0.0f,1.0f,0.0f); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef( 0.5f, 0.5f,0.0f); Q.render_triangulo(drawable); gl.glLoadIdentity(); gl.glColor3f(0.0f,0.0f,1.0f); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glRotatef(45,0.0f,0.0f,1.0f); Q.render_triangulo(drawable); gl.glLoadIdentity(); gl.glColor3f(1.0f,1.0f,0.0f); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glScalef(0.5f, 0.5f,0.5f); Q.render_triangulo(drawable); gl.glLoadIdentity(); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } 11 } } 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- Projeção Perspectiva 12 Em uma projeção perspectiva, nós estabelecemos um cone de visualização. O comando utilizado é: void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far); 1.8- Â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 torno do eixo z. no sentido anti-horário em Em seguida o sistema de coordenadas resultante é rotacionado em torno do eixo y de graus. 13 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. main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static dominio D = new dominio(); static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Dominio 3D"); canvas.addGLEventListener( new JoglRender() ); 14 frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GL gl = drawable.getGL(); D.init(gl); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); D.plota_eixo(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } } Dominio.java import net.java.games.jogl.*; public class dominio { float xmin,xmax,ymin,ymax,zmin,zmax; float gama,phi,theta; dominio() xmin = xmax = gama = phi = theta= } { ymin = zmin = -1; ymax = zmax = 1; 90; 45; 135; 15 dominio(float xm,float ym,float zm,float xM,float yM,float zM) { xmin = xm; ymin = ym; zmin = zm; xmax = xM; ymax = yM; zmax = zM; gama = 90; phi = 45; theta= 135; } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); } gl.glColor3f (1.0f, 0.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (xmax,0,0); gl.glVertex3f (0,0,0); gl.glEnd(); gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (0,0,0); gl.glVertex3f (0,ymax,0); gl.glEnd(); gl.glColor3f (0.0f, 0.0f, 1.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (0,0,0); gl.glVertex3f (0,0,zmax); gl.glEnd(); public void init(GL gl) { gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrtho(xmin,xmax, ymin,ymax, zmin,zmax); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glRotatef(gama ,0,0,1); gl.glRotatef(phi ,0,1,0); gl.glRotatef(theta,0,0,1); } public void set_angle(float g,float p,float t) { gama = g; phi = p; theta = t; } } 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 muse anda na direção vertical alteramos phi. 16 main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static dominio D = new dominio(); static int xm,xb,ym,yb; static float gama,phi,theta; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Dominio 3D"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GL gl = drawable.getGL(); gama = 90; phi = 45; theta = 135; D .init(gl); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); D.init(gl); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); D.plota_eixo(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, 17 int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==1) { System.out.println("Entra"); xb = e.getX(); yb = e.getY(); } } public void mouseReleased(MouseEvent e) { if (e.getButton()==1) { theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); canvas.display(); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } static class JoglMouseMotion implements MouseMotionListener { public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { xm = e.getX(); ym = e.getY(); theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); theta = theta - xm + xb; phi = phi + ym - yb; canvas.display(); } } } public void mouseMoved(MouseEvent e) { } } 18 1.9 – Visualização de gráfico de funções A seguir apresentamos um programa exemplo para visualização de gráficos de funções . main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static dominio D = new dominio(); static funcao f = new funcao(); static int xm,xb,ym,yb; static float gama,phi,theta; static float scale; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new LCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Funcao 3D"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addMouseWheelListener( new JoglMouseWheel() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GL gl = drawable.getGL(); gama = 90; phi = 45; theta = 135; D .init(gl); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); D.init(gl); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); 19 gl.glColor3f(1.0f,0.0f,0.0f); D.plota_eixo(drawable); f.plota_funcao(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==1) { System.out.println("Entra"); xb = e.getX(); yb = e.getY(); } } public void mouseReleased(MouseEvent e) { if (e.getButton()==1) { theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); canvas.display(); } } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } static class JoglMouseMotion implements MouseMotionListener { public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & 20 InputEvent.BUTTON1_MASK) != 0) { xm = e.getX(); ym = e.getY(); theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); theta = theta - xm + xb; phi = phi + ym - yb; canvas.display(); } } public void mouseMoved(MouseEvent e) { } } static class JoglMouseWheel implements MouseWheelListener { public void mouseWheelMoved(MouseWheelEvent e) { scale += e.getWheelRotation()/10.0; D.set_scale(scale); canvas.display(); } } } funcao.java import net.java.games.jogl.*; public class funcao { float xmin,xmax,ymin,ymax; int points; funcao() { xmin = ymin = -1; xmax = ymax = 1; points = 10; } public float f(float x,float y) { return(x*x+y*y); } public void plota_funcao(GLDrawable drawable) { GL gl = drawable.getGL(); float x,y; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; gl.glColor3f (1.0f, 1.0f, 1.0f); x = xmin; 21 for(int i=0;i<points;i++) { y = ymin; for(int j=0;j<points;j++){ gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(x ,y ,f(x ,y) ); gl.glVertex3f(x+dx,y ,f(x+dx,y) ); gl.glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); gl.glVertex3f(x ,y+dy,f(x ,y+dy)); gl.glEnd(); y += dy; } x += dx; } } } import net.java.games.jogl.*; public class dominio { float xmin,xmax,ymin,ymax,zmin,zmax; float gama,phi,theta; float scale; dominio() xmin = xmax = gama = phi = theta= scale= } { ymin = zmin = -2; ymax = zmax = 2; 90; 45; 135; 1; dominio(float xm,float ym,float zm,float xM,float yM,float zM) { xmin = xm; ymin = ym; zmin = zm; xmax = xM; ymax = yM; zmax = zM; gama = 90; phi = 45; theta= 135; scale= 1; } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f (1.0f, 0.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (xmax,0,0); gl.glVertex3f (0,0,0); gl.glEnd(); gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); 22 gl.glVertex3f (0,0,0); gl.glVertex3f (0,ymax,0); gl.glEnd(); gl.glColor3f (0.0f, 0.0f, 1.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (0,0,0); gl.glVertex3f (0,0,zmax); gl.glEnd(); } public void init(GL gl) { gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrtho(xmin,xmax, ymin,ymax, zmin,zmax); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glScalef(scale,scale,scale); gl.glRotatef(gama ,0,0,1); gl.glRotatef(phi ,0,1,0); gl.glRotatef(theta,0,0,1); } public void set_angle(float g,float p,float t) { gama = g; phi = p; theta = t; } public void set_scale(float s) { scale = s; } } 23 2- ILUMINAÇÃO Para definir o seu modelo de iluminação são necessárias três etapas básicas: 1) Definir as fontes de luz (posição, cor, direção, etc.); 2) Definir a iluminação. 3) Definir o tipo de material do 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 Emitida: é a componente que se origina de um objeto e é inalterada pelas fontes de luz. - 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 a luz ambiente, difusa e especular. Vamos iniciar com um simples exemplo, ilustrando as dificuldades de se estabelecer uma boa iluminação. Nosso primeiro exemplo é um cubo, com uma face amarela e outra verde, onde se estabeleceu uma iluminação básica, porém não satisfatória ainda. A classe Iluminacao contem alguns parâmetros básicos. main.java public class main { static dominio D = new dominio(); static Iluminacao I = new Iluminacao(); static cubo C = new cubo(); ... static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { GL gl = drawable.getGL(); gama = 90; phi = 45; theta = 135; D.init(drawable); I.light_on(drawable); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); D.init(drawable); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); D.plota_eixo(drawable); I.render_light(drawable); 24 I.light_on(drawable); C.render_cubo(drawable); I.light_off(drawable); gl.glFlush(); } ... } dominio.java public class dominio { ... public void init(GLDrawable drawable) { ... gl.glRotatef(phi ,0,1,0); gl.glRotatef(theta,0,0,1); gl.glEnable(GL.GL_DEPTH_TEST); } cubo.java public class cubo { ... public void render_cubo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f(1,1,0); gl.glBegin(GL.GL_QUADS); gl.glNormal3f(0,0,1); gl.glVertex3f(P[0][0],P[0][1],P[0][2]); gl.glVertex3f(P[1][0],P[1][1],P[1][2]); gl.glVertex3f(P[2][0],P[2][1],P[2][2]); gl.glVertex3f(P[3][0],P[3][1],P[3][2]); gl.glEnd(); gl.glColor3f(0,1,0); gl.glBegin(GL.GL_QUADS); gl.glNormal3f(0,0,1); gl.glVertex3f(P[4][0],P[4][1],P[4][2]); gl.glVertex3f(P[5][0],P[5][1],P[4][2]); gl.glVertex3f(P[6][0],P[6][1],P[4][2]); gl.glVertex3f(P[7][0],P[7][1],P[4][2]); gl.glEnd(); gl.glColor3f(1,0,1); gl.glBegin(GL.GL_LINES); gl.glVertex3f(P[0][0],P[0][1],P[0][2]); gl.glVertex3f(P[4][0],P[4][1],P[4][2]); gl.glVertex3f(P[1][0],P[1][1],P[1][2]); gl.glVertex3f(P[5][0],P[5][1],P[5][2]); gl.glVertex3f(P[2][0],P[2][1],P[2][2]); gl.glVertex3f(P[6][0],P[6][1],P[6][2]); gl.glVertex3f(P[3][0],P[3][1],P[3][2]); 25 gl.glVertex3f(P[7][0],P[7][1],P[7][2]); gl.glEnd(); } ... } Iluminacao.java import net.java.games.jogl.*; public class Iluminacao { float[] mat_specular; float[] mat_shininess; float[] light_position; Iluminacao() { mat_specular = new float[4]; mat_specular[0] = 1.0f; mat_specular[1] = 1.0f; mat_specular[2] = 1.0f; mat_specular[3] = 1.0f; mat_shininess = new float[1]; mat_shininess[0] = 50.0f; } light_position = new float[4]; light_position[0] = 2.0f; light_position[1] = 2.0f; light_position[2] = 2.0f; light_position[3] = 1.0f; public void light_on(GLDrawable drawable) { } GL gl = drawable.getGL(); gl.glShadeModel (GL.GL_SMOOTH); gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular); gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess); gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position); gl.glEnable(GL.GL_LIGHTING); gl.glEnable(GL.GL_LIGHT0); gl.glEnable(GL.GL_COLOR_MATERIAL); gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE); gl.glEnable(GL.GL_NORMALIZE); public void render_light(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f(1,0,0); gl.glPointSize(8); gl.glBegin(GL.GL_POINTS); gl.glVertex3f(light_position[0], light_position[1], light_position[2]); 26 gl.glEnd(); } public void light_off(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glDisable(GL.GL_LIGHTING); gl.glDisable(GL.GL_LIGHT0); gl.glDisable(GL.GL_DEPTH_TEST); } } 2.1– 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) GL_DIFFUSE GL_SPECULAR (1.0, 1.0, 1.0, 1.0) (1.0, 1.0, 1.0, 1.0) GL_POSITION GL_SPOT_DIRECTION GL_SPOT_EXPONENT (0.0, 0.0, 1.0, 0.0) (0.0, 0.0, -1.0) 0.0 GL_SPOT_CUTOFF GL_CONSTANT_ATTENUATION GL_LINEAR_ATTENUATION GL_QUADRATIC_ATTENUATION 180.0 1.0 0.0 0.0 Intensidade da luz ambiente Intensidade da luz difusa Intensidade da luz especular posição da luz direção da luz Parâmetro que controla a distribuição da luz. Ângulo de abertura da luz 2.1.1– Cor A característica da luz é definida pelo parâmetro iluminação. O modelo de iluminação do OPENGL considera que a iluminação pode ser dividida em quatro componentes independentes: emitida, ambiente, difusa e especular. - Luz Emitida: é a componente que se origina de um objeto e é inalterada pelas fontes de luz. - 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. Por exemplo, para alterar a luz ambiente utiliza-se o seguinte código: GLfloat luz_ambiente[4] = { 0.0, 0.0, 0.0, 1.0 }; 27 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambiente); 2.1.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 luz_posicao[4]={x , y, z, 1.0}. 2.2– Selecionando o Modelo de Iluminação 2.2.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 o comando: 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.2.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.2.3 – Iluminação nos dois lados das faces 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.2.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); 28 2.3– Selecionando as Propriedades do Material Para definir as propriedades do material do objeto em cena utilizamos os 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) GL_DIFFUSE (0.8, 0.8, 0.8, 1.0) GL_SPECULAR GL_SHININESS GL_EMISSION (0.0, 0.0, 0.0, 1.0) 0.0 (0.0, 0.0, 0.0, 1.0) Cor da luz ambiente do material Cor da luz difusa do material Especular cor do material Índice especular Cor de emissão do material 2.4– Exemplo 1 Como exemplo, inserimos o modulo de iluminacao no programa funcao3D. funcao.java import net.java.games.jogl.*; public class funcao { float xmin,xmax,ymin,ymax; int points; funcao() { xmin = ymin = -2; xmax = ymax = 2; points = 40; } // public float f(float x,float y) { return(x*x-y*y); return((float)Math.cos(Math.sqrt(x*x+y*y))); } public void plota_funcao(GLDrawable drawable) { GL gl = drawable.getGL(); float x,y; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; float[] v; gl.glColor3f (1.0f, 1.0f, 1.0f); 29 x = xmin; for(int i=0;i<points;i++) { y = ymin; for(int j=0;j<points;j++){ gl.glBegin(GL.GL_QUADS); v = normal(x,y); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x ,y ,f(x ,y) ); v = normal(x+dx,y); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x+dx,y ,f(x+dx,y) ); v = normal(x+dx,y+dy); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); v = normal(x,y+dy); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x ,y+dy,f(x ,y+dy)); gl.glEnd(); y += dy; } x += dx; } } public float dfx(float x,float y) { // return(2*x); return((float)(-Math.sin(Math.sqrt(x*x+y*y))*x/Math.sqrt(x*x+y*y))); } public float dfy(float x,float y) { // return(-2*y); return((float)(-Math.sin(Math.sqrt(x*x+y*y))*y/Math.sqrt(x*x+y*y)) ); } public float[] normal(float x,float y) { float[] v = new float[3]; v[0] = -dfx(x,y); v[1] = -dfy(x,y); v[2] = 1; return(v); } } main.java import net.java.games.jogl.*; public class main { static static static static static static dominio D = new dominio(); funcao f = new funcao(); Iluminacao I = new Iluminacao(); int xm,xb,ym,yb,mov=0; float gama,phi,theta; float scale; 30 static GLCanvas canvas GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); = public static void main(String[] args) { Frame frame = new Frame("Funcao 3D"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addMouseWheelListener( new JoglMouseWheel() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { gama = 90; phi = 45; theta = 135; D .init(drawable); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); D.init(drawable); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glColor3f(1.0f,0.0f,0.0f); D.plota_eixo(drawable); I.render_light(drawable); I.light_on(drawable); f.plota_funcao(drawable); I.light_off(drawable); gl.glFlush(); } ... } Iluminacao.java import net.java.games.jogl.*; public class Iluminacao { float[] float[] float[] float[] mat_specular; mat_shininess; light_position; light_diffuse; Iluminacao() { 31 mat_specular = new float[4]; mat_specular[0] = 1.0f; mat_specular[1] = 1.0f; mat_specular[2] = 0.0f; mat_specular[3] = 1.0f; mat_shininess = new float[1]; mat_shininess[0] = 50.0f; light_position = new float[4]; light_position[0] = 2.0f; light_position[1] = 2.0f; light_position[2] = 2.0f; light_position[3] = 1.0f; } light_diffuse = new float[4]; light_diffuse[0] = 1.0f; light_diffuse[1] = 0.0f; light_diffuse[2] = 0.0f; light_diffuse[3] = 1.0f; public float[] get_light_position() { return(light_position); } public void rotaciona_light() { double x,y; double t = 0.01; Math.sin(t); Math.cos(t); x= light_position[0] * Math.cos(t) - light_position[1] * y= light_position[0] * Math.sin(t) + light_position[1] * light_position[0] = (float)x; light_position[1] = (float)y; } public void light_on(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glShadeModel (GL.GL_SMOOTH); gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular); gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess); gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position); gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE , light_diffuse); gl.glEnable(GL.GL_LIGHTING); gl.glEnable(GL.GL_LIGHT0); gl.glEnable(GL.GL_COLOR_MATERIAL); gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE); gl.glEnable(GL.GL_NORMALIZE); } public void render_light(GLDrawable drawable) { GL gl = drawable.getGL(); 32 gl.glColor3f(1,1,1); gl.glPointSize(8); gl.glBegin(GL.GL_POINTS); ); gl.glVertex3f(light_position[0],light_position[1],light_position[2] gl.glEnd(); } public void light_off(GLDrawable drawable) { GL gl = drawable.getGL(); // } } gl.glDisable(GL.GL_LIGHTING); gl.glDisable(GL.GL_LIGHT0); gl.glDisable(GL.GL_DEPTH_TEST); dominio.java import net.java.games.jogl.*; public class dominio { float float float float xmin,xmax,ymin,ymax,zmin,zmax; gama,phi,theta; scale; aa,bb; dominio() xmin = xmax = gama = phi = theta= scale= } { ymin = zmin = -5; ymax = zmax = 5; 90; 45; 135; 1; dominio(float xm,float ym,float zm,float xM,float yM,float zM) { xmin = ymin = zmin = xmax = ymax = zmax = gama = phi = theta= xm; ym; zm; xM; yM; zM; 90; 45; 135; } public void plota_eixo(GLDrawable drawable) { GL gl = drawable.getGL(); gl.glColor3f (1.0f, 0.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (xmax,0,0); gl.glVertex3f (0,0,0); 33 } gl.glEnd(); gl.glColor3f (0.0f, 1.0f, 0.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (0,0,0); gl.glVertex3f (0,ymax,0); gl.glEnd(); gl.glColor3f (0.0f, 0.0f, 1.0f); gl.glBegin (GL.GL_LINES); gl.glVertex3f (0,0,0); gl.glVertex3f (0,0,zmax); gl.glEnd(); public void init(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); // // // gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrtho(xmin,xmax, ymin,ymax, zmin,zmax); glu.gluPerspective(40.0,1.0,0.1,40); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0,0,-10); gl.glScalef(scale,scale,scale); gl.glRotatef(gama ,0,0,1); gl.glRotatef(phi ,0,1,0); gl.glRotatef(theta,0,0,1); gl.glEnable(GL.GL_DEPTH_TEST); } public void set_angle(float g,float p,float t) { gama = g; phi = p; theta = t; } public void set_scale(float s) { scale = s; } } 2.5– Comando glLookAt O comando glLookAt permite que você defina 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). 34 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. No exemplo abaixo, o observador se desloca sobre uma helice olhando sempre para a origem do sistema. dominio.java public void init(GLDrawable drawable) { GL gl = drawable.getGL(); GLU glu = drawable.getGLU(); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(40.0,1.0,0.1,40); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); gl.glScalef(scale,scale,scale); glu.gluLookAt(2.1*Math.cos(t), 2.1*Math.sin(t), t+0.01, 0,0,0 ,0,0,1); t -= 0.01; gl.glEnable(GL.GL_DEPTH_TEST); } curva.java import net.java.games.jogl.*; public class curva { float tmin,tmax; int points; curva() { tmin = 0; tmax = 10; points = 80; } public float[] c(float t) { float[] p = new float[3]; p[0] = 2*(float)Math.cos(t); p[1] = 2*(float)Math.sin(t); p[2] = (float)t; return(p); } public void plota_curva(GLDrawable drawable) { GL gl = drawable.getGL(); float t; float dt = (tmax-tmin)/points; float[] v; gl.glColor3f (1.0f, 1.0f, 1.0f); gl.glBegin(GL.GL_LINE_STRIP); t = tmin; for(int i=0;i<points;i++) { 35 v = c(t); gl.glVertex3f(v[0],v[1],v[2]); t += dt; } } gl.glEnd(); } 2.6 – Visualizando as normais Podemos acrescentar um novo metodo para visualizarmos as normais sobre a superfície. public void plota_normal(GLDrawable drawable) { GL gl = drawable.getGL(); float x,y; float dx = (xmax-xmin)/points; float dy = (ymax-ymin)/points; float[] v; float n = 10; gl.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++){ gl.glBegin(GL.GL_LINES); v = normal(x,y); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x ,y ,f(x ,y) ); gl.glVertex3f(x+v[0]/n,y+v[1]/n,f(x ,y)+v[2]/n); v = normal(x+dx,y); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x+dx,y ,f(x+dx,y) ); gl.glVertex3f(x+dx+v[0]/n,y+v[1]/n,f(x+dx,y)+v[2]/n); v = normal(x+dx,y+dy); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x+dx,y+dy,f(x+dx,y+dy)); gl.glVertex3f(x+dx+v[0]/n,y+dy+v[1]/n,f(x+dx,y+dy)+v[2]/n); v = normal(x,y+dy); gl.glNormal3f(v[0],v[1],v[2]); gl.glVertex3f(x ,y+dy,f(x ,y+dy)); gl.glVertex3f(x+v[0]/n,y+dy+v[1]/n,f(x,y+dy)+v[2]/n); gl.glEnd(); 36 } y += dy; } x += dx; } 3- SUPERFÍCIES PARAMETRIZADAS Para compreender a idéia de uma superfície parametrizada, considere D uma região do plano, cujas variáveis são denotadas por . A cada par de D vamos associar um ponto no espaço tridimensional, o qual pode ser escrito em termos de suas funções coordenadas por: Uma superfície parametrizada é uma aplicação superfície S correspondente a função parâmetros (u, v). é a imagem onde D é algum domínio em . A . A superfície parametrizada depende de dois 3.1– Visualização de superfícies na forma paramétrica . Para visualizar superfícies dadas na forma paramétrica, utilizaremos o programa abaixo. O programa é composto de dois módulos: sup_main.cpp e sup_param.cpp. O módulo sup_main.cpp é responsável pelas tarefas de iluminação e definição do ambiente OpenGL. O segundo módulo sup_param.cpp define a parametrização e através da função draw_superficie(), visualiza a superfície desejada. 37 import net.java.games.jogl.*; public class parametrico { float vmin,vmax,umin,umax; int points; parametrico() { vmin = umin = 0; vmax = (float)Math.PI; umax = 2*(float)Math.PI; points = 40; } public float[] superficie(float u,float v) { float[] r = new float[3]; r[0] = (float)(Math.cos(u) * Math.sin(v)); r[1] = (float)(Math.sin(u) * Math.sin(v)); r[2] = (float)(Math.cos(v)); r[0] = (float)(-Math.sin(u)*(2+Math.cos(v))); r[1] = (float)(Math.cos(u)*(2+Math.cos(v))); r[2] = (float)(Math.sin(v)); } return(r); public void GL gl float float float plota_superficie(GLDrawable drawable) { = drawable.getGL(); u,v; du = (umax-umin)/points; dv = (vmax-vmin)/points; float[] r,n; gl.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++){ gl.glBegin(GL.GL_QUADS); n = normal(u,v); r = superficie(u,v); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(r[0],r[1],r[2]); n = normal(u+du,v); r = superficie(u+du,v); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(r[0],r[1],r[2]); n = normal(u+du,v+dv); r = superficie(u+du,v+dv); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(r[0],r[1],r[2]); n = normal(u,v+dv); r = superficie(u,v+dv); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(r[0],r[1],r[2]); 38 gl.glEnd(); v += dv; } } } u += du; public float[] normal(float u,float v) { float[] v1 = new float[3]; float[] v2 = new float[3]; float[] n = new float[3]; float norma; float[] p1 = new float[3]; float[] p2 = new float[3]; float[] p3 = new float[3]; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; p1 = superficie(u,v); p2 = superficie(u,v+dv); p3 = superficie(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 = (float)Math.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; return(n); } } 3.2– Exercícios 1) Utilizando o programa anterior, visualize as seguintes superfícies e identifique-as: a) b) c) d) 39 e) f) g) 2) Visualize os vetores normais sobre a superfície. Observe o exemplo da letra f). 40 4- SUPERFÍCIES IMPLÍCITAS main.java import net.java.games.jogl.*; public class main { static dominio D = new dominio(); static superficie f = new superficie(); static Iluminacao I = new Iluminacao(); static int xm,xb,ym,yb,mov=0; static float gama,phi,theta; static float scale; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Superficie Implicita"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addMouseWheelListener( new JoglMouseWheel() ); frame.add(canvas); frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { gama = 90; phi = 45; theta = 135; D.init(drawable); f.set_draw(drawable); } public void display(GLDrawable drawable) { GL gl = drawable.getGL(); D.init(drawable); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); D.plota_eixo(drawable); I.render_light(drawable); I.light_on(drawable); f.plota_funcao(); I.light_off(drawable); 41 gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { if (e.getButton()==1) { xb = e.getX(); yb = e.getY(); } if (e.getButton()==3) { mov = (mov+1) % 2; if (mov == 0) System.out.println("Scala "); else System.out.println("Resolucao "); } } } public void mouseReleased(MouseEvent e) { if (e.getButton()==1) { theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); canvas.display(); } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } { static class JoglMouseMotion implements MouseMotionListener 42 public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { xm = e.getX(); ym = e.getY(); theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); theta = theta - xm + xb; phi = phi + ym - yb; canvas.display(); } } public void mouseMoved(MouseEvent e) { } } static class JoglMouseWheel implements MouseWheelListener { public void mouseWheelMoved(MouseWheelEvent e) { if (mov == 0){ scale += e.getWheelRotation()/10.0; D.set_scale(scale); canvas.display(); } else { int p = f.get_pontos(); p += e.getWheelRotation(); if (p <= 0) p = 1; f.set_pontos(p); canvas.display(); } } } } superficie.java import net.java.games.jogl.*; public class superficie { float xmin,xmax,ymin,ymax,zmin,zmax; int pontos; GLDrawable drawable; superficie() { xmin = ymin xmax = ymax pontos = 5; } = zmin = -2; = zmax = 2; public int get_pontos() { 43 return pontos; } public void set_pontos(int p) { pontos = p; } public void set_draw(GLDrawable draw) { drawable = draw; } // public float f(float x,float y,float z) { return(x*x-y*y-z); return(x*x+(float)Math.cos(x)*y*y-z*y-1); } // // // public void normal(float[] v, float x,float y,float z) { v[0] = 2*x-(float)Math.sin(x)*y*y; v[1] = 2*y*(float)Math.cos(x)-z; v[2] = -y; v[0] = 2*x; v[1] = -2*y; v[2] = -1.0f; } void intersect(float[] v,float[] x,float[] y,float[] z,float[] w,int i,int j) { float t; t = w[i]/(w[i]-w[j]); v[0] = x[i] + t * (x[j] - x[i]); v[1] = y[i] + t * (y[j] - y[i]); v[2] = z[i] + t * (z[j] - z[i]); } void tri(float[] x,float[] y,float[] z,float[] w,int i,int j,int k,int l) { GL gl = drawable.getGL(); float[] v1 = new float[3]; float[] v2 = new float[3]; float[] v3 = new float[3]; float[] n = new float[3]; intersect(v1,x,y,z,w,i,j); intersect(v2,x,y,z,w,i,k); intersect(v3,x,y,z,w,i,l); gl.glBegin(GL.GL_TRIANGLES); normal(n,v1[0],v1[1],v1[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v1[0],v1[1],v1[2]); normal(n,v2[0],v2[1],v2[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v2[0],v2[1],v2[2]); normal(n,v3[0],v3[1],v3[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v3[0],v3[1],v3[2]); gl.glEnd(); 44 } void quad(float[] x,float[] y,float[] z,float[] w,int i,int j,int k,int l) { GL gl = drawable.getGL(); float[] v1 = new float[3]; float[] v2 = new float[3]; float[] v3 = new float[3]; float[] v4 = new float[3]; float[] n = new float[3]; } intersect(v1,x,y,z,w,i,k); intersect(v2,x,y,z,w,i,l); intersect(v3,x,y,z,w,j,l); intersect(v4,x,y,z,w,j,k); gl.glBegin(GL.GL_TRIANGLES); normal(n,v1[0],v1[1],v1[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v1[0],v1[1],v1[2]); normal(n,v2[0],v2[1],v2[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v2[0],v2[1],v2[2]); normal(n,v3[0],v3[1],v3[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v3[0],v3[1],v3[2]); gl.glEnd(); gl.glBegin(GL.GL_TRIANGLES); normal(n,v1[0],v1[1],v1[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v1[0],v1[1],v1[2]); normal(n,v3[0],v3[1],v3[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v3[0],v3[1],v3[2]); normal(n,v4[0],v4[1],v4[2]); gl.glNormal3f(n[0],n[1],n[2]); gl.glVertex3f(v4[0],v4[1],v4[2]); gl.glEnd(); void tetraedro(float[] x,float[] y,float[] z,float[] w,int i,int j,int k,int l) { GL gl = drawable.getGL(); // light_on(drawable); gl.glColorMaterial(GL.GL_FRONT, GL.GL_DIFFUSE); gl.glColor3f(1,1,0); gl.glColorMaterial(GL.GL_BACK , GL.GL_DIFFUSE); gl.glColor3f(1,0,0.2f); if (w[i] < 0) { if (w[j] < 0) { if (w[k] < 0) { if (w[l] >= 0) tri(x,y,z,w,l,k,j,i); } else { if (w[l] < 0) tri(x,y,z,w,k,i,j,l); else 45 quad(x,y,z,w,k,l,i,j); } } else { if (w[k] < 0) { if (w[l] < 0) tri(x,y,z,w,j,l,k,i); else quad(x,y,z,w,j,l,k,i); } else { if } } (w[l] < 0) quad(x,y,z,w,j,k,i,l); else tri(x,y,z,w,i,l,k,j); } else { if (w[j] < 0) { if (w[k] < 0) { if (w[l] < 0) tri(x,y,z,w,i,j,k,l); else quad(x,y,z,w,i,l,j,k); } else { if } (w[l] < 0) quad(x,y,z,w,i,k,l,j); else tri(x,y,z,w,j,l,i,k); } else { if (w[k] < 0) { if (w[l] < 0) quad(x,y,z,w,i,j,k,l); else tri(x,y,z,w,k,l,j,i); } else { } if (w[l] < 0) tri(x,y,z,w,l,i,j,k); } // } desabilita_lighting(); gl.glColorMaterial(GL.GL_FRONT, GL.GL_DIFFUSE); gl.glColor3f(0.0f,0.0f,1.0f); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(x[i],y[i],z[i]); gl.glVertex3f(x[j],y[j],z[j]); gl.glVertex3f(x[k],y[k],z[k]); gl.glEnd(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(x[i],y[i],z[i]); gl.glVertex3f(x[j],y[j],z[j]); gl.glVertex3f(x[l],y[l],z[l]); gl.glEnd(); 46 gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(x[i],y[i],z[i]); gl.glVertex3f(x[k],y[k],z[k]); gl.glVertex3f(x[l],y[l],z[l]); gl.glEnd(); gl.glBegin(GL.GL_LINE_LOOP); gl.glVertex3f(x[j],y[j],z[j]); gl.glVertex3f(x[k],y[k],z[k]); gl.glVertex3f(x[l],y[l],z[l]); gl.glEnd(); } public void plota_funcao() { GL gl = drawable.getGL(); int i,j,k,l; float x,y,z; float dx,dy,dz; float[] xv,yv,zv,wv; xv = new float[8]; yv = new float[8]; zv = new float[8]; wv = new float[8]; gl.glColor3f(1.0f,1.0f,0.0f); dx = (xmax - xmin)/pontos; dy = (ymax - ymin)/pontos; dz = (zmax - zmin)/pontos; for(i=0;i<pontos;i++) { x = xmin + i * dx; for (l = 0;l < 8;l++) xv[l] = ((l % 2) == 0) ? x : x+dx; for(j=0;j<pontos;j++) { y = ymin + j * dy; for (l = 0;l < 8;l++) yv[l] = ((l % 4) < 2) ? y : y+dy; for(k=0;k<pontos;k++) { z = zmin + k * dz; for (l = 0;l < 8;l++) { zv[l] = (l < 4) ? z : z+dz; wv[l] = f(xv[l],yv[l],zv[l]); } tetraedro(xv,yv,zv,wv,0,1,3,7); tetraedro(xv,yv,zv,wv,0,5,1,7); tetraedro(xv,yv,zv,wv,0,3,2,7); tetraedro(xv,yv,zv,wv,0,2,6,7); tetraedro(xv,yv,zv,wv,0,4,5,7); tetraedro(xv,yv,zv,wv,0,6,4,7); } } } } } 47 5- TEXTURA Parametrico.java import net.java.games.jogl.*; public class parametrico { float vmin,vmax,umin,umax; int points; parametrico() { vmin = umin = 0; vmax = (float)Math.PI; umax = 2*(float)Math.PI; vmin = umin = -5; umax = vmax = 5; points = 20; } public float[] superficie(float u,float v) { float[] r = new float[3]; r[0] = (float)(Math.cos(u) * Math.sin(v)); r[1] = (float)(Math.sin(u) * Math.sin(v)); r[2] = (float)(Math.cos(v)); r[0] = (float)(-Math.sin(u)*(2+Math.cos(v))); r[1] = (float)(Math.cos(u)*(2+Math.cos(v))); r[2] = (float)(Math.sin(v)); r[0] = u; r[1] = v; r[2] = (float)(Math.cos(Math.sqrt(u*u+v*v))); r[2] = (float)(Math.cos(u)*v); r[2] = (float)((Math.sqrt(u*u+v*v))); r[0] = u*(float)Math.cos(v); r[1] = u*(float)Math.sin(v); r[2] = u; // // // // // // // // } return(r); public void plota_superficie(GLDrawable drawable) { GL gl = drawable.getGL(); float u,v; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; float[] r,n; gl.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++){ gl.glBegin(GL.GL_QUADS); n = normal(u,v); r = superficie(u,v); gl.glNormal3f(n[0],n[1],n[2]); 48 gl.glTexCoord2f(u/10.0f+0.5f, v/10.0f+0.5f); gl.glTexCoord2f(0,0); gl.glTexCoord2f(u/umax, v/vmax); gl.glTexCoord2f(u, v); gl.glVertex3f(r[0],r[1],r[2]); n = normal(u+du,v); r = superficie(u+du,v); gl.glNormal3f(n[0],n[1],n[2]); gl.glTexCoord2f((u+du)/10.0f+0.5f, v/10.0f+0.5f); gl.glTexCoord2f(0, 1); gl.glTexCoord2f((u+du)/umax, v/vmax); gl.glTexCoord2f(u+du, v); gl.glVertex3f(r[0],r[1],r[2]); n = normal(u+du,v+dv); r = superficie(u+du,v+dv); gl.glNormal3f(n[0],n[1],n[2]); gl.glTexCoord2f((u+du)/10.0f+0.5f, (v+dv)/10.0f+0.5f); gl.glTexCoord2f(1, 1); gl.glTexCoord2f((u+du)/umax, (v+dv)/vmax); gl.glTexCoord2f(u+du, v+dv); gl.glVertex3f(r[0],r[1],r[2]); n = normal(u,v+dv); r = superficie(u,v+dv); gl.glNormal3f(n[0],n[1],n[2]); gl.glTexCoord2f(u/10.0f+0.5f, (v+dv)/10.0f+0.5f); gl.glTexCoord2f(1, 0); gl.glTexCoord2f(u/umax, (v+dv)/vmax); gl.glTexCoord2f(u, v+dv); gl.glVertex3f(r[0],r[1],r[2]); gl.glEnd(); v += dv; } u += du; } } public float[] normal(float u,float v) { float[] v1 = new float[3]; float[] v2 = new float[3]; float[] n = new float[3]; float norma; float[] p1 = new float[3]; float[] p2 = new float[3]; float[] p3 = new float[3]; float du = (umax-umin)/points; float dv = (vmax-vmin)/points; 49 p1 = superficie(u,v); p2 = superficie(u,v+dv); p3 = superficie(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 = (float)Math.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; return(n); } } Imagemrgb.java import net.java.games.jogl.*; import java.io.*; public class Imagemrgb { int int byte[][][] String dimx,dimy,range; rx,ry; imagergb; file; Imagemrgb(String s) { file = s; try { Reader q = new FileReader(s); int ch; String p; ch = q.read(); p = String.valueOf((char)ch); while(!Character.isWhitespace((char) ch )) { ch = q.read(); if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); } dimx = Integer.parseInt(p); 50 } while(Character.isWhitespace((char) ch)) ch = q.read(); p = String.valueOf((char)ch); while(!Character.isWhitespace((char) ch)) { ch = q.read(); if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); dimy = Integer.parseInt(p); while(Character.isWhitespace((char) ch)) ch = q.read(); p = String.valueOf((char)ch); while(!Character.isWhitespace((char) ch)) { ch = q.read(); if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); } range = Integer.parseInt(p); imagergb = new byte[dimx][dimy][3]; System.out.println(" " + dimx + " " + dimy + " " + range); for (int i = 0; i<dimx; i++) { for(int j = 0; j<dimy; j++) { for(int k = 0; k < 3; k++) { while(Character.isWhitespace((char) ch)) ch = q.read(); p = String.valueOf((char)ch); while (!Character.isWhitespace((char) ch)) { ch = q.read(); if (Character.isWhitespace((char) ch)) break; p += String.valueOf((char)ch); } imagergb[i][j][k] = (byte)Integer.parseInt(p); // // // + p ); } if (imagergb[i][j][k] < 0) imagergb[i][j][k] += 256; System.out.println(imagergb[i][j][k] + " " } } } catch (Exception e) { e.printStackTrace(); } } public byte get_image(int i,int j,int k) { if ((i < dimx) && (j < dimy)) { return(imagergb[i][j][k]); 51 } else { System.out.println(i+ " " + j + " " + dimx + " " + dimy + " " + imagergb[i][j][k]); return(0); } } public int get_dimx() { return dimx; } public int get_dimy() { return dimy; } public void draw_image(GLDrawable draw) { GL gl = draw.getGL(); for (int i=0;i<dimx;i++) for (int j=0;j<dimy;j++) { gl.glColor3f(imagergb[i][j][0]/(float)range,imagergb[i][j][1]/(floa t)range,imagergb[i][j][2]/(float)range); gl.glBegin(GL.GL_POINTS); gl.glVertex2d(j,i); gl.glEnd(); } } } main.java import java.awt.*; import java.awt.event.*; import net.java.games.jogl.*; public class main { static dominio D = new dominio(); static parametrico f = new parametrico(); static Iluminacao I = new Iluminacao(); static Textura T = new Textura("bricks2.pgm",1); // static Textura T = new Textura("sea.pgm"); static int xm,xb,ym,yb,mov=0; static float gama,phi,theta; static float scale; static GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); public static void main(String[] args) { Frame frame = new Frame("Textura"); canvas.addGLEventListener( new JoglRender() ); canvas.addMouseListener( new JoglMouse() ); canvas.addMouseMotionListener( new JoglMouseMotion() ); canvas.addMouseWheelListener( new JoglMouseWheel() ); frame.add(canvas); 52 } frame.setSize(600, 600); frame.setLocation(50,50); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); static class JoglRender implements GLEventListener { public void init(GLDrawable drawable) { } gama = 90; phi = 45; theta = 135; D.init(drawable); T.set_Drawable(drawable); T.init(); public void display(GLDrawable drawable) { GL gl = drawable.getGL(); GL.GL_DEPTH_BUFFER_BIT); D.init(drawable); gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | I.rotaciona_light(); D.plota_eixo(drawable); I.render_light(drawable); I.light_on(drawable); T.texture_on(); f.plota_superficie(drawable); T.texture_off(); I.light_off(drawable); gl.glFlush(); } public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void reshape(GLDrawable drawable, int x, int y, int width, int height) { } } static class JoglMouse implements MouseListener { public void mouseEntered(MouseEvent e) { // System.out.println("Mouse Entra"); } public void mouseExited (MouseEvent e) { // System.out.println("Mouse Sai"); } public void mousePressed(MouseEvent e) { 53 if (e.getButton()==1) { System.out.println("Entra"); xb = e.getX(); yb = e.getY(); } if (e.getButton()==2) { System.out.println("troca"); mov = (mov+1) %3; System.out.println("Persp = " + mov); } } } public void mouseReleased(MouseEvent e) { if (e.getButton()==1) { theta = theta + xm - xb; phi = phi - ym + yb ; D.set_angle(gama,phi,theta); canvas.display(); } public void mouseClicked(MouseEvent e) { System.out.println("Mouse botao"); } } { static class JoglMouseMotion implements MouseMotionListener public void mouseDragged(MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { xm = e.getX(); ym = e.getY(); theta = theta + xm phi = phi - ym + D.set_angle(gama,phi,theta); theta = theta - xm phi = phi + ym canvas.display(); } xb; yb ; + xb; - yb; } } public void mouseMoved(MouseEvent e) { } static class JoglMouseWheel implements MouseWheelListener { public void mouseWheelMoved(MouseWheelEvent e) { scale = D.get_scale(); scale += e.getWheelRotation()/10.0; D.set_scale(scale); 54 canvas.display(); } } } Textura.java import net.java.games.jogl.*; public class Textura { byte[] Image; int dimx,dimy,depth; int[] texName = new int[1]; int rx,ry; GLDrawable draw; Imagem I; Imagemrgb R; Textura(String s) { int ind; I = new Imagem(s); dimx = I.get_dimx(); dimy = I.get_dimy(); depth = 3; Image = new byte[dimx*dimy*3]; ind = 0; System.out.println("W/B"); for(int i=0;i<dimx;i++) { for(int j=0;j<dimy;j++) { Image[ind] = I.get_image(i,j); Image[ind+1] = Image[ind+2] = Image[ind]; ind = ind + 3; } } } Textura(String s,int type) { int ind; R = new Imagemrgb(s); dimx = 512; dimy = 512; depth = 3; rx = R.get_dimx(); ry = R.get_dimx(); Image = new byte[dimx*dimy*3]; ind = 0; System.out.println("Color"); for(int i=0;i<dimx;i++) { for(int j=0;j<dimy;j++) { for(int k=0;k<3;k++) { Image[ind] = R.get_image(i,j,k); ind = ind + 1; } } } } public void set_Drawable(GLDrawable drawable) { draw = drawable; 55 } public void texture_on() { GL gl = draw.getGL(); gl.glEnable(GL.GL_TEXTURE_2D); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_DECAL); // GL_GL_BLEND , GL_REPLACE, GL_MODULATE gl.glBindTexture(GL.GL_TEXTURE_2D, texName[0]); } public void texture_off() { GL gl = draw.getGL(); gl.glDisable(GL.GL_TEXTURE_2D); } public void init() { GL gl = draw.getGL(); gl.glClearColor (0, 0, 0, 0); gl.glShadeModel(GL.GL_SMOOTH); gl.glEnable(GL.GL_DEPTH_TEST); gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); gl.glGenTextures(1, texName); gl.glBindTexture(GL.GL_TEXTURE_2D, texName[0]); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); //GL_CLAMP gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,GL.GL_LINEAR); //GL.GL_NEAREST gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,GL.GL_LINEAR); gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, dimx,dimy, 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,Image); } } 56