sábado, 14 de junho de 2014

“The Beauty of Data Visualization” de David McCandless

"Dados são o novo petróleo." E os dados são uma espécie de recursos ubíquos que podemos moldar para fornecer inovações e novas percepções e está por todo o lado, e pode ser extraída muito facilmente. "

Informações nunca tiveram tanto valor. Principalmente informações sobre temas variados. Hoje, se você não está atualizado sobre tudo, você não é uma pessoa suficientemente "inteligente". Hoje se faz necessário ter compreensão, uma "opinião formada sobre tudo", e isso é no que a tecnologia vem apostando nos últimos anos. 

Meios de comunicação que utilizam de recursos visuais nunca foram tão procurados. Notebooks de ponta são as novas ferramentas para nos mantermos informados por ser um recurso mais visual; as televisões foram (quase) esquecidas, o que dirá dos rádios e jornais de papel.

Hoje, se uma informação não chega com atrativos, é descartada, é tratada como desinteressante, então nada mais compreensível que as novas tecnologias hoje se adequem a o que é bonito de se ver, que atraiam o olhar, e David McCandless nos mostra uma ferramenta muito importante para que essa ideia seja válida, os gráficos e infográficos.

Para entender um infográfico você não precisa ler um texto enorme sobre o assunto, você só precisa olhar para ele e entender o que significam os poucos dados que nos informam, como, por exemplo o gráfico do fim do vídeo, onde David pergunta ao público sobre o que tratava o gráfico que ele mostrou e recebeu diversas interpretações das pessoas. É isso o que a tecnologia hoje deseja: maior compreensão dada da melhor forma possível.

domingo, 8 de junho de 2014

Jogo da Vida com Zoom


O exercício proposto foi achar um modo de dar um zoom no jogo da vida para melhor visualização dos comportamentos. Descobri que já existia uma função no processing que fazia isso automaticamente. A scale() onde pode-se passar por parametro a quantidade de vezes que pretende dar um zoom.

//A tela terá dimensão tam x tam
int tam = 100;
//Como o tipo PImage é armazenado em vetor, então...
int vtam = tam*tam;
//Imagem a ser exibida
PImage mundo = createImage(tam, tam, RGB);
//Imagem auxiliar para criar uma geração
PImage mundoTemp = createImage(tam, tam, RGB);

int geracao = 0;
int maiorPopulacao = 0;
int menorPopulacao = 0;

void setup() {
  size(800, 800);
  background(0);
  frameRate(5);
  criaMundo();
}

void draw() {
 
 
  scale(8);
  //Criando gerações
  evoluiMundo();
  //Exibindo
  image(mundo, 0, 0);
  geracao++;
  maiorPopulacao = maiorPopulacao(maiorPopulacao);
  menorPopulacao = menorPopulacao(menorPopulacao);
  println("Numero de células vivas " + contaCelulas() + " na geração " + geracao);
  println("Maior população: " + maiorPopulacao);
  println("Menor população: " + menorPopulacao);
}

//cria uma geração
void evoluiMundo() {
  /*A nova geração será guardada em mundoTemp, então
   é necessário copiar a geração atual para mundoTemp */
  for (int i=0; i<vtam; i++)
    mundoTemp.pixels[i] =  mundo.pixels[i];

  //Contador de vizinhos 
  int vizinhos;
  //Para cada célula aplicar as regras do jogo da vida
  for (int i=1; i<tam-1; i++)
    for (int j=1; j<tam-1; j++) {
      vizinhos = contaVizinhos(i, j); //Qtde de vizinhos de uma célula i,j     
      //Se a célula viva, ...
      if (mundo.pixels[pos(i, j)] == color (0, 255, 0)) {
        //Menor que 2 vizinhos ou maior que 3, morra
        if ((vizinhos < 2) ||(vizinhos > 3))
          mundoTemp.pixels[pos(i, j)] = color (0, 0, 0);
      }
      //Se morta, mas com 3 vizinhos, viva
      else if (vizinhos == 3)
        mundoTemp.pixels[pos(i, j)] = color (0, 255, 0);
    }

  //Depois de geração criada, atualizar o mundo, copiando de mundoTemp
  mundo.loadPixels();
  for (int i=0; i<vtam; i++)
    mundo.pixels[i] = mundoTemp.pixels[i];
  mundo.updatePixels();
}

//Conta quantos vizinhos a célula possui
int contaVizinhos(int i, int j) {
  int vizinhos=0;
  vizinhos = celula(i-1, j-1) + celula(i-1, j) + celula(i-1, j+1)
    +celula(i, j-1) + celula(i, j+1) + celula(i+1, j-1)
      +celula(i+1, j) + celula(i+1, j+1);
  return vizinhos;
}

