• Nenhum resultado encontrado

Controle das peças da AduboGL

3.3 IMPLEMENTAÇÃO

3.3.1.1 Controle das peças da AduboGL

A parte fundamental da AduboGL é formada por peças que representam uma forma gráfica ou um comando importante da OpenGL para realizar uma interação no espaço 3D que será gerado pela junção das peças.

Antes de iniciar a modelagem das peças a partir das primitivas gráficas da OpenGL foram feitos croquis de seu formato. Os formatos foram estudados para que pudesse ser iniciado um trabalho com as formas mais simples de serem modeladas, mas também para que pudessem ser alteradas posteriormente. As peças futuras foram modeladas no Corel Draw e gravadas no formato PNG, porém não se obteve tempo para substituir as iniciais no presente

trabalho. Os croquis das peças, assim como o resultado das peças finais em PNG podem ser

vistos no Apêndice B.

Primeiro trabalhou-se com dois tipos de peças. As peças podem ser observadas na Figura 13 e são utilizadas para representar o desenho de um cubo e representar os comandos

glPushMatrix() glPopMatrix()(ver seção 2.2.4), respectivamente. As peças foram

desenhadas para permitir seu encaixe, gerando assim peças filhas. Isso porque ao aplicar uma transformação em um cubo e colocá-lo entre um comando glPushMatrix() glPopMatrix()

a transformação passa a ser unicamente das peças dentro do bloco. Já se a peça a sofrer a transformação estiver fora dos comandos, ao transformá-la, transformará as demais peças fora do bloco.

45

Figura 13 – Peças glPushMatrix(), glPopMatrix() e cubo

Para as transformações, foram criadas três novas peças semelhantes à peça correspondente ao cubo, porém de outra cor para distingui-las. A peça correspondente a translação foi desenhada na cor marrom, a correspondente a rotação em um tom verde musgo e a escala em um tom de roxo. Não foram escolhidas as cores bases do RGB, pois por ter a mesma forma que o cubo, ao alterar a cor dele, essas peças seriam confundidas. Além da cor, é apresentada a letra inicial da transformação ao lado da peça, para que o usuário possa entender qual seu significado. As peças podem ser vistas na Figura 14.

Figura 14 – Peças que representam as transformações

As peças podem pertencer à fábrica, à bandeja do exercício ou ainda, quando não for do tipo glPushMatrix() glPopMatrix(), podem ser filha de uma peça do tipo glPushMatrix()glPopMatrix() que está na bandeja. A classe para a peça é a mesma para

os cinco tipos, denominada objetoGraficoExercicio, o que as diferencia é o local onde a

mesma está adicionada na classe Principal e suas características como cor e tipo.

Na classe Principal existem dois vetores. O primeiro armazena todas as peças

representadas na fábrica e o segundo possui aquelas peças que já foram colocadas na bandeja, na ordem em que estão posicionadas na tela. Por sua vez, cada peça do exercício tem um vetor de objetos para armazenar os seus filhos. Os vetores presentes na AduboGL podem ser observados no Quadro 21. Nota-se uma semelhança com o grafo de cena (ver seção 2.3), pois é uma estrutura onde acontece a relação entre pai e filho. Dessa forma, ao aplicar uma transformação no objeto antecessor, essa é repassada para todos os seus sucessores. Por outro lado, se a transformação for aplicada no sucessor, não interferirá na peça antecessora.

46

Quadro 21 – Estrutura das peças na AduboGL

Para que a peça da fábrica possa ser levada para a bandeja e as peças da bandeja possam ser arrastadas, desenvolveu-se uma rotina que retorna o identificador da peça clicada. Sempre que é clicada em uma parte da tela correspondente a fábrica ou a bandeja é chamada uma função que percorre cada uma das três listas da AduboGL. Então é verificado se foi clicado dentro da peça a partir dos pontos de sua BoundingBox. Se com a análise percebe-se

que foi clicado dentro da BoundingBox é passado o algoritmo da ScanLine para verificar se o

