• Nenhum resultado encontrado

Computação Gráfica Walderson Shimokawa 19

N/A
N/A
Protected

Academic year: 2021

Share "Computação Gráfica Walderson Shimokawa 19"

Copied!
12
0
0

Texto

(1)

uma abordagem matemática, que serão utilizados com frequência nos próximos capítulos. Após a apresentação geral, alguns algoritmos úteis serão apresentados para serem usados posteriormente. Nos capítulos 6 e 7 trataremos de polígonos que sejam faces de objetos 3D sólidos. Como polígonos de modo geral são difíceis de serem manipulados, será melhor dividirmos em triângulos, conforme será apresentado da última seção deste capítulo.

2.1 Vetores

Começaremos com a noção matemática de vetor, que não deve ser confundido com a classe-padrão Vector, disponível em Java, para armazenar um número arbitrário de objetos. Um vetor é um segmento de reta orientado, caracterizado apenas pelo seu comprimento e por sua direção. A Figura 9 mostra duas representações do mesmo vetor u = PQ = v = RS. Assim, assim um vetor não é alterado por sua translação.

Figura 9: Dois vetores iguais

A soma dos w vetores u e v, escrita w = u + v

pode ser obtida como a diagonal de um paralelogramo com u, v e w começando no mesmo ponto, conforme mostrado na figura 10.

Figura 10: Adição de vetores

A Figura 11 mostra três vetores unitários i, j e k em um espaço tridimensional. Eles são mutuamente perpendiculares e têm comprimento igual a 1 (um). Suas direções são as direções positivas dos eixos de coordenadas. Dizemos que i, j e k formam um terno de vetores unitários ortogonais. Muitas vezes escolhemos a origem O do sistema de coordenadas como o ponto inicial de todos os vetores. Qualquer vetor v pode ser escrito como uma combinação linear dos vetores unitários i, j e k:

v = xi + yj + zk

Os números reais x, y e z são as coordenadas da extremidade P do vetor v = OP. Muitas vezes escrevemos esse vetor como

v = [ x y z ] ou v = (x,y,z)

(2)

Figura 11: Sistema de coordenadas com orientação positiva

2.2 Produto Interno

O produto interno ou produto escalar de dois vetores a e b é um número real, escrito como a  b e definido como

a  b = |a||b| cos  se a ≠ 0 e b ≠ 0 a  b = 0 se a = 0 ou b = 0

em que  é o ângulo entre a e b. Resulta da primeira equação que a  b também é zero se  = 90. Aplicando-se essa definição aos vetores unitários i, j e k, encontramos

i  i = j  j = k  k = 1

i  j = j  i = j  k = k  j = k  i = i  k = 0

O produto interno de dois vetores u = [u1 u2 u3] e v = [v1 v2 v3] pode ser calculado como u  v = u1v1 + u2v2 + u3v3

2.3 Determinantes

Antes de prosseguirmos produtos de vetores, devemos dar atenção aos determinantes. Suponha que queiramos resolver o seguinte sistema de duas equações lineares para x e y:

Podemos então multiplicar a primeira equação por b2, a segunda por –b1, e adicioná-las, isolando x e y, encontrando (se (a1b2 – a2b1) ≠ 0):

Usando determinantes, podemos escrever a solução da equação como:

(3)

Determinantes são muito úteis em álgebra linear e geometria analítica. Eles têm muitas propriedades interessantes, algumas das quais são listadas a seguir:

1. O valor de um determinante permanece o mesmo se suas linhas forem escritas como colunas na mesma ordem;

2. Se duas linhas (ou colunas) forem intercambiadas, o valor do determinante é multiplicado por -1; 3. Se uma linha ou coluna for multiplicada por um fator, o valor do determinante é multiplicado por

este fator;

4. Se uma linha for alterada pela adição de uma outra linha multiplicada por uma constante, o valor do determinante permanece inalterado;

5. Se uma linha (ou uma coluna) for uma combinação linear de outras linhas (ou colunas), o valor do determinante é zero.

