Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

Visualização de dados com Processing, Parte 3: 2-D, 3-D, física e redes

M. Tim Jones, Independent author, .
author photo - M. Tim Jones
M. Tim Jones é arquiteto de firmware integrado e autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (atualmente em sua segunda edição), AI Application Programming (em sua segunda edição) e BSD Sockets Programming from a Multilanguage Perspective. Seu conhecimento em engenharia varia do desenvolvimento de kernels para naves espaciais geossincrônicas até a arquitetura de sistemas embarcados e o desenvolvimento de protocolos de rede. Tim é arquiteto senior da Emulex Corp. em Longmont, Colorado.

Resumo:  Este artigo final da série "Visualização de Dados com Processing"explora alguns dos recursos mais avançados do Processing, começando com uma introdução aos gráficos 2D e 3D e recursos de iluminação. Depois, exploraremos aplicativos de física com visualização gráfica, aprenderemos os recursos de rede do Processing e desenvolveremos um aplicativo simples que visualiza os dados a partir da Internet.

Visualizar mais conteúdo nesta série

Data:  16/Mar/2011
Nível:  Intermediário Também disponível em :   Inglês
Atividade:  1898 visualizações
Comentários:  


Parte 1 e Parte 2 exploram muitos dos recursos da linguagem Processing, de gráficos 2D básicos e texto a processamento de imagem. Esta parte final une as pontas soltas e analisa como o Processing lida com gráficos 3D, iluminação e redes. A discussão sobre rede fornece uma maneira de dar o seu aplicativo Processing alguns dados úteis para trabalhar com visualização.

Vamos começar com uma discussão das transformações e dos diversos recursos do Processing que as fornecem.

Transformações

Se já desenvolveu aplicativos gráficos, você provavelmente está familiarizado com álgebra linear e operações de matriz necessárias para implementar coisas como conversão, escala e rotação. O Processing fornece funções para simplificar operações como essas com uma única chamada de função, ocultando a matemática de matriz que ocorre por baixo dos panos.

Coordenar conversão do sistema

A conversão simplesmente muda o sistema de coordenadas, de forma que o canto superior esquerdo exista em um novo deslocamento. É uma operação de adição na qual a conversão define o deslocamento para novas operações na janela do monitor. Por exemplo, o código da Listagem 1 desenha um quadrado com a função rect , depois especifica uma mudança no sistema de coordenadas usando translate. Qualquer nova forma desenhada após a função translate aparece com o deslocamento; por isso, nesse caso, a função rect na verdade cria um quadrado em 100, 100, 150, 150, como mostrado na Figura 1, célula A.


Listagem 1. Usando translate() para alterar o sistema de coordenadas
	
size(200, 200);

rect(0, 0, 50, 50);

translate(100, 100);

rect(0, 0, 50, 50);

Escala

A função scale , como o nome indica, aumenta as operações de desenho. Por exemplo, se você solicitar uma escala de 2.0, seu objeto será 200 por cento maior do que o original (em cada dimensão). A Listagem 2 ilustra esse conceito, com a saída resultante mostrada na Figura 1, célula B.


Listagem 2. Usando scale() para ampliar as operações de desenho de forma
	
size(200, 200);

rect(0, 0, 50, 50);

translate(75, 75);
scale(2.0);

rect(0, 0, 50, 50);

Rotação

A função rotate gira uma forma em torno do canto superior esquerdo (coordenada 0,0). Por essa razão, girar uma forma na verdade não gira no lugar. A Listagem 3 mostra a operação de rotação aplicada a um quadrado. Primeiro, desenha-se o quadrado, depois, especifica-se a operação de rotação que é aplicada às formas posteriores desenhadas na janela de exibição. O resultado é mostrado na Figura 1, célula C.


Listagem 3. Usando rotate() para girar um objeto
	
size(200, 200);

rect(100, 100, 50, 50);

rotate(PI/16);
rect(100, 100, 50, 50);

