[Trabalho 2] Quadro animado por meio de uma interface


Agora o quadro de Geraldo de barros terá uma nova forma, que pode ser controlada pelo usuário a partir da interface gráfica do controlP5 para o Processing P3, além de poder ter sua imagem salva em diferentes formatos
ao se pressionar uma tecla.

Link de acesso ao arquivo .pde no Google Drive.

Código completo:


//PRIMEIRA ABA


/*             QUADRO ANIMADO A PARTIR DE UMA INTERFACE CONTROLP5

  - Pelo menos dois parâmetros sendo alterados, por elemento de interface:
        alterar a posição, "inverter" o quadro, mantendo as proporções
        escolher as cores que o formam
        alterar o tamanho do quadro sem perder as proporções
  
 - Salva a imagem em formatos diferentes e cria um arquivo de texto com informações
 Na hora que o usuário desejar

 - Armazena informações sobre o arquivo através da classe
 Deve: criar um arquivo de texto com data, copyright simples e formato da imagem    */
//___________________________________________________________________________________

//Importação da biblioteca para o Processing
import controlP5.*;

//Criação de nova instância do tipo ControlP5
ControlP5 cp5;

//Definirá o tamanho do quadro
Slider tam;
//Definirá as posições dos elementos
Slider move;

//Definirão as cores do quadro
Slider red;
Slider gre;
Slider blu;

int cont = 0; //Contador para o salvamento de imgs e textos


void setup(){
 
   size(900,563);
 
   cp5 = new ControlP5(this);

 
 //Definições dos sliders que alterarão os elementos do quadro:

 //Tamanho do quadro:  
   tam = cp5.addSlider("tamanho");
     tam.setRange(200,563) /*O tamanho mínimo do quadro será 200, enquanto o máximo será 563*/
        .setValue(563) /*O quadro iniciará no tamanho máximo*/
        .setPosition(590,210)
        .setSize(200,20);
 
//Cores:
   red = cp5.addSlider("R");
     red.setRange(0, 255)
       .setValue(0)
       .setPosition(590, 140)
       .setSize(200, 20);
      
   gre = cp5.addSlider("G");
     gre.setRange(0, 255)
       .setValue(0)
       .setPosition(590, 160)
       .setSize(200, 20);
      
   blu = cp5.addSlider("B");
     blu.setRange(0, 255)
       .setValue(0)
       .setPosition(590, 180)
       .setSize(200, 20);
      
      
   //Posicionamento:
   move = cp5.addSlider("inverte");
     move.setRange( 1, (tam.getValue()/2) )  /*Os pontos X dos quadriláteros tem o limite máximo de metade do tamanho do quadro para se moverem*/
       .setValue(1)
       .setPosition(590, 100)
       .setSize(200, 20);
}


void draw (){
 
    background (100); 
   
    Quadro();


      //Instruções ao usuário
     
      String titulo = "Altere o que quiser.";
      textSize(20);
      fill(200);
      text(titulo, 580, 30);
     
      //Instruções ao usuário após ele alterar algum elemento, em seus mínimos
     
      if (move.getValue() > 1 || red.getValue()>=17 || gre.getValue()>=21 || blu.getValue()>=28 ||tam.getValue()<563){
      String mensagem1 = "Que bonito!";
      String mensagem2 = "Geraldo de Barros estaria orgulhoso de você.";
      String mensagem3 = "Para salvar em .PNG, tecle 'p'";
      String mensagem4 = "Para salvar em .TIFF, tecle 't'";
      String mensagem5 = "Para salvar em .JPEG, tecle 'j'";
      textSize(14);
      fill(200);
      text(mensagem1, 580, 450);
      text(mensagem2, 580, 470);
      fill(255);
      text(mensagem3,580,510);
      text(mensagem4,580,530);
      text(mensagem5,580,550);
      }

}