2.4 Produto Vetorial

O produto vetorial ou produto cruzado de dois vetores u e v é escrito u X v

e é um vetor w com as seguintes propriedades. Se u = cv para algum escalar c, então w = 0. Caso contrário, o comprimento de w é igual a:

|w| = |u||v| sen 

em que  é o ângulo entre u e v. Observe que o comprimento de |w| é igual á área de um paralelogramo que tenha como lados os vetores u e v, como a Figura 12 mostra:

Figura 12: Produto vetorial u X v

(4)

Usando esses produtos vetoriais na expansão de:

que pode ser escrito como:

Reescrevemos isso em uma forma que é mais fácil de lembrar:

Esse é um auxílio mnemônico, e não é um verdadeiro determinante, já que os elementos da primeira linha são vetores em vez de números.

2.5 A Orientação de Três Pontos

Suponha que tenhamos recebido um termo ordenado (A, B, C) de três pontos no plano xy e que queiramos saber sua orientação; em outras palavras, queremos saber se giramos no sentido anti-horário ou horário ao visitar esses pontos na ordem dada. A figura 13 mostra as possibilidades, às quais também nos referimos como orientação positiva e negativa, respectivamente.

Figura 13: Orientação anti-horária (orientação > 0) e horária de (orientação < 0) A, B, C

Existe a necessidade de se conhecer um modo de descobrir a orientação por meio de cálculos, usando apenas as coordenadas xA, yA, xB, yB, xC e yC. Definiremos dois vetores a = CA e b = CB, conforme mostra a figura 14.

(5)

Figura 14: Usando os vetores a e b em vez dos lados CA e CB

a = a1i + a2j + 0k b = b1i + b2j + 0k

De modo geral, temos

> 0 = 0 < 0 2.5.1 Um Método Java Útil

O método area2 no fragmento a seguir é baseado nos resultados encontrados. Esse método recebe três argumentos da classe Point2D, apresentado no final do Capítulo 1. Usaremos a classe Tools2D para diversos métodos estáticos a serem usados como ferramentas bidimensionais.