Se quisesse girar o objeto no lugar, seria preciso atualizar o sistema de coordenadas para dar conta disso. Para isso, use translate para ajustar o sistema de coordenadas e depois redesenhe seu quadrado rotacionado (com coordenadas x e y atualizadas), como mostrado na Listagem 4. O resultado é mostrado na Figura 1, célula D.


Listagem 4. Usando translate() e rotate()
	
size(200, 200);

rect(100, 100, 50, 50);

translate(100, 100);
rotate(PI/16);
rect(0, 0, 50, 50);

O código na Listagem 4 na verdade não girou o objeto no local em torno de seu centro, mas em torno do seu canto superior esquerdo. É possível girar seu quadrado, definindo como desenhar seu objeto. O modo padrão para desenhar retângulos é CORNERS, o que significa que o canto superior esquerdo é definido pelos parâmetros x e y de rect. Se o modo for alterado para CENTER (onde os parâmetros x e y de rect definem o centro), pode-se desenhar um quadrado e girá-lo em torno de seu centro. Isso é mostrado na Listagem 5, com o resultado mostrado na Figura 1, célula E.


Listagem 5. Usando translate() e rotate() em centros
	
size(200, 200);
rectMode(CENTER);
  rect(100, 100, 50, 50);

translate(100, 100);
rotate(PI/16);
rect(0, 0, 50, 50);

Agora, aplique esses conceitos para desenvolver uma imagem que lembre as do espirógrafo. Nesse exemplo, gire um quadrado no seu centro, mas não o preencha. O quadrado é girado 16 vezes em torno do centro, com o resultado mostrado na Figura 1, célula F (com o aplicativo simples mostrado na Listagem 6).


Listagem 6. Mais diversão com conversão e rotação
	
size(200, 200);
rectMode(CENTER);
  noFill();
translate(100, 100);

for (int i = 1 ; i < 16 ; i++) {
  rotate( (PI/16)*i );
  rect(0, 0, 100, 100);
}

O Processing oculta a complexidade das operações de matriz e, em vez disso, apresenta um simples conjunto de funções com operações gráficas úteis, como escala e rotação.


Figura 1. Imagens resultantes do código nas Listagens 1-6


Gerenciando transformações

Após abranger as transformações básicas, vamos explorar mais um tópico que é útil ao desenhar diversas transformações e objetos. Lembre-se de que, depois que uma função de transformação é chamada, os desenhos de formas subsequentes usam essa transformação. Transformações adicionais podem ser realizadas, e elas são aplicadas ao conjunto atual de matrizes definido pelas operações anteriores. Por exemplo, chamar translate no contexto de outro translate significa que o segundo translate se baseia no sistema de coordenadas do primeiro translate, não no original. Pode-se salvar as matrizes de coordenadas internas por meio de uma chamada para pushMatrix e restaurá-las usando popMatrix. Visto que essas funções usam pilha semântica, pode-se criar camadas de transformações para formas e depois removê-las para restaurar as matrizes originais.

Como exemplo, a Listagem 7 mostra pushMatrix e popMatrix. Depois de certa inicialização, empurra-se as matrizes de coordenadas atuais para a pilha. Então, pode-se criar um novo sistema de coordenadas centralizado na sua exibição utilizando translate e armazenar essa matriz. Em seguida, gire e armazene essa matriz; depois, desloque o sistema de coordenadas atual com translate (aplicado a partir das matrizes giradas e convertidas anteriormente) e desenhe uma elipse vermelha. Entre na pilha e desenhe um retângulo verde para remover a conversão e escala anteriores. Entre novamente e desenhe um retângulo azul (que não inclui mais a transformação de rotação). Depois, volte à matriz original e desenhe um quadrado cinza. Esse esquema permite a estratificação das transformações uma sobre a outra, proporcionando a capacidade de restaurar matrizes utilizadas anteriormente para outros objetos na tela. Note que a endentação mostrada na Listagem 7 está ali apenas para facilitar a leitura e não é necessária.