ponto clicado está também dentro da peça (a análise da BoundingBox e do algoritmo da

ScanLine pode ser observado na Figura 15).

Figura 15 – Análise do clique sobre uma peça

O algoritmo da ScanLine verifica se os segmentos de reta do objeto se interseccionam com a reta da ScanLine. Para cada ponto de intersecção é somado 1 a uma variável que foi iniciada com 0. Se a soma for par é porque foi clicado fora do objeto e se for ímpar foi clicado dentro. Isso é necessário porque existe a peça correspondente ao glPushMatrix()

47

glPopMatrix() que é uma peça côncava. Por fim é retornado o id da peça selecionada ou -1

caso não tenha sido clicado em alguma peça. Sabe-se que é uma peça da fábrica quando o id

retornado for menor do que 10, pois foi o número estipulado de elementos para ela, e, se for maior, é porque foi um objeto da bandeja, podendo ser filho de outra peça. O trecho de código que realiza a varredura das peças colocadas na bandeja e na fábrica e chama as funções para verificar a BoundingBox e a ScanLine pode ser analisado no Quadro 22.

GLint getIdPecaClicada(int x, int y)

{

GLint indice = -1;

const Point4D mousePto(x,y,0);

for (int i = 1; i < MAX_GABARITO; i++) {

if(listaFabrica[i] != NULL) {

if (listaFabrica[i]->GetBoundingBox()->testPoint(mousePto)) {

//scanline:

const Point4D p = *new Point4D(x, y, 0);

bool s = listaFabrica[i]->PontoNoObjeto(p, listaFabrica[i]);

if (s) { return listaFabrica[i]->GetId(); } } } else { break; } }

for (int i = MAX_GABARITO; i < 255; i++) {

if(listaBandeja[i] != NULL) {

if (listaBandeja[i]->GetBoundingBox()->testPoint(mousePto)) {

//scanline:

bool s = listaBandeja[i]->PontoNoObjeto(mousePto, listaBandeja[i]);

if (s) {

return listaBandeja[i]->GetId();

}

for (int j = 0; j < listaBandeja[i]->GetQuantidade(); j++) {

ObjetoGraficoExercicio *filho = static_cast<ObjetoGraficoExercicio*>( listaBandeja[i]->GetFilho(j)); if (filho != NULL) { if (filho->GetBoundingBox()->testPoint(mousePto)) { //scanline: s = filho->PontoNoObjeto(mousePto, filho); if (s) { return filho->GetId();

} // senão está fora da boudingbox

} }

// ...código...

return indice;

}

Quadro 22 - Trecho de código que retorna identificador da peça clicada

Quando é adicionada a primeira peça na bandeja, essa, por sua vez, é adicionada no vetor de peças da bandeja na posição correspondente ao seu índice, lembrando que esse vetor possui as primeiras posições reservadas, pois elas identificam os índices das peças da fábrica.

48

Tem-se assim o id da peça correspondente ao índice da posição em que ela está adicionada no

vetor. Desse modo, para capturar a peça clicada do exercício, também é trabalhado o identificador em conjunto com a posição do vetor. No Quadro 23 podem-se notar as posições que são ocupadas no vetor da bandeja e sua relação com o identificador da peça. É possível alocar no máximo 255 peças no vetor, o valor correspondente a um byte, pois não se achou

necessária a criação de mais peças em um mesmo exercício.

Quadro 23 – Representação do vetor do exercício com relação ao id da peça

Na classe principal, quando o botão do mouse é solto é validada a posição em que a peça é solta. De acordo com o estado da peça definido pela posição em que ela é colocada acontecerá uma ação a ela (Figura 12). Se a peça for colocada dentro da fábrica a peça é apagada e removida do exercício. Se for colocada abaixo de todas, esta é reposicionada abaixo da última peça já colocada na bandeja. Isso ocorre tanto para uma nova peça quanto para uma já existente na bandeja. Esse processo pode ser analisado na Figura 16. Para realizar o procedimento é calculada a altura das peças já colocadas e então a peça é transladada com base nos valores em y e x deslocados. O trecho de código correspondente ao reposicionamento da peça solta pode ser visto no Quadro 24.

49

void pecas2D_mouse(int button, int state, int x, int y)

{ //...código...

if (xTrans > sub_largura || yTrans <= alturaLinha) { //dentro da fábrica

atualizaAlturaPecas();

} else if (yTrans > alturaY) {//abaixo das outras peças, coloca para cima

if (!pecaexercicio) { //peça nova – veio da fábrica

GLfloat difX = xTrans - pontoAlto.GetX() + espacoBorda; GLfloat difY = yTrans - alturaY;

transAux.MakeTranslation(Point4D(-difX, -difY, 0)); clicado->SetMatrizTransformacao(transAux *

clicado->GetMatrizTransformacao()); alturaY += (pontoBaixo.GetY() - pontoAlto.GetY());

} else {

//É peça da bandeja que foi colocada para baixo, atualiza a posição de

//todas as demais, e adiciona ela ao fim de tudo! ObjetoGraficoExercicio *objAlterado = clicado; atualizaAlturaPecas();

objAlterado->SetId(idPecaExercicio);

GLfloat difX = xTrans - pontoAlto.GetX() + espacoBorda; GLfloat difY = yTrans - alturaY;

transAux.MakeTranslation(Point4D(-difX, -difY, 0)); objAlterado->SetMatrizTransformacao(transAux *

objAlterado->GetMatrizTransformacao()); alturaY += (pontoBaixo.GetY() - pontoAlto.GetY());

listaBandeja[idPecaExercicio] = objAlterado; idPecaExercicio++; } } //...código... }

Quadro 24 – Trecho de código correspondente ao reposicionamento da peça colocada

Se a peça foi criada e colocada no exercício ao lado das demais, ou seja, em uma linha horizontal, é feita a validação para ver se é uma peça filha e então é removida da lista de exercício e adicionada na lista de filhas da peça. A adição do filho pode ser analisado no Quadro 25.

void pecas2D_mouse(int button, int state, int x, int y)

{ //...código... if (idPecaFilho > idPecaExercicio) { clicado->SetId(idPecaFilho); idPecaFilho--; } if (!cima) obj->AdicionaFilho(clicado); else obj->InserirPrimeiraPosicaoFilho(clicado); //...código... }

Quadro 25 – Inserção de peça filha a uma peça do exercício

Quando uma peça é adicionada como filha de outra, é realizado um cálculo para descobrir qual será sua peça antecessora. Para isso a lista é percorrida até ser encontrada a peça que está ao lado da posicionada. Ao pegar a futura antecessora, é calculada a altura da peça e sua largura para então realizar o encaixe. Esse cálculo é feito a partir dos pontos da

50

peça capturados da lista de pontos. Então, a peça filha é colocada no ponto de origem e em seguida ela é transladada conforme a largura da peça pai e sua altura em relação ao cenário. Esse processo pode ser verificado na Figura 17.

Se a peça antecessora já possuir peças filhas, ela também é modificada. Nesse caso, é calculada também a altura da peça sucessora, para ser acrescentada na altura da peça pai. Essa altura calculada é acrescentada em cada y dos vértices da parte inferior da peça pai. Assim a

peça fica maior e permite o encaixe do próximo filho. Para o próximo filho também é acrescida sua altura na translação em y. O filho pode ser inserido na primeira posição, se a

peça estiver no início da antecessora, ou na última posição. Essa interação pode ser analisada na Figura 18.

51

Figura 18 – Deslocamento das peças para mais de um filho

Se uma peça que já está na bandeja for colocada ao lado de outra peça da bandeja, a primeira é inserida a cima ou abaixo da segunda peça conforme a posição colocada. Para encontrar a peça horizontal é feito o mesmo cálculo realizado para encontrar a peça pai de uma filha. Ao inserir uma peça acima de outra, a peça que está embaixo será transladada em y

a altura da peça que foi adicionada a cima. Isso ocorrerá para todas as peças abaixo da peça transladada.

Documentos relacionados