class Tools2D {

static float area2(Point2D a, Point2D b, Point2D c) {

return (a.x – c.x) * (b.y – c.y) - (a.y – c.y) * (b.x – c.x); }

//Veja a seção 2.13 }

Esse método calcula a área do triângulo ABC multiplicado por 2, ou, se, A, B e C estiverem orientados no sentido horário, por -2. Se estivermos interessados apenas na orientação dos pontos A, B e C, cada um do tipo Point2D, podemos escrever:

if (Tools2D.area2(a, b, c) > 0) { //A, B e C no sentido anti-horário }

else

{ //A, B e C no sentido horário, a menos que area2 retorne 0 (zero); //neste caso, A, B e C pertencem à mesma reta

}

2.6 Polígonos

Um polígono é uma sequência P0, P1, ..., Pn-1 de vértices, em que n ≥ 3, com lados associados P0P1, P1P2, ..., Pn-1P0. Neste curso nos restringiremos a polígonos simples, em que os lados não adjacentes não tem intersecção.

Se todos os vértices de um polígono forem convexos, diz-se que o próprio polígono é convexo. Vértices não convexos são chamados de reflexos. Se um polígono possuir pelo menos um vértice reflexo, diz-se que o polígono é côncavo. Veja a Figura 15 que exemplifica os polígonos convexo e côncavo.

: orientação de A,B e C positiva (sentido anti-horário) : A, B e C na mesma reta

(6)

Figura 15: Polígonos convexo e côncavo

O seguinte método pode ser definido em uma classe para desenhar polígonos (seção 2.13, classe

PolyTria), para se identificar se um dado polígono, expresso em coordenadas de pontos usando a classe Point2D está desenhado no sentido anti-horário:

static boolean ccw(Point2D[] p) { int n = p.length, k = 0; for (int i=1; i<n; i++)

if (p[i].x <= p[k].x && (p[i].x < p[k].x || p[i].y < p[k].y)) k = i;

// p[k] é um vértice convexo. int prev = k - 1, next = k + 1; if (prev == -1) prev = n - 1; if (next == n) next = 0;

return Tools2D.area2(p[prev], p[k], p[next]) > 0; }

2.7 A Área de Um Polígono

Como vimos na Figura 12, o produto vetorial a X b é um vetor cujo comprimento é igual à área de um paralelogramo do qual a e b sejam dois lados. Como esse paralelogramo é de dois triângulos de área igual, segue-se para Figura 14, obtendo:

Se A, B e C está no sentido anti-horário e :

Que pode ser generalizada para obter a área de um polígono obtendo a fórmula (P0 e Pn no mesmo vértice):

2.8 Teste Ponto-no-Triângulo

Determinar a orientação de três pontos como acabamos de ver é útil em um teste para ver se um determinado ponto P está localizado dentro de um triângulo ABC. Como a Figura 16 mostra, esse é o caso se a orientação dos triângulos ABP, BCP e CAP for a mesma do triângulo ABC.

(7)

Figura 16: Orientação usada para testar se P está dentro do triângulo ABC

Sabendo-se que a orientação de ABC é no sentido anti-horário. Podemos chamar o seguinte método para testar se P está dentro do triângulo ABC (ou em um de seus lados):

static boolean insideTriangle(Point2D a, Point2D b, Point2D c, Point2D p) { //Admite-se que ABC tem sentido anti-horário

return Tools2D.area2(a, b, p) >= 0 && Tools2D.area2(b, c, p) >= 0 && Tools2D.area2(c, a, p) >= 0; }

2.9 Teste de Ponto-no-Polígono

A noção de orientação também é útil também quando precisamos determinar se um dado ponto P está localizado dentro de um polígono. Será então conveniente se houver um método disponível que receba como argumentos o polígono em questão e o ponto P, e retorne verdadeiro se P estiver dentro e

falso se estiver fora do polígono. Cruzando o polígono desde o ponto P para a direita podemos dizer se

estamos dentro ou fora do polígono: se quantidade de intersecções for par, estamos fora; se for ímpar, estamos dentro. Veja a Figura 17 para exemplificar este cálculo.

Figura 17: Determinando se um ponto está dentro ou fora do polígono

Devemos ter cuidado com alguns casos especiais, como mostra a figura 18:

(8)

Tools2D.area2(pol[j], pol[i], p) > 0 && pol[i].y <= y && y < pol[j].y &&

Tools2D.area2(pol[i], pol[j], p) > 0) b = !b; j = i; } return b; }

2.10 Teste Ponto-na-Reta

Testar se um ponto P está localizado em uma determinada reta é muito simples se essa reta for dada como uma equação, digamos,

ax + by = h

Então tudo o que precisamos fazer é testar se as coordenadas de P satisfazem esta equação (eps é o épsilon, que indica um pequeno intervalo real aceitável de margem de erro a ser tolerado):

if (Math.abs(Tools2D.area2(a, b, p)) < eps) //P pertence à reta AB

2.10.1 Testando se um Ponto Pertence a um Segmento de Reta

Em vez de testar se P pertence ao segmento AB, podemos querer aplicar um teste semelhante na projeção P’ de P sobre AB, como a Figura 19 mostra.

Figura 19: Projeção de P’ de P sobre a reta AB entre A e B

2.11 Distância Entre um Ponto e uma Reta

Podemos descobrir a distância entre um ponto P e uma reta r de diferentes formas, dependendo da maneira pela qual a reta é especificada. Então as propriedades e fórmulas geométricas podem ser aplicadas para se descobrir as distâncias entre um ponto e uma reta.

2.12 Projeção de um Ponto em uma Reta

Suponha que uma reta r e um ponto P (não sobre r) sejam dados e que queiramos calcular a projeção P’ sobre r (conforme Figura 19). Este ponto P’ possui três propriedades interessantes:

(9)