//Se a célula for viva (cor 0,255,0 - verde), retorna 1, senão 0
int celula(int i, int j) {
  if (mundo.pixels[pos(i, j)] == color(0, 255, 0))
    return 1;
  return 0;
}

//Mapeia a posição da matriz em um vetor
int pos(int i, int j) {
  return j * tam + i;
}

//Conta células vivas
int contaCelulas()
{
  int c = 0;

  for (int i = 0; i < vtam; i++)
  {
    if (mundo.pixels[i] == color(0, 255, 0))
    {
      c++;
    }
  }
  return c;
}

//Verifica a maior populacao existente
int maiorPopulacao(int maior)
{
  if (contaCelulas() > maior)
  {
    maior = contaCelulas();
  }
  return maior;
}

//Verifica a menor populacao existente
int menorPopulacao(int menor)
{
  if (menor == 0)
  {
    menor = contaCelulas();
  }
  else if (contaCelulas() < menor)
  {
    menor = contaCelulas();
  }
  return menor;
}


//Cria um mundo aleatório em um quadrado central que vai de 1/3 a 2/3 da tela
void criaMundo() {

  for (int i=0; i<vtam; i++)
  {
    int x = int(random(tam/3, 2*tam/3));
    int y = int(random(tam/3, 2*tam/3));
    mundo.pixels[pos(x, y)] = color(0, 255, 0);
  }
}

terça-feira, 27 de maio de 2014

Análise de interface

Neste post irei fazer uma análise da usabilidade de uma aplicação feita no Processing, os autores que serão utilizados como referência são o Jakob Nielsen e o Steve Krug.

Podemos definir Usabilidade como:

"Usabilidade significa fazer algo que funciona bem, e que uma pessoa não muito experiente consiga usá-lo para a sua devida finalidade, sem nenhuma frustração durante esse processo."(Krug)



Nielsen é um cientista da computação com PHD em Interação Humano-Computador e criou 10 heurísticas para avaliar a usabilidade. Podemos definir uma heurística, segundo a wikipédia, como: Um método ou processo criado com o objetivo de encontrar soluções para um problema.

Steve Krug é um pesquisador na área de usabilidade e escreveu um livro chamado "Don't make me think" que trata do tema usabilidade e interação humano-computador.




Link da aplicação: http://vimeo.com/6875954 

Olhar para as barras de seleção de cor e de tamanho.

Olhar para as barras de seleção de cor e de tamanho.

Neste printscreen temos 5 elementos de interação (3 checkboxes, 2 barras de seleção e 4 textos informativos), as barras de seleção são bastante interessantes para a interação com o sistema, já que elas indicam o estado do "pincel". A barra de seleção de cor se modifica de acordo com a cor escolhida e o tamanho da barra "Pen Size" engrossa e afina facilitando a compreensão da aplicação por parte do usuário. Tal característica representa uma das heurísticas de Nielsen que diz:

"Feedback:
  • O sistema deve informar continuamente ao usuário sobre o que ele está fazendo.
  • 10 segundos é o limite para manter a atenção do usuário focalizada no diálogo."

Apesar de ter utilizado respostas visuais bastante eficientes a interface erra na aplicação das checkboxes e do texto informativo na parte inferior da tela.

A aplicação falha ao deixar o usuário pintar sobre a informação de limpar a tela.

"Os usuários não gostam de quebra-cabeças na hora de fazer as coisas. Isso é fato. Se as pessoas que projetam interfaces não se importarem suficientemente em criar coisas óbvias, podem abalar diretamente a confiança dos usuários sobre o seu site."(Krug)

As checkboxes são extremamente não intuitivas o que contradiz o que Krug aponta como ideal, podendo fazer que o usuário perca tempo e acabe por ter dificuldades em dizer o que o designer quis passar ao usuário. Outra falha é o fato da aplicação permitir que o usuário desenhe sobre a informação de limpar a tela.

A aplicação possui um misto em erros e acertos segundo a heurística de Nielsen que fala sobre atalhos.