void keyPressed() {

/*
- Cada tecla salva o frame em um formato de imagem diferente

- Cada uma das condições realiza funções semelhantes, com a mudança mínima do
formato de imagem.

- Temos uma variável contadora que é incrementada a cada vez que se pressiona
uma tecla, para não haver sobreescrita e perda de arquivos.

- A variável contadora torna mais fácil a manipulação dos nomes dos arquivos
de texto e imagem do que a contagem de número de frames

- Cria-se o novo objeto da classe ArquivoInfo a cada vez que uma das teclas
é pressioada, e tem como atributos o nome dos arquivos de texto, imagem e seu
formato.

- Cria-se as strings necessárias para o arquivo de texto na classe ArquivoInfo

- Utiliza-se o método de retornar detalhes da classe Arquivo Info (info.retornaDet())
para executá-lo na função saveStrings() e adicionar ao arquivo de texto todas as informações
necessárias de data, copyright, nome da imagem e seu formato.*/

  if(key == 'p'){
    String nomeImg = "designDeAzulejosImg"+cont;
    String nometxt = "designDeAzulejosTxt"+cont;
    String formato = "PNG";
    ArquivoInfo info = new ArquivoInfo(nomeImg,nometxt,formato);
    saveFrame(nomeImg+".png");
    saveStrings(nometxt+".txt",info.retornaDet());
    cont++;
  }
 
  if(key == 't'){
    String nomeImg = "designDeAzulejosImg"+cont;
    String nometxt = "designDeAzulejosTxt"+cont;
    String formato = "TIFF";
    ArquivoInfo info = new ArquivoInfo(nomeImg,nometxt,formato);
    saveFrame(nomeImg+".tif");
    saveStrings(nometxt+".txt",info.retornaDet());
    cont++;
  }
 
  if(key == 'j'){
    String nomeImg = "designDeAzulejosImg"+cont;
    String nometxt = "designDeAzulejosTxt"+cont;
    String formato = "JPEG";
    ArquivoInfo info = new ArquivoInfo(nomeImg,nometxt,formato);
    saveFrame(nomeImg+".jpg");
    saveStrings(nometxt+".txt",info.retornaDet());
    cont++;
  }
 
}
//___________________________________________________________________________
//SEGUNDA ABA

/*A classe ArquivoInfo cria objetos que conterão as informações necessárias para
o arquivo de texto, criado juntamente com as imagens

Recebe como atributos o nome da imagem, seu formato e o nome do arquivo de texto.

Adiciona informações de dia, mês e ano de criação, além de um copyright

Reúne as Strings de informação num vetor de strings no método de retornar detalhes ( retornaDet() )

Esse método retorna as strings ao código principal ao ser chamado por meio do objeto (info), ao
ser pressionada alguma tecla*/

class ArquivoInfo{

//strings locais com o mesmo nome das strings do código principal
String imgNome;
String txtNome;
String formato;

ArquivoInfo(String imgNome, String txtNome, String formato){

/*Inicializa-se as variáveis da classe pelo construtor, equivalendo seus valores
aos valores presentes nas strings do código principal*/

this.imgNome = imgNome; 
this.txtNome = txtNome;
this.formato = formato;
}

String [] retornaDet (){
 
//Adiciona-se os "det"alhes presentes no arquivo de texto 
String detimagem = "Nome da imagem: " + imgNome + "\n";
String detformato = "De formato: "+formato+"\n";
String detTxt = "Nome do arquivo de texto: "+ txtNome + "\n";
String copyR = "O quadro original pertence a Geraldo de Barros, mas você agora pode dizer que virou um designer de Azulejos.\n";

int d = day();
int m = month();
int y = year();
int h = hour();
int min = minute();

String data = "criado em: "+String.valueOf(d) +"/"+String.valueOf(m)+"/"+String.valueOf(y)+" às: "+String.valueOf(h)+":"+String.valueOf(min)+"\n";

//Cria-se o array para armazenar as strings em ordem para o arquivo de texto
  String retorno[] = new String [5];
  retorno[0] = detimagem;
  retorno[1] = detformato;
  retorno[2] = detTxt;
  retorno[3] = data;
  retorno[4] = copyR;

 
  return retorno; //retorna o array de strings ao documento de texto que é criado ao se pressionar uma tecla
}

}

//_______________________________________________________________________

//TERCEIRA ABA


/*
Aqui cria-se o quadro e seus elementos.

As proporções do quadro são as seguintes:
  -  A largura dos quadriláteros sempre são 1/8 do lado da imagem (img/8),
  - Por esse motivo há a variável larg, que contém esse valor (imgW/8)
  - Os quadriláteros mais externos são a base para o posicionamento dos seguintes
  - O espaço entre a largura de um quadrilátero e outro são: ou a própria largura (larg = imgW/8), ou 0,
  alternando-se.
  - O espaço entre as alturas de cada quadrilátero para o seu seguinte são particulares, não tendo um
  padrão percebido imediatamente. Usa-se, porém, frações da largura e do lado da imagem como unidade de medida
 
  - Para se ter uma animação mais fluida, em casos que os pontos X esquerdo (lX)
  e X direito (rX), que são as larguras dos quadriláteros, estivessem mais à frente
  ao serem incrementados com o valor de "anda" que os pontos X Superior (topX) e
  X inferior (btmX), parecendo estar mais rápidos, diminui-se em 1/2 ou menos o valor da
  variável de movimento, dependendo do tamanho do quadrilátero.
 
*/