Trabalhando diretamente com matrizes

Se precisar trabalhar com matrizes diretamente, use printMatrix para ver a matriz atual, applyMatrix para multiplicar a matriz atual por uma definida pelo usuário e resetMatrix para reconfigurar a matriz atual para a matriz de identificação.


Listagem 7. Salvando e restaurando matrizes
	
size(200, 200);
rectMode(CENTER);
  noFill();
smooth();
strokeWeight(2);
colorMode(RGB, 100);

pushMatrix();

  translate(100, 100);
pushMatrix();

    rotate(PI/4);
    pushMatrix();

      translate(20, 20);
      scale(2.0);
      stroke(255, 0, 0); // Red
      ellipse(0, 0, 50, 10);

    popMatrix();
    stroke(0, 255, 0); // Green
    rect(0, 0, 50, 25);

  popMatrix();
  stroke(0, 0, 255); // Blue
  rect(0, 0, 75, 50);

popMatrix();
stroke(128, 128, 128); // Gray
rect(0, 0, 50, 50);

O resultado do código da Listagem 7 é mostrado na Figura 2.


Figura 2. Demonstrando pushMatrix e popMatrix


Gráficos 3D

Agora, vamos ampliar a visualização para a terceira dimensão (em um plano 2D), explorando algumas das APIs que o Processing fornece para 3D. Não deixe de acessar Recursos para se aprofundar nos detalhes mais tenebrosos.

O exemplo mostrado na Listagem 8 fornece um programa simples em 3D que usa a função box para criar um objeto na janela de exibição. Como o nome sugere, a função box cria uma caixa na tela (como mostrado, com dimensões iguais). É possível criar retângulos com box apenas adicionando alguns parâmetros (altura, largura e profundidade).

Os únicos outros elementos novos aqui são as funções rotate . Essas funções permitem girar em torno de determinado eixo. A primeira caixa gira em torno do eixo y, e a segunda caixa, em torno do eixo x. O parâmetro para a rotação é determinada a partir do mouse para o eixo específico. O valor do mouse é lido e mapeado (via função map ) no intervalo -PI a PI.


Listagem 8. Exemplo 3D simples com rotação baseada no mouse
	
void setup() {
  size(200, 200, P3D);
  noFill();
  smooth();
}

void draw() {
  background(0);
  translate(width/2, height/2, -(width/2));
  rotateY(map(mouseX, 0, width, -PI, PI));
  stroke(100);
  box(150);
  
  rotateX(map(mouseY, 0, height, -PI, PI));
  stroke(150);
  box(75);
}

A saída da Listagem 8 (pelo menos uma parte estática dela) é mostrada na Figura 3.


Figura 3. Saída estática da Listagem 8


Também é possível adicionar iluminação, e o Processing fornece um conjunto de funções que simplificam isso. Demonstro um aqui com outra função de desenvolvimento de objeto 3D e, em seguida, analiso alguns dos outros. Como a função box , é possível usar sphere para criar uma esfera 3D na janela de exibição. O argumento para sphere representa o raio da esfera.

A Listagem 9 demonstra a função pointLight . Essa função cria uma fonte de luz definida pelos três últimos argumentos de pointLight (sua posição no espaço). Os três primeiros argumentos definem a cor da luz.


Listagem 9. Esfera e luz
	
size(100, 100, P3D);
background(0);
  noStroke();
pointLight(50, 100, 180, 80, 20, 40);
translate(20, 50, 0);
sphere(40);

A Figura 4 fornece a saída do aplicativo simples de Processing na Listagem 9.


Figura 4. Demonstração de pointLight