Em muitas aplicações gráficas é desejável dividir um polígono em triângulos. Esse problema pode ser resolvido de diversas formas. Discutiremos um algoritmo comparativamente simples, que recebe um polígono na forma de um vetor de elementos da classe Point2D, contendo os vértices do polígono em sentido anti-horário. O método triangulate apresentado recebe tal vetor como argumento. Para armazenar os triângulos resultantes, ele também recebe, como segundo argumento, um vetor de elementos da classe

Triangle, que é definida da seguinte forma:

class Triangle {

Point2D a, b, c;

Triangle(Point2D a, Point2D b, Point2D c) { this.a = a; this.b = b; this.c = c; } }

Se um dado polígono tiver n vértices, o vetor de triângulos deve ter comprimento n – 2. O algoritmo funciona da seguinte maneira: percorrendo os vértices do polígono no sentido anti-horário, para cada vértice P, Q e R sucessivos dos quais Q seja um vértice convexo (com ângulo menor que 180), removemos o triângulo PQR do polígono se esse triângulo não contiver algum dos outros vértices do polígono. Por exemplo, começando com o polígono ABCDE da Figura 20, não podemos remover o triângulo ABC, porque contém o vértice D. O triângulo CDE também não é um bom candidato, porque D não é um vértice convexo. Esses problemas não existem no triângulo BCD, de forma que o removeremos, reduzindo o polígono ABCDE ao mais simples, ABDE.

Figura 20: Removendo um triângulo

Para isto, usamos o método estático triangulate, que, junto com alguns outros já discutidos, é listado na classe Tools2D a seguir:

class Tools2D

{ static float area2(Point2D a, Point2D b, Point2D c)

{ return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x); }

static boolean insideTriangle(Point2D a, Point2D b, Point2D c, Point2D p) // Admite-se que ABC tem sentido anti-horário { return

Tools2D.area2(a, b, p) >= 0 && Tools2D.area2(b, c, p) >= 0 && Tools2D.area2(c, a, p) >= 0;

(10)

j = i; }

return b; }

static void triangulate(Point2D[] p, Triangle[] tr)