void Quadro() {    

  //imgW para largura do quadro
  //imgH para altura do quadro
  float imgW = tam.getValue();
  float imgH = tam.getValue();
 


  //_________ Definições de cores _______________

  //As cores originais da obra estão armazenadas nesta lista, alternando conforme as posições
  //da esquerda para a direita.
  color [] cor = {color (255), color (163), color(255), color (163), color (255), color (163)};

  /*Estas variáveis armazenarão os valores de cada slider RGB, e serão transformadas em valores de cor RGB*/
  float r = red.getValue();
  float g = gre.getValue();
  float b = blu.getValue();


  /*Condição para definição de cores para os quadriláteros:
  
   Se os valores de cor forem maiores que os do plano de fundo da obra original
   Preenche-se os vetores com com os valores das cores novas, que também se alteram
   seguindo o esquema visual de posicionamento.
   Vão do mais escuro ao mais claro
   */
  
  if (r >= 17 || g >= 21 || b >= 28) {
    for (int i = 0; i<6; i++) {
      if (i%2 ==0) {
        cor[i] = color(r*(i+2), g*(i+2), b*(i+2));
      } else {
        cor[i] = color(r, g, b);
      }
    }
  }

  /*Condição para a definição de cores do plano de fundo e tamanho do quadro:
 
   Caso as cores recebam um valor maior que a cor do plano de fundo original,
   O plano de fundo segue as mesmas matizes, com luminosidade mais baixa, para
   distinguir-se dos quadriláteros.
  
   O tamanho do plano de fundo dita o posicionamento de todos os quadriláteros
   e o tamanho do quadro em si, podendo ir de 200 a 563
   */

  if (r >= 17 || g >= 21 || b >= 28) {
    fill(r-50, g-60, b-40);
  } else {
    fill(r, g, b);
  }
 
  rect(0, 0, imgW, imgH);
 


  //_________________DEFINIÇÕES DE POSICIONAMENTO____________

  float topX, lX, btmX, rX;
  float topY, lY, btmY, rY;
  float larg = imgW/8;
  float anda;
 
  //Cria-se a condição para o incremento da variável anda
  //a partir dos valores do slider "move"
  if (move.getValue() > 1){
  anda = move.getValue();
  } else {
  anda = 0;
  }


/*
A partir daqui serão criados os quadriláteros individualmente
Pois cada uma de suas animações e posições possuem particularidades

Todos os quadriláteros são posicionados com seus pontos em ordem
anti-horária: (Topo, esquerdo, inferior, direito)

Quadriláteros posicionados no lado esquerdo do quadro tem seus topos
movidos para a esquerda, enquanto os da direita, movem-se para a direita.

Os pontos esquerdo e direito de cada quadrilátero seguem temporariamente
em uma direção contrária a dos topos, para alinharem-se a eles, depois
seguem a mesma direção.
*/

//_____QUADRILÁTERO 01- GRANDE - ESQUERDO ______

  topX = imgW/2 - anda;
  topY = 0;
 
  lX = anda;
  lY = imgH/2;
 
  btmX = imgW/2 - anda;
  btmY = imgH;
 
  rX = larg + anda;
  rY = imgH/2;
 
 
 /*Cria-se a condição para que nem o topo nem o inferior ultrapassem
 a borda esquerda da imagem e para que nem o lado esquerdo e o direito
 ultrapassem a metade do quadro (imgW/2), fixando suas posições
 */
  if(lX > imgW/2 || rX > imgW/2 || topX < 0 || btmX < 0){
  lX = imgW/2;
  rX = imgW/2 - larg;
  topX = 0;
  btmX = 0;
  }
 
  fill(cor[0]); //recebe a primeira cor do array
  noStroke();
  quad(topX, topY, lX, lY, btmX, btmY, rX, rY); //Em ordem anti-horária
 
 
 
//____QUADRILÁTERO 02 - MÉDIO - ESQUERDO____

 topX = (imgW/2 - anda*2)+(imgW/16);   //Seu topo e seu inferior se movem mais depressa
 topY = larg;                          //que seus lados direito e esquerdo

 lX = larg - (anda/5);

 btmX = (imgW/2 - anda*2)+(imgW/16);
 btmY = imgH-(larg);

 rX = (larg - (anda/5)) + larg ;

/*
Cria-se a condição para que, caso o lX e o rX tenham posições menores que os valores
de 0 e da largura (img/8), ou seja, caso chegem à borda esquerda do quadro, eles
invertam o valor de seus movimentos, movendo-se nas direções contrárias.
*/

if (lX <= 0 || rX < larg){
rX = larg + anda+5; 
lX = rX - larg; 

  if(rX >= imgW/2){  //Mas caso o rX ultrapasse o limite da metade do quadro,
  rX = larg - anda+5; //volta a mover-se na direção contrária
  }
}

/*
Cria-se a condição para fixar as posições do quadrilátero, caso o limite seja
atingido pelo topo e pelo inferior, pelo lado esquerdo do quadro, e pelo
lX e rX pela metade do quadro.
*/

if (topX < 0 || btmX < 0 || rX > (imgW/2 - 2*larg) || lX > imgW/2 - larg){
topX = 0;
btmX = 0;
rX = (imgW/2 - 2*larg);
lX = rX + larg;
}
  
  fill(cor[1]);
  noStroke();
  quad(topX, topY, lX, lY, btmX, btmY, rX, rY);
 
 
 
//_________QUADRILÁTERO 3 - PEQUENO - ESQUERDO_________________

/*É o quadrilátero com a maior particularidade dos 3 esquerdos, pelo
posicionamento de seus pontos inferiores e superiores*/

topX = (imgW/2)+larg/2 - anda*2;
topY = topY+ larg + larg/3;
btmX = topX;
btmY = btmY- (larg + larg/3);
rX = imgW/2 - larg/3 + anda;
lX = imgW/2 - larg + anda;

//Condição para o limite de movimento de rX e lX
//também delimitados pelo meio da imagem (imgW/2)

if (rX >= imgW/2){
rX = imgW/2 - larg/3 - anda;
lX = rX - larg;

if (rX < imgW/2 - 2*larg){
rX = imgW/2 - 2*larg;
lX = rX - larg;
topX = 0;
btmX = 0;
}
}
     
  fill(cor[2]);
  noStroke();
  quad(topX, topY, lX, lY, btmX, btmY, rX, rY);


//___________LADO DIREITO________________

/*Os quadriláteros do lado direito movem-se de maneira oposta aos do lado
esquerdo, porém possuem comportamentos semelhantes. Não podem ultrapassar
o limite do meio da imagem, nem da borda direita*/

//_________QUADRILÁTERO 01 - GRANDE - DIREITO_________________


  topX = imgW/2 + anda;
  topY = 0;
  lX = (imgW-larg) - anda;

  btmX = imgW/2 + anda;
  btmY = imgH;
  rX = imgW  - anda;

//Cria-se a condição de limite para topX, btmX, lX e rX

  if (lX < imgW/2 || rX < imgW/2 || topX > imgW || btmX > imgW){
  lX = imgW/2;
  rX = imgW/2 + larg;
  topX = imgW;
  btmX = imgW;
  }
 
    fill(cor[3]);
    noStroke();
    quad(topX, topY, lX, lY, btmX, btmY, rX, rY);
   
   
   
   
//____________QUADRILÁTERO 02 - MÉDIO - DIREITO______________

/*Agora a maior particularidade pertence a este quadrilátero, por
seu posicionamento de topo e inferior não estarem dentro das proporções
da largura, tendo que utilizar o lado da imagem como unidade de medida*/

  topY = topY+imgW/5;
  rX = imgW  + anda - imgW/4;
  lX = (imgW-larg) + anda - imgW/4;
  btmY = btmY-imgW/5;

//Condição para o limite da largura esquerda e direita 
if (lX <= imgW/2 || rX <= imgW/2-larg){
 rX = (imgW/2-larg) - anda; 
 lX = rX - larg;  
}

if (rX > (imgW - 2*larg) || lX > imgW/2 - larg){
   rX = imgW/2 + 2*larg;
   lX = imgW/2 + larg;
}

//Condição para o limite dos pontos inferiores e superiores
if (topX > imgW || btmX > imgW){ 
topX = imgW;
topY = topY+imgW/3;
btmX = imgW;
btmY = topY+imgW/3;
}

    fill(cor[4]);
    noStroke();
    quad(topX, topY, lX, lY, btmX, btmY, rX, rY);
   
   
   
//________QUADRILÁTERO 3 - PEQUENO - DIREITO ____________ 
/*O último quadrilátero é o menor de todos e possui particularidades
na posição de seu topo e de seu inferior, tendo frações da largura como unidade
de medida*/

topY = imgH/2 - (larg/2 + larg/3);
btmY = imgH/2 + (larg/2 + larg/3);

topX = imgW/2 + anda;
btmX = topX;

lX = (imgW/2 + larg/3) - anda;

rX = ((imgW-larg) - imgW/4) - anda;

/*Condição para o incremento de seu lX e seu rX*/
if (lX<imgW/2){
lX = imgW/2 + anda;
rX = imgW/2+larg + anda;
}

//condição para o limite de posição de lX e rX
if (lX > imgW - (larg/2 + larg/3)){
lX = imgW - larg/3;
rX =  lX - larg;

topX = topX + anda/2;   //Aqui aumenta-se um pouco a velocidade do topX e do btmX
btmX = btmX + anda/2;  //para manter a fluidez do movimento
}

//Condição para o limite de posição de topX e btmX
if (topX > imgW){
topX = imgW;
btmX = imgW;
}

 fill(cor[5]);
 noStroke();
 quad(topX, topY, lX, lY, btmX, btmY, rX, rY);

}

Comentários