A função pointLight fornece uma das mais simples funções de luz (com exceção, talvez, de ambientLight), mas o Processing fornece mais controle sobre a iluminação. A função spotLight acrescenta um holofote com controles consideráveis. Por exemplo, além da localização, direção e cor da luz, é possível controlar o ângulo do cone do spotlight e o viés do centro do cone. A função directionalLight permite que a luz seja focalizada em determinada direção e proporciona mais iluminação natural que muda de acordo com a direção e o ângulo da luz.

O Processing oferece meios muito mais complexos de desenvolver objetos usando vértices. É possível desenvolver formas dessa maneira, com a capacidade de texturizá-las. Confira Recursos para obter detalhes sobre esse aspecto do Processing.


Fisíca

Os exemplos anteriores em 3D utilizaram modelos estáticos, mas se quiser um pouco de física de projéteis, poderá estender esse exemplo em tempo real. A Listagem 10 fornece uma simulação simples da caixa sendo lançada de um canhão. As equações da cinemática estão fora do escopo deste artigo, mas confira Recursos para obter mais informações.

A função setup cria a janela de exibição e inicializa a posição inicial da caixa (a origem). Ao desenhar, use background para limpar o monitor e, em seguida, calcular cossenos de direção para a orientação do canhão. Em seguida, em vista da sua variável de tempo, calcule a posição da caixa de dentro da janela de exibição ao longo das três dimensões. Só para adicionar alguns efeitos interessantes, gire a caixa ao redor dos eixos x- e yem proporções diferentes.

Use a função pointLight para criar duas fontes de luz. À esquerda, coloque uma luz azul; à direita, uma luz vermelha. Então, emita o local atual da caixa no espaço 3D para o console de depuração.

Por fim, coloque a caixa no monitor. Comece empurrando o conjunto de matrizes atual para a pilha e chame translate para mudar o deslocamento da sua caixa. Fazer isso permite colocar x ligeiramente à direita da janela, inverter o eixo y (porque, no sistema de coordenadas do Processing, y cresce para baixo) e, finalmente, projetar z para fora (também invertendo-o). Lembre-se de que, no sistema de coordenadas do Processing, x cresce para a direita, y para baixo e z para longe. Por fim, aplique suas rotações de x e y , coloque sua caixa no monitor e entre no conjunto atual de matrizes.


Listagem 10. Simulação de projéteis com Processing
	
float x, y, z;          // Posição atual
float velocity = 120.0; // Velocidade no bocal;
float alpha = 30.0;     // Ângulo do eixo y
float gamma = 60.0;     // Ângulo do eixo x
float g = 9.8;          // Aceleração devido à gravidade (m/s^2)
float time = 0.0;
float dt = 0.1;
float rotX = 0.0, rotY = 0.0;

void setup() {
  size(300, 400, P3D);
  smooth();
  x = 0.0; y = 0.0; z = 0.0;
}


void draw() {
  float b, Lx, Ly, Lz;
  time += dt;
  
  background(0);

  // Calcula cossenos da orientação do canhão (estático)
  b = cos((90.0-alpha) * 3.14/180.0);
  Lx = b * cos(gamma * 3.14/180.0);
  Ly = cos(alpha * 3.14/180.0);
  Lz = b * sin(gamma * 3.14/180.0);

  // Calcular a posição da caixa em determinado momento
  x = velocity * Lx * time;
  y = (cos(alpha*3.14/180.0)) + (velocity * Ly * time) - 
	(0.5 * g * time * time);
  z = velocity * Lz * time;

  // Girar a caixa ao redor dos eixos x e y.
  rotX += PI/256.0;
  rotY += PI/128.0;

  // Criar duas fontes de luz (uma azul e outra vermelha)
  pointLight(0, 100, 255, 0, 0, 0);
  pointLight(255, 0, 0, 400, 400, 0);

  println("x " + x + " y " + y + " z " + z );

  // Colocar a caixa no monitor
  pushMatrix();
  translate(100, 400-y, -z);
  rotateX(rotX); rotateY(rotY);
  box(90);  
  popMatrix();
}