{ // p contém todos os n vértices do polígono no sentido anti-horário // Os triângulos resultantes serão armazenados em um array tr. // O array tr tem comprimento n - 2.

int n = p.length, j = n - 1, iA=0, iB, iC; int[] next = new int[n];

for (int i=0; i<n; i++) { next[j] = i;

j = i; }

for (int k=0; k<n-2; k++)

{ // Encontre um triângulo apropriado, que consista em // dois lados e uma diagonal interna:

Point2D a, b, c;

boolean triaFound = false; int count = 0;

while (!triaFound && ++count < n) { iB = next[iA]; iC = next[iB]; a = p[iA]; b = p[iB]; c = p[iC]; if (Tools2D.area2(a, b, c) >= 0) { // Lados AB e BC; diagonal AC.

// Teste para ver se nenhum outro vértice de polígono // está localizado dentro do triângulo ABC:

j = next[iC];

while (j != iA && !insideTriangle(a, b, c, p[j])) j = next[j];

if (j == iA)

{ // O triângulo ABC não contém outro vértice: tr[k] = new Triangle(a, b, c); next[iA] = iC; triaFound = true; } } iA = next[iA]; } if (count == n)

{ System.out.println("Não é um polígono simples" +

" ou a sequência de vértices não tem sentido anti-horário."); System.exit(1);

} } }

static float distance2(Point2D p, Point2D q) { float dx = p.x - q.x,

dy = p.y - q.y; return dx * dx + dy * dy; }

(11)

quadrados para economizar a operação bastante custosa do cálculo de raízes quadradas.

O programa a seguir permite ao usuário definir um polígono, da mesma forma que fizemos no programa DefPoly.java na seção 1.5, mas dessa vez o polígono será dividido em triângulos, os quais aparecem em diferentes cores. Esse programa, PolyTria.java, usa as classes Triangle e Tools2D desta seção, assim como a classe CvDefPoly, que se encontra no programa DefPoly.java da seção 1.5. Na nossa subclasse, CvPolyTria, aplicamos o método ccw, discutido na seção 2.6, ao polígono dado para examinar a orientação de sua sequência de vértices. Se ela for no sentido horário, colocamos os vértices em ordem reversa no vetor P, de modo que a sequência de vértices terá o sentido anti-horário nesse vetor, que pode então ser passado com segurança para o método triangulate:

import java.awt.*;

import java.awt.event.*; import java.util.*;

public class PolyTria extends Frame

{ public static void main(String[] args){new PolyTria();}

PolyTria()

{ super("Clique para definir os vértices do polígono"); addWindowListener(new WindowAdapter()

{public void windowClosing(WindowEvent e){System.exit(0);}}); setSize(500, 300);

add("Center", new CvPolyTria());

setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); show();

} }

class CvPolyTria extends CvDefPoly // veja seção 1.5 { public void paint(Graphics g)

{ int n = v.size(); if (n > 3 && ready)

{ Point2D[] p = new Point2D[n];

for (int i=0; i<n; i++) p[i] = (Point2D)v.elementAt(i); // Se não possuir sentido anti-horário, reverta a ordem: if (!ccw(p))

for (int i=0; i<n; i++)

p[i] = (Point2D)v.elementAt(n - i - 1); int ntr = n - 2;

Triangle[] tr = new Triangle[ntr]; Tools2D.triangulate(p, tr);

initgr();

for (int j=0; j<ntr; j++)

{ g.setColor(new Color(rand(), rand(), rand())); int[] x = new int[3], y = new int[3];

x[0] = iX(tr[j].a.x); y[0] = iY(tr[j].a.y); x[1] = iX(tr[j].b.x); y[1] = iY(tr[j].b.y); x[2] = iX(tr[j].c.x); y[2] = iY(tr[j].c.y); g.fillPolygon(x, y, 3); } } g.setColor(Color.black); super.paint(g); }

(12)

return Tools2D.area2(p[prev], p[k], p[next]) > 0; }

}

A classe CvPolyTria é uma subclasse de CvDefPoly, de forma que a construção de um polígono com vértices especificados pelo usuário é feita da mesma forma que na seção 1.5. Nessa subclasse, chamamos o método triangulate para construir um vetor tr de triângulos. Esses são então exibidos em cores geradas com um gerador de números aleatórios, de maneira que possamos distingui-los claramente. O resultado na tela ficará parecido com a apresentado na Figura 21.

Referências

Documentos relacionados

DATA: 17/out PERÍODO: MATUTINO ( ) VESPERTINO ( X ) NOTURNO ( ) LOCAL: Bloco XXIB - sala 11. Horário Nº Trabalho Título do trabalho

- Se o estagiário, ou alguém com contacto direto, tiver sintomas sugestivos de infeção respiratória (febre, tosse, expetoração e/ou falta de ar) NÃO DEVE frequentar

O pressuposto teórico à desconstrução da paisagem, no caso da cidade de Altinópolis, define que os exemplares para essa análise, quer sejam eles materiais e/ou imateriais,

Feitiço do Segredo: deposita um segredo numa pessoa de confiança, essa pessoa fica deposita um segredo numa pessoa de confiança, essa pessoa fica sendo o &#34;Fiel do sendo o

- Remover as pastilhas usadas e retornar todo o parafuso de regulagem em seguida montar uma pastilha nova do lado da roda, empurrando com a mão a pinça no sentido do cilindro de

Lernaea cyprinacea of Steindachnerina insculpta from Taquari River, municipality of Taquarituba, São Paulo State, Brazil.. Note the hemorrhagic area around the insertion point of

Contribuições/Originalidade: A identificação dos atributos que conferem qualidade ao projeto habitacional e das diretrizes de projeto que visam alcançá-los, são de fundamental

• Capacitação e Transferência da metodologia do Sistema ISOR ® para atividades de Coaching e/ou Mentoring utilizando o método das 8 sessões;.. • Capacitação e Transferência