Operações com vetores e a classe PVector
Vetores no fundo são são listas de números, algo como [105, 42] ou [120, 81, 35]. Os números são os componentes e os vetores, que podem ter o número de componentes que você quiser, mas nos interessam mais neste momento os vetores com 2 ou 3 componentes pois eles são úteis para representar coordenadas, velocidades e acelerações em duas e três dimensões. Podemos visualizá-los como pontos ou como segmentos de reta orientados, a representação gráfica usual é como uma seta.
É possível trabalhar com vetores de muito mais dimensôes, que não são fáceis de visualizar, muito usados em computação científica, da álgebra linear à representação de palavras para processamento de linguagem natural e tradução automatizada.
É possível somar e subtrair vetores somando os componentes de cada um nas mesmas posições, é fácil também multiplicar ou dividir um vetor por um número comum, multiplicando cada componente pelo número (e isso multiplica ou divide a magnitude do vetor). Já para multiplicar vetores entre si tem mais de uma maneira de fazer, o chamado produto escalar (dot product) e o produto vetorial (cross product). Mas podemos pedir para o computador fazer para nós essas operações!
A classe PVector
Os vetores 2-D e 3-D, de duas e três dimensões, podem ser expressos no Processing como objetos da classe PVector, construídos com PVector(x, y)e PVector(x, y, z), respectivamente. Acredito que em breve você vai concordar comigo que essa classe vai facilitar muito fazer operações, contas e transformações, com vetores, o que é especialmente útil para animar partículas e calcular diversas geometrias.
pos = PVector(75, 400) # posição inicial
vel = PVector(2, -8) # velocidade inicial
acel = PVector(0, 0.1) # aceleração, para baixo
def setup():
size(500, 500)
strokeWeight(5)
def draw():
global pos, vel
point(pos.x, pos.y)
pos += vel
vel += acel

No exemplo acima, o vetor pos representa a posição de uma partícula, o vetor vel a sua velociade, e o vetor acel uma aceleração para baixo (que pode ser interpretada como resultado de uma força causada pela ação da gravidade, por exemplo).
No código o operador de atribuição aumentada +=, aplicado à variável global pos, faz a velocidade alterar a posição, algo equivalente a pos = pos + vel, e da mesma maneira a velocidade é alterada pela aceleração acel.
Uma classe de partículas que fogem do mouse
particles = []
def setup():
size(400, 400)
strokeWeight(5)
for i in range(200):
particles.append(Particle(random(width),random(height)))
def draw():
background(200)
mouse_pos = PVector(mouseX, mouseY)
for p in particles:
p.update(mouse_pos)
class Particle:
def __init__(self, x, y):
self.pos = PVector(x, y)
self.vel = PVector(0, 0) # PVector.random2D()
def update(self, mouse_pos):
delta = self.pos - mouse_pos
d = delta.mag()
if 0 < d < 50:
acel = delta.normalize() * 0.01
self.vel += acel
self.pos += self.vel
self.vel = self.vel * 0.995 # slow down
stroke(max(0, 255 - d * 5,), 0, 0)
point(self.pos.x, self.pos.y)
if self.pos.x < 0:
self.pos.x = width
elif self.pos.x > width:
self.pos.x = 0
if self.pos.y < 0:
self.pos.y = height
elif self.pos.y > height:
self.pos.y = 0

Neste segundo exemplo a diferença (subtração) entre um vetor criado com as cordenadas da posição do mouse (mouse_pos) e o vetor que indiaca a posição de cada partícula (self.pos) é usada para calcular um vetor delta cuja magnitude delta.mag() afeta a aceleração das partículas. Podem ser visto também o uso do método .normalize() para obter um vetor unitário (de magnitude 1) que, mantendo apenas a direção do vetor original delta, é usado para calcular a direção da aceleração. O código poderia talvez ser tornado mais eficiente usando o método que cálcula o quadrado da magnitude (.magSq()) que é mais econômico que o cálculo da magnitude.
Métodos dos vetores PVector
| método | descrição |
|---|---|
| set() | Define (altera) os componentes do vetor. |
| random2D() | Cria um novo vetor unitário 2D com uma direção aleatória. |
| random3D() | Cria um novo vetor unitário 3D com uma direção aleatória. |
| fromAngle() | Cria um novo vetor unitário 2D a partir de um ângulo. |
| copy() | Produz um novo vetor, cópia do original. |
| mag() | Calcula a magnitude do vetor. |
| magSq() | Calcula a magnitude ao quadrado do vetor. É mais rápido que calcular a magnitude! |
| add() | Soma compontentes x, y, e z, ou um segundo vetor a um vetor. Pode-se usar o operador + para somar dois vetores também. |
| sub() | Subtrai compontentes x, y, e z, ou um segundo vetor a um vetor. Pode-se usar o operador - pra subtrair um vetor de outro também. |
| mult() | Multipica um vetor por um valor escalar. Pode-se usar o operador * |
| div() | Divide um vetor por um valor escalar. Pode-se usar o operador / |
| dist() | Calcula a distância entre dois pontos representados por dois vetores. |
| dot() | Calcula o produto escalar (dot product) entre dois vetores. |
| cross() | Calcula o produto vetorial (cross product) entre dois vetores. |
| normalize() | Normaliza o vetor, isto é faz com que fique com a magnitude 1, mantendo a mesma direção. |
| limit() | Limita a magnitude do vetor a um certo valor. |
| setMag() | Define, isto é altera, a magnitude do vetor. |
| heading() | Calcula o ângulo de rotação do vetor, isto é, para onde ele aponta. |
| rotate() | Gira o vetor um certo ângulo em radianos (funciona apenas em 2D). |
| lerp() | Produz o resultado da interpolação linear entre dois vetores. |
| angleBetween() | Calcula o ângulo entre dois vetores. |