Com esta pequena quantidade de código, implementamos uma simulação simples de um projétil giratório. As etapas de tempo dessa simulação são mostradas na Figura 5, embora a visualização em tempo real seja muito mais interessante.


Figura 5. Trechos da saída da Listagem 10



Redes

O desenvolvimento de aplicativos de rede no Processing é similar às abordagens de Ruby e Python, em comparação com a API padrão em C (a API Berkeley Socket). As funções de rede são implementadas em uma biblioteca e apresentam duas classes para desenvolvimento de aplicativos. A primeira é a classe Server , que pode ser usada para criar servidores; a segunda é a classe Client , que pode ser usada para criar clientes. Há também um conjunto de métodos de eventos que pode ser usado como auxílio para o desenvolvimento de aplicativos. Por exemplo, o evento de servidor é um método de retorno de chamada que é invocado quando um novo cliente se conecta ao servidor. O evento de cliente é um método de retorno de chamada que é invocado quando o servidor enviou bytes para o cliente.

A Listagem 11 mostra um cliente que se comunica com um servidor da Web do mesmo nível com a finalidade de identificar seu software de servidor. Isso é feito simplesmente com o método HTTP HEAD , que retorna metainformações sobre a solicitação do cliente. Por exemplo, os clientes costumam enviar uma solicitação HTTP GET para retornar um arquivo a partir de um servidor Web. A solicitação HEAD não retorna o corpo da mensagem HTTP, mas sim as metainformações do arquivo de solicitação (tamanho, etc.). Essa é a maneira mais simples de reunir as informações nas quais se tem interesse.

A Listagem 11 começa criando uma nova classe de cliente. Defina o servidor e a porta à qual deseja se conectar (nesse caso, a porta do servidor da Web da IBM). Quando se obtém uma conexão com o servidor da Web, é possível enviar a solicitação HTTP usando o método write . No método draw , verifique se há bytes disponíveis para leitura; se houver, execute tokenize neles para dentro de um array. Depois, procure o array para o campo na resposta HTTP para o tipo de servidor (que se parece com Server: Apache). Quando encontrar o campo do servidor, emita o próximo token, que será a própria cadeia de caracteres do servidor (nesse exemplo, IBM_HTTP_Server).


Listagem 11. Um exemplo simples de soquete de cliente
	
import processing.net.*;
Client myClient;
String inString;

void setup() {
  myClient = new Client( this, "www.ibm.com", 80);
  myClient.write("HEAD / HTTP/1.0\n\n");
}

void draw() {
  if (myClient.available() > 0) {
    inString = myClient.readString();
    String[] tokens = splitTokens(inString, ":\n ");
    for (int i = 0 ; i < tokens.length-1 ; i++) {
      if (tokens[i].equals("Server")) println(tokens[i+1]);
    } 
  }
}

A classe Server fornece um conjunto de métodos similares, além de disconnect, que desconecta determinado cliente, e stop, que desconecta todos os clientes e para o servidor. Consulte a referência do Processing (veja Recursos) para obter mais detalhes sobre essa API.


Desenvolvendo um mashup de rede