"Atalho
  • Para usuários experientes executarem as operações mais rapidamente.
  • Para usuários leigos o sistema precisa ser fácil de usar.
  • Abreviações, teclas de função, duplo clique no mouse, função de volta em sistemas hipertexto.
  • Atalhos também servem para recuperar informações que estão numa profundidade na árvore navegacional a partir da interface principal."  

 Não há um botão que possa limpar a tela, utilizasse apenas um atalho por teclado, além disso o texto informando o teclado ainda pode ser encoberto pelo usuário. Acredito que o melhor seria possuir um botão e ter o atalho, assim um usuário mais experiente poderia aprimorar sua utilização do programa e o usuário mais leigo poderia recorrer à algo mais intuitivo como um botão.

 Uma sugestão seria a criação de botões e atalhos para desfazer ou refazer uma operação(Undo e Redo) segundo o Livro "Don't make me think" do Krug: "Usuários ainda são apegados ao botão de “voltar”", ou seja : Mesmo com uma boa usabilidade, não é difícil ver usuários errando o caminho de vez em quando durante a navegação. Para isso, basta um clique equivocado em um momento de pressa. Apesar dos estudos de Krug serem focados para a parte de web, podemos adaptar esse conceito aos botões de undo e redo propostos acima.

Resumo:

Pontos negativos
  • Não intuitividade sobre o funcionamento das checkboxes.
  • A possibilidade de desenhar sobre um texto que passa uma informação importante sobre o uso da aplicação.
  • Falta de botões para usuários leigos. (Ausência de botões)

Pontos positivos
  •  O bom feedback do sistema em relação ao estado do pincel (Cor, tamanho do traço).
  •  A pintura é feita de forma intuitiva.

Melhorias propostas
  • Separação do menu de configuração do pincel do quadro onde será executado a pintura.
  • Criação de botões (limpar a tela, desfazer uma ação, refazer uma ação).
  • Criação de atalhos para modificar o pincel (mudar cor ou tamanho)
  • Criar labels para os checkboxes de randomico.
Sugestão de interface



Referências:
  •  http://www.tidbits.com.br/as-10-heuristicas-de-usabilidade-do-nielsen
  • http://www.uxdesign.blog.br/usabilidade/10-licoes-de-usabilidade-de-steve-krug/
  • http://pt.slideshare.net/huxleydias/as-10-heursticas-de-nielsen
  • http://corais.org/node/99
  • http://en.wikipedia.org/wiki/Jakob_Nielsen_%28usability_consultant%29
  • http://en.wikipedia.org/wiki/Steve_Krug
  • http://pt.slideshare.net/barao/conceitos-de-usabilidade

 

terça-feira, 13 de maio de 2014

Criação de Cross-Fade.


Segue o código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
PImage imgOriginal;
PImage img2;
float r, g, b;

void setup()
{
  size(320, 240);
  imgOriginal = loadImage("original.jpg");
  img2 = loadImage("personagem.jpg");
}

void draw()
{
  crossFadeCroma(imgOriginal, img2, 30);
}

void crossFadeCroma(PImage img1, PImage img2, float alfa)
{
  {

    loadPixels();
    alfa = alfa/100;
    
    for (int x = 0; x < 320; x++)
    {
      for (int y = 0; y < 240; y++)
      {
        pos = y * 320 +x;
        r = alfa*red(img1.pixels[pos]) + (1-alfa)*red(img2.pixels[pos]);
        g = alfa*green(img1.pixels[pos])  + (1-alfa)*green(img2.pixels[pos]);
        b = alfa*blue(img1.pixels[pos])  + (1-alfa)*blue(img2.pixels[pos]);
        pixels[pos] = color(r, g, b);
      }
    }
    updatePixels();
  }

}




Tratamento de Imagem