Vejamos outro exemplo de soquete de cliente que recebe dados da Internet e os apresenta. Para o exemplo, vamos incorporar ideias de outros tópicos que aprendemos neste artigo final para visualizar os dados a partir de um serviço da Web. Usaremos seu cliente de soquete para nos conectar à API Yahoo! Traffic REST e extrair as informações de tráfego para determinado local (veja a Listagem 12). Depois de ter se conectado ao servidor remoto (parte da instanciação da classe Client ), escreva sua solicitação. Essa é uma solicitação REST e especifica o serviço com o qual você deseja se comunicar (Yahoo!'s MapsService) juntamente com as informações de localização nas quais se interessa (Sunnyvale, Calif.). Com sua solicitação concluída, é possível criar seu monitor e carregar sua fonte.

A função draw tem duas seções de código. A primeira é o recebimento da resposta HTTP (que aparece primeiro). Nessa seção, receberemos caracteres à medida que estiverem disponíveis, executaremos tokenize no resultado atual para procurar o token Title (na verdade, <Title>, mas parte do processo de tokenize é retirar os sinais de maior e menor). Quando o token Title é localizado, a próxima cadeia de caractere será o título do incidente de tráfego.

A próxima seção emite uma cadeia de caracteres de incidente de tráfego para o monitor, se tiver sido recebida (é possível saber isso porque ela tem um comprimento diferente de zero). Como se deu no exemplo 3D anterior, aplique escala e rotação à saída para torná-la um pouco mais interessante. O resultado é uma cadeia de caracteres que gira lentamente, se afastando até o infinito.


Listagem 12. Cliente simples para extrair dados de incidentes de tráfego
	
import processing.net.*;
Client myClient;
String input="";
String displayString="";
float myScale=1.0, myRatioX = 0.0, myRatioY = 0.0;

void setup() {
  myClient = new Client(this, "local.yahooapis.com", 80);
  myClient.write("GET /MapsService/V1/trafficData"+
      "?appid=YdnDemo&city=Sunnyvale&state=CA HTTP/1.1\n");
  myClient.write("Accept: text/html, text/xml\n");
  myClient.write("Host: mtjones.com\n\n");

  size(900, 300, P3D);
  PFont font = loadFont("AbadiMT-Condensed-48.vlw");
  textFont(font, 48);
  frameRate(20);
  smooth();
}

void draw()
{
  background(100);

  if (myClient.available() > 0) {
    input += myClient.readString();
    
    String tokens[] = splitTokens(input, "<>\n");
    
    for (int i = 0 ; i < tokens.length ; i++) {
      if (tokens[i].equals("Title")) {
        displayString = tokens[i+1];
      }
    }
    
  }
  
  if ((displayString.length() > 0) && (myScale > 0)) {

    myRatioX += (PI/300);
    myRatioY += (PI/460);
    myScale -= 0.005;
 
    scale(myScale);
    pushMatrix();
    translate( 50, height/2, 0);
    rotateX(myRatioX);
    rotateY(myRatioY);
    rotateZ(myRatioY/4);
    texto(displayString, 0, 0);
    popMatrix();
  }
  
}

O resultado da Listagem 12 é mostrado na Figura 6. Essa imagem foi obtida em 23 quadros, por isso, está apenas começando seu movimento.


Figura 6. Saída da Listagem 12



Avançando um pouco mais

O Processing não é apenas uma ótima linguagem e ambiente para visualização, mas um ótimo exemplo do que é possível com a tecnologia de software livre. O Processing é utilizado não só por engenheiros e cientistas para visualização de dados, mas também por artistas e pessoas interessadas em aprender programação e design visual.


Recursos

Aprender

Obter produtos e tecnologias

Discutir

  • Participe dos Blogs do developerWorks e participe da comunidade do developerWorks.

  • Participe da comunidade do developerWorks. Entre em contato com outros usuários do developerWorks, enquanto explora os blogs, fóruns, grupos e wikis orientados ao desenvolvedor.

Sobre o autor

author photo - M. Tim Jones

M. Tim Jones é arquiteto de firmware integrado e autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (atualmente em sua segunda edição), AI Application Programming (em sua segunda edição) e BSD Sockets Programming from a Multilanguage Perspective. Seu conhecimento em engenharia varia do desenvolvimento de kernels para naves espaciais geossincrônicas até a arquitetura de sistemas embarcados e o desenvolvimento de protocolos de rede. Tim é arquiteto senior da Emulex Corp. em Longmont, Colorado.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=632916
ArticleTitle=Visualização de dados com Processing, Parte 3: 2-D, 3-D, física e redes
publish-date=03162011
author1-email=mtj@mtjones.com
author1-email-cc=

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).