O exercício dessa vez é trabalhar com tratamento de imagem. O trabalho consiste em pegar uma mesma imagem e editar seus canais de cor para alterar sua forma. Na imagem abaixo podemos ver a seguinte ordem. (Foto original, foto adicionada com brilho, foto em negativo, foto em preto e branco, foto com preto e branco com média ponderada, Canal vermelho do RGB, canal verde do RGB, canal azul do rgb e as 3 ultimas é uma imagem com cada canal do padrão CMY.





quarta-feira, 7 de maio de 2014

Questão 3 - Prova

Código da questão 3, para descobrir o ângulo foi utilizado o método atan2() que recebe por parametro os 2 catetos do triangulo para calcular esse angulo, retornando um valor entre -180 e 180. Por isso na hora de realizar o text foi acrescido o valor 180 para fazer o número ficar entre 0 e 360.

float posAng = 0; int larguraTela = 600; void setup() { background(200); size(larguraTela, larguraTela); } void draw() { background(200); fill(0); rect(0, 10, larguraTela, 60); fill(255); rect(((larguraTela-30)*posAng)/360, 10, 30, 60); float ang = calculaAngulo(mouseY-larguraTela/2, mouseX-larguraTela/2) ; stroke(0); ellipse(larguraTela/2, larguraTela/2, larguraTela/2, larguraTela/2); polar(larguraTela/4, -ang); posAng = ang+180; textSize(20); text("Angulo " + posAng, larguraTela/2-50, larguraTela - 50); } void polar(float r, float a) { float x = r*cos(radians(a)); float y = r*sin(radians(a)); //stroke(255, 0, 0); strokeWeight(2); line(x+larguraTela/2, larguraTela/2-y, larguraTela/2, larguraTela/2); } float calculaAngulo(float y, float x) { float ang = atan2(y, x); ang = degrees(ang); return ang; }

segunda-feira, 28 de abril de 2014

Lançamento balistico utilizando ângulos

Exercício proposto para criação de uma função que receba como parâmetro um ângulo e a velocidade do disparo.

Print de um instante de execução do código


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
int relogio = millis();
int intervalo = 1000;
float dx;
float dy = 600;

float t;

ArrayList pontos = new ArrayList();

void setup()
{
   size(600,600);
  background(100); 
}

void draw()
{
  t = millis()/100; //contador de tempo
  disparoBalistico(70,100);
  desenhaTrajeto(pontos);
  
}


void disparoBalistico(int ang, int velLancamento)
{
  /*
  Essa função funciona a partir da decomposição dos vetores de movimento
  o Vo da formula é o valor velLancamento, passado por parametro.
  O V utilizado no dx é o resultado da decomposição do eixo X do vetor de movimentação
           |  /
V do MRUV  | /  a linha de / = resultante do vetor, ou hipotenusa, responsável pela direção do projétil
           |/___
            Velocidade do MRU
     eixo y = hipotenusa * seno(angulo)
     eixo x = hipotenusa * cos(angulo)     
  */
  background(100);
  float a = -9.8; //declaro a aceleração, uma CONSTANTE.
  float hipo = velLancamento/sin(radians(ang)); // descubro o valor da hipotenusa, necessária para descobrir o eixo X do vetor
  float velFixo = hipo * cos(radians(ang)); //Descubro o eixo X do vetor.
  //A partir daqui é apenas aplicação de formula.
 pontos.add(dx);    //pontos utilizados para a função desenhaTrajeto.
 pontos.add(dy+600);
 dx = velFixo*t;
 dy = (velLancamento*t + (a*t*t/2))*-1;
 pontos.add(dx);
 pontos.add(dy+600);
 ellipse(dx,600 + dy, 30,30);
 
}

void desenhaTrajeto(ArrayList pontos)
{
 for(int i = 3; i < pontos.size(); i+=2)
{
   line((Float)pontos.get(i-3),(Float)pontos.get(i-2),(Float)pontos.get(i-1),(Float)pontos.get(i));
   
} 
}

Cortando pizzas

Exercício que propõe a divisão de uma esfera em um número de fatias informadas no parametro da função.





 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
void setup()
{
  size(600,600);
  
  desenhaPizza(6);
  
    
}

void desenhaPizza(int n)
{
  int inc = 360/n;
  for(int i = 0; i <= 360; i += inc)
  {
   arc(300,300,250,250,radians(i),radians(i+inc),PIE); 
  }
    
}

Desenho de quadrados

Exercício que propõe a criação de uma função que desenhe um quadrado.





Resultado do código abaixo



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void setup()
{
  size(600,600);
  
  desenhaQuad(10,10,20,20);
  
    
}

void desenhaQuad(int x1,int y1 ,int x2,int y2)
{
  line(x1,y1,x1,y2);
  line(x1,y2,x2,y2);
  line(x2,y2,x2,y1);
  line(x2,y1,x1,y1);
}

Desenhando o Yin Yang

Exercício para utilizar a criação de imagens através da junção de formas geométricas.

Resultado do código abaixo.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void setup ()
{
  size (500, 500);
  mostraYinYang(250, 250, 90);
}

void mostraYinYang (float x, float y, float r)
{
  fill (0);
  ellipse(x, y, 5*r, 5*r); //faz a elipse preta
  fill(255);
  arc(x,y,5*r,5*r,0,PI,OPEN); //faz um meio arco aberto no meio da elipse preta
  noStroke(); //sem linha
  ellipse(x - r-r/4, y, 2.5*r, 2.5*r); // faz a esfera menor do lado esquerdo de acordo com um raio
  fill(0);  
  ellipse(x + r+r/4, y, 2.5*r, 2.5*r); // faz a esfera menor do lado direito de acordo com o raio
  fill(255);
  ellipse(x + r+r/4, y, r, r); //faz a esferinha pequena dentro da esfera menor direita 
  fill(0);
  ellipse(x - r-r/4, y, r, r); //faz a esferinha pequena dentro da esfera menor esquerda 
}

Halftone vertical

Continuação da aula de estruturas de repetição para criação de efeitos visuais.


Resultado do código abaixo.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
void setup () {
  size (400, 400);
}

void draw () {
  background (255);
  int largura = 1;
  for (int j = 0; j < 400; j += 40) //espaçamento vertical das elipses
  {
    largura = largura + 5; // a largura aumenta 5 a cada elipse
    for (int i = 0; i< 400; i += 40) //espaçamento horizontal das elipses
    {
      ellipse(i + 20, j+ 20, largura, largura);
      stroke (mouseX * mouseY, mouseY- mouseX, mouseX+mouseY); //retira a linha das elipses
      fill (mouseX * mouseY, mouseY- mouseX, mouseX+mouseY); //colore as elipses
    }
  }
}

Efeito Halftone central

Objectivo desse exercício é utilizar estruturas de repetição (for) para criação de efeitos visuais.


Resultado do código abaixo.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
int largura = 400;
int altura = 400;

void setup ()
{ 
  size (largura, altura);
  background(0);
  Grid();
}

void Grid() {
  for (int i = 0; i < largura; i+=30) 
  {
    for (int j = 0; j < altura; j+=30)
    {
      float d = dist (i, j, largura/2, altura/2)/10;// d = distância entre pontos
      stroke (255);
      ellipse ( i + 10, j + 10, d*2, d*2);
    }
  }
}

Tabuleiro de xadrez

Exercício para criar o desenho de um tabuleiro de xadrez.

Resultado do código abaixo.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int x = 400;
int y = 400;
int cor = 1;
int largura = 40;
int altura = 40;

void setup()
{
  size(400, 400);
  background(255); //branco
  fill(0); //roxo
}

void draw() 
{
  for (y=0; y<=400; y+=80) //laço para fazer as colunas coloridas intercaladas
  {
      for (x=0; x<400; x+=80) {
        rect(x, y, largura, altura);
        rect(x+40, y+40, largura, altura);
      } 
  }
}

Uso de MRUV horizontal

O exercício aqui foi fazer um código que informasse na tela e no console em qual instante t, a bola alcança a distancia de 123 metros.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int largura=800; 
int altura=800; 
int relogio; 
int intervalo=100; 
float d = 0; 
float v=0; 
float vIni= 0;
float t=0;  
float a=10; 
boolean printou;


void setup() { 
  relogio=millis(); 
  size(largura, altura);
} 
void draw() { 
  if (millis()>relogio+intervalo) { 
    relogio=millis(); 
    background(125); 
    linhas(); 
    moveBolaMRUV(); 
    t+= 0.1;
    if(d <= 0)
    {
     println(t); 
    }
  }
} 
void moveBolaMRUV() { 
  d=vIni*t + (a*t*t)/2;  
  ellipse(d, 400, 25, 25);
  
  textSize(30);
  text("Distância: "+d, 300,200);
  text("Tempo: "+t, 300,250);
  if(d >= 123 && !printou)
  {
     println("Distancia é 123 e o tempo é: " + t );
    printou = true; 
  }
} 

Criando n poligonos regulares

Esse exercício é criar uma função onde seja possível desenhar um polígono regular no centro da tela e com a quantidade de lados que seja desejado.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int largura = 500;    //largura da tela
int altura = 500;     //altura da tela
void setup()
{
   size(largura,altura);
  desenhaForma(150,200); 
}


void draw()
{
  
 
}
//Função que retorna o eixo x de uma coordenada polar em relação an centro da tela
float polarX(float angulo, float raio)
{
  
  float x = raio * (cos(radians(angulo)));
  return x + largura/2;
}

//Função que retorna o eixo y de uma coordenada polar em relação an centro da tela
float polarY(float angulo, float raio)
{
 float y = raio * (sin(radians(angulo))); 
 return y + altura/2;
}


//Função que desenha os lados dos poligonos utlizando o valor retornado pelas funções polarX e polarY
void desenhaForma(int numLado,int raio)
{
  //incremento é o intervalo em angulos das "fatias" do poligono
  float incremento = 360/numLado;
  for(int i = 0; i < 360; i+=incremento)
  {
    line(polarX(i,raio),polarY(i,raio),polarX(i+incremento, raio),polarY(i+incremento, raio));   
  }
}

Cronômetro

O exercício aqui foi o uso de coordenadas polares e controle de tempo afim de criar um relógio apenas com os ponteiros dos segundos.

int relogio;
int intervalo=1000;

float angulo = 270;
void setup() {
  relogio=millis();
  size(500, 500);
}
void draw() {
  if (millis()>relogio+intervalo)
  {
    relogio=millis();
    background(255);
    cronometro();
     angulo += 6;    
  }
}

void polar(float angulo, float raio)
{
  float x = raio * (cos(radians(angulo)));
  float y = raio * (sin(radians(angulo)));              //Decomposição dos vetores x e y para descoberta do valor do ponto desejado.
  line(250,250, x+250,y+250);
}
void cronometro()
{
  //função repsonsável por desenhar o cronometro
     ellipse(250,250,200,200);
     polar(angulo, 80); 
}

quinta-feira, 10 de abril de 2014

Harmonografo

(Harmonia + grafia) Instrumento para combinar e registrar mecanicamente duas ou mais vibrações em uma só curva. Geralmente, são máquinas que simulam dois braços em forma de pêndulo e, com uma caneta ou lápis na ponta de cada braço, realizam movimentos circulares em superfícies, de acordo com o balanço de cada pêndulo em atuação com a gravidade (a frequência, a fase e a amplitude).

A criação dessas máquinas, que começaram a aparecer em meados do século 19 e chegou em popularidade na década de 1890, não podem ser conclusivamente atribuídas a uma única pessoa, embora acredita- se que Hugh Blackburn, professor de matemática na Universidade de Glasgow, possa ter sido o inventor oficial.

Um tipo de harmonógrafo também bem conhecido é o pantógrafo, que usam motores elétricos em vez de pêndulos para mover uma caneta para criar desenhos fantasticamente detalhados e belas linhas. A principal diferença entre este e o harmonógrafo tradicional, além dos motores, é que o pantógrafo possui braços em formato de tesouras que podem ter suas posições alteradas para formarem desenhos diferentes de acordo com a velocidade atribuída a eles.

Há também quem utilize tipos de harmonógrafos como brinquedos. É o caso do espirógrafo, um brinquedo muito famoso que consiste em um conjunto de engrenagens, anéis e retas de plástico com dentes e buracos em seu interior, que, para usá-los, se encaixam um dentro do outro e, em cima de uma folha de papel, com a ajuda de um lápis introduzido nos buracos vazados das peças e arrastado pelo papel, fazem as peças se moverem em movimentos uniformes, desenhando no papel diversas formas.

Nosso Hamonografo  é baseado em funções trigonométricas seno e cosseno e variações de ângulo e amplitude.

O eixo X é baseado na formula = L/2 + cos(angulo1)*(a - i), onde L é a largura da tela, a é a amplitude inicial, e i é um incremento que se modifica em tempo de execução. Em tempo de execução as variáveis angulo1 e i são modificadas fazendo assim uma elipse com amplitude menor e com rotação diferente.

O eixo Y é baseado na formula = L/2 + seno(angulo1)*(a + i), onde L é a largura da tela, a é a amplitude inicial, e i é um incremento que se modifica em tempo de execução. Em tempo de execução as variáveis angulo1 e i são modificadas fazendo assim uma elipse com amplitude maior e com rotação diferente.

Utilizando x = 350 + cos(angulo1)*(200-i), onde angulo1  e i são iniciados em 0(zero),
Y = 350 + sen(angulo2)*(200+i), onde angulo2 é inciado em 60 e o i em 0 e com ajuda de algumas variáveis de controle para realizar o controle dos incrementos nós obtivemos a seguinte imagem:

No processing utilizamos a função descrita abaixo:

int relogio;        //Variável para fazer o timer
int intervalo=100;  //intervalo em millisegundos

//Variáveis para criação do Harmonografo
int anguloHorizontal = 0;    //angulo inicial passado para posição x
int anguloVertical = 60;     //angulo inicial passado para posição y
float incHorizontal = 3;    //valor que incrementa o angulo dentro do método Desenho()
float incVertical = 3;      //valor que incrementa o angulo dentro do método Desenho()
float amplitude = 200;      //valor que será multiplicado ao resultado do coseno ou seno para a amplitude do desenho
float variacaoAmplitude = 6;  //Valor que é utilizado para incrementar e decrementar a amplitude. Assim gerando a dinamica do desenho

//dimensoes da tela
int largura = 700;
int altura = 700;

//Angulos

float cos; 
float sen;
float tan;

//Controle
boolean controle;  //variável de controle para modificação de parametros

void desenho()
{
 
  fill(cos*(100-variacaoAmplitude),sen*200,tan*(150+variacaoAmplitude));
  ellipse(350+cos*(amplitude - variacaoAmplitude ) , 350+-sen*(amplitude +   variacaoAmplitude),10,10);
  anguloHorizontal += incHorizontal;
  anguloVertical += incVertical;
}

void draw()
{
  cos = cos(radians(anguloVertical));
  sen = sin(radians(anguloHorizontal));
  tan = tan(radians(anguloHorizontal));
  if (millis()>relogio+intervalo)
  {
    relogio=millis();
   
    if(!controle)
    {
     variacaoAmplitude++;
    }
    else
    {
     variacaoAmplitude--;
    }
   
    if(variacaoAmplitude > 120)
    {
      controle = !controle;
    }
    else if(variacaoAmplitude < -120)
    {
     controle = !controle;
     anguloVertical = - anguloVertical;
     anguloHorizontal = - anguloHorizontal;
    }
}



quarta-feira, 19 de março de 2014

Pong com 2 players

Para finalizar eu fiz algumas mudanças para poder acrescentar um segundo player jogo.

// Horizontal
int bolaX = 200; //posição da elipse no eixo X
int dX = 10; // coeficiente de movimentação da elipse no eixo X
int dXoriginal = dX;
int inversoes = 0;

//Vertical
int bolaY = 200;
int dY = -10;
int dYoriginal = dY;
int inversoesY = 0;

//paddle Mouse
int posXPaddle = 5;
int topoYPaddle;
int fundoYPaddle;
int alturaPaddle = 100;
int larguraPaddle = 20;

//paddle Teclado
int larguraPaddleT = 20;
int alturaPaddleT = 100;
int fundoYPaddleT;
int topoYPaddleT;
int posXPaddleT = 800 - 25;
int posYPaddleT = 300;
int velY = 5;

// Tela
int larguraTela = 800;
int alturaTela = 600;

// Game State
boolean derrota;

void setup()
{
     size(larguraTela,alturaTela);
}

void draw()
{
  posYPaddleT = velY;
  keyPressed();
  topoYPaddleT = posYPaddleT;
  fundoYPaddleT = posYPaddleT + alturaPaddleT;
  topoYPaddle = mouseY;
  fundoYPaddle = mouseY + alturaPaddle;
  background(0);
  rect(posXPaddle, mouseY,larguraPaddle,alturaPaddle);
  rect(posXPaddleT, posYPaddleT, larguraPaddleT, alturaPaddleT);
  ellipse(bolaX,bolaY,20,20);
   
  bolaX += dX;
  bolaY += dY;
 
  detectarColisao();
  detectarCenario();
}

void detectarColisao()
{
 if(bolaX - 20 <= posXPaddle + larguraPaddle/2 && bolaX - 20 >= posXPaddle - larguraPaddle/2)
  {
    //println("Detectou X");
    if(bolaY >= topoYPaddle && bolaY <= fundoYPaddle)
    {
       dX += dX/10;
       dX *= -1;
      calcularAngulo();
    }
  }

 if(bolaX - 20 >= posXPaddleT)
  {
    //println("Detectou X");
    if(bolaY >= topoYPaddleT && bolaY <= fundoYPaddleT)
    {
       dX += dX/10;
       dX *= -1;
      calcularAngulo();
    }
  }
}

void detectarCenario()
{
  if(bolaY >= 590 || bolaY <= 10)
  {
   inversoesY++;
   dY *= -1;
  }
}

void calcularAngulo()
{
  float rand = random(3,8);
  if(bolaY >= topoYPaddle && bolaY <= topoYPaddle + alturaPaddle/2)
   {
     dY -= rand;
     //println(rand);
   }
 else
 {
   dY += rand;
   //println("Bateu baixo " + rand);
 }
}

void keyPressed() {
  if (key == CODED) {
    if (keyCode == UP) {
      velY += -5;
    } else if (keyCode == DOWN) {
      velY += 5;
    }
    else
    {
      velY = velY;
    }
  }
}

Funções:
keyPressed: Detecta se as setas para cima ou para baixo estão apertadas
detectarColisao: Acrescentei o condicional para detectar o paddle do teclado.

Pong - Mouse


Dando continuação ao projeto de fazer o pong, segue o código de um jogo de 1 player. Por enquanto mais se assemelha a um squash

// Horizontal
int bolaX = 200; //posição da elipse no eixo X
int dX = 10; // coeficiente de movimentação da elipse no eixo X
int dXoriginal = dX;

//Vertical
int bolaY = 200;
int dY = -10;
int dYoriginal = dY;

//paddle Mouse
int posXPaddle = 5;
int topoYPaddle;
int fundoYPaddle;
int alturaPaddle = 100;
int larguraPaddle = 20;

// Tela
int larguraTela = 800;
int alturaTela = 600;

// Game State
boolean derrota;

void setup()
{
     size(larguraTela,alturaTela);
}

void draw()
{
  topoYPaddle = mouseY;
  fundoYPaddle = mouseY + alturaPaddle;
  background(0);
  rect(posXPaddle, mouseY,larguraPaddle,alturaPaddle);
  ellipse(bolaX,bolaY,20,20);
   
  bolaX += dX;
  bolaY += dY;
 
  detectarColisao();
  detectarCenario();
}

void detectarColisao()
{
 if(bolaX - 20 <= posXPaddle + larguraPaddle/2 && bolaX - 20 >= posXPaddle - larguraPaddle/2)
  {
    //println("Detectou X");
    if(bolaY >= topoYPaddle && bolaY <= fundoYPaddle)
    {
       dX += dX/10;
       dX *= -1;
      calcularAngulo();
    }
  }
}

void detectarCenario()
{
  if(bolaY >= 590 || bolaY <= 10)
  {
   inversoesY++;
   dY *= -1;
  }
}

void calcularAngulo()
{
  float rand = random(3,8);
  if(bolaY >= topoYPaddle && bolaY <= topoYPaddle + alturaPaddle/2)
   {
     dY -= rand;
     //println(rand);
   }
 else
 {
   dY += rand;
   //println("Bateu baixo " + rand);
 }
}
}

Funções:
calcularAngulo: Detecta em qual posição do paddle a bola bateu gerando um efeito diferente de acordo com a posição da colisão.
detectarCenario: Vê se a bolinha rebateu na parede.
detectarColisão: Detecta se a bolinha está colidindo com a raquete

Criando um Padle

O projeto da disciplina é desenvolver um Pong utilizando o processing. Neste código explico como fiz o Paddle.

//paddle Mouse
int posXPaddle = 5;
int topoYPaddle;
int fundoYPaddle;
int alturaPaddle = 100;
int larguraPaddle = 20;

// Tela
int larguraTela = 800;
int alturaTela = 600;

void setup()
{
     size(larguraTela,alturaTela);
}

void draw()
{
background(0);  //redesenha o fundo, eliminando assim a posição anterior do paddle da tela
rect(posXPaddle, mouseY,larguraPaddle,alturaPaddle); // Desenha o paddle que recebe como parametro para a posição Y um input da posição Y do mouse.
}



quarta-feira, 26 de fevereiro de 2014

Debugging no Processing

O processing não possui uma ferramenta de debug nativa e isto restringe o uso da aplicação a coisas menores. O debug serve para poder acompanhar a execução do código para procurar possíveis erros, muitas vezes no processing ele não aponta onde é o erro deixando o desenvolvedor completamente perdido.

Para facilitar a codificação uma estratégia é utilizar println() para conseguir acompanhar o código e saber se o condicional foi ativado, ou se o laço ta sendo executado o número certo e vezes. Isto pode facilitar o processor, porém não elimina a necessidade de ser criado um debugging mais profissional.

quarta-feira, 19 de fevereiro de 2014

Matemática e Arte

A matemática e a arte estão interligadas de vários modos de expressão. Inicialmente podemos citar a música e seus tempos, seu ritmo. Na arquitetura e suas formas. Na pintura e suas combinações de cores e formas.

Achei essa página da Universidade do Porto que trata justamente disso e demonstra vários exemplos desenvolvidos na própria universidade.

http://cmup.fc.up.pt/cmup/arte/index.html

Irei tratar do número de ouro nessa postagem.

O número de ouro é um número irracional misterioso e enigmático que nos surge numa infinidade de elementos da natureza na forma de uma razão, sendo considerada por muitos como uma oferta de Deus ao mundo.

O número pode ser encontrado de diversas maneiras tal qual uma sequencia de raizes quadradas, ou de frações entre outros modos. 

Esse número pode ser encontrado em pinturas:


Na arquitetura: 


Além de diversas coisas na natureza:






Podemos ver como a matemática vai muito além de números, podemos ver ela aplicada e produzindo coisas magnificas e todos os aspectos.