Curva Animada com Bezier

Antes de tudo..

Esse artigo é destinado a quem gosta de matemática e quem gosta de animação usando códigos. Caso você seja um programador e tenha curiosidade, recomendo olhar o código antes no final do artigo e depois voltar ao inicio e ir lendo com calma, assim acho que vai ficar mais interessante de ler.

Parte matemática da coisa

O que é a Curva Bezier

A Curva Bézier é uma fórmula para criar uma curva entre dois pontos. Porém ela irá precisar de um terceiro ponto que definira o arco da curva. Vou explicar primeiro os elementos da fórmula até chegar na conclusão do que precisa para recriar ela no papel.

A curva vai se formando ao longo de um tempo, esse tempo é calculado usando porcentagem. Por exemplo, a curva vai ser formada em 5s, logo 0 representa 0% e 5 representa 100%.

Na matemática porcentagem é melhor representada usando a forma decimal entre 0 e 1.
0.01 (1%) - 0.02 (2%) - 0.20 (20%) - 1 (100%).

Além da variante de tempo, a curva de Bézier precisa de 3 pontos para formar ela, o ponto inicial $A_0$, o ponto que define o arco da curva $A_1$, e o ponto que finaliza $A_2$. Esses pontos nesse exemplo vão ser pontos do eixo Y, não vamos considerar o eixo X. pois esse também vai se alterar ao longo do tempo. Vai ficar mais evidente no código em Javascript ao final do artigo.

Passo 1: Calculando $B_0$ e $B_1$

Produto é a operação de multiplicação entre dois ou mais números.

Com esses três pontos o próximo passo é achar os pontos $B_0$ e $B_1$, eles são pontos que vão se mover de acordo com o tempo $t$.

Por exemplo $B_0$, vai iniciar com o mesmo valor de $A_0$ e ao poucos vai indo até o valor de $A_1$. Ou seja, quando $t = 0$, $B_0$ vai ser igual a $A_0$, e quando $t = 1$, $B_0$ vai ser igual a $A_1$.

A fórmula $B_0$ é a soma de dois produtos, o produto $(1 - t) A_{0}$ e o produto $tA_{1}$.

$B_{0} = (1 - t) A_{0} + tA_{1}$

Produto $(1 - t) A_{0}$

$A_0$ é o ponto inicial, se o valor dele for 2, a expressão $(1 - t)$ que vai multiplicar por ele vai começar sem mudar o valor, mas ao poucos vai reduzindo o valor de 2 até chegar a 0.

Caso o ponto inicial $A_0$ tenha o valor 2, a expressão $(1 - t)$ vai reduzir ao longo do tempo de 2 para 0. Segue o exemplo a seguir:

Sendo $t = 0$, $A_0 = 2$:
$(1 - t) * A_0$   =   $(1 - 0) * 2$   =   $2$

Sendo $t = 0.5$, $A_0 = 2$:
$(1 - t)* A_0$   =   $(1 - 0.5) * 2$   =   $0.5 * 2$   =   $1$

Sendo $t = 1$, $A_0 = 2$:
$(1 - t) * A_0$   =   $(1 - 1) * 2$   =   $1 * 2$   =   $0$

Produto $t * A_1$

Enquanto $tA_1$ aos poucos vai aumentando seu valor, começando de $0$ até chegar a $A_1$.

Sendo $t = 0; A_1 = 5$:
$t*A_1$   =   $0 * 5$   =   $0$

Sendo $t = 0.5; A_1 = 5$:
$t*A_1$   =   $0.5 * 5$   =   $2.5$

Sendo $t = 1; A_1 = 5$:
$t*A_1$   =   $1 * 5$   =   $5$

Agora juntando as duas equações pra achar tanto $B_0$ quanto $B_1$:

Inicio da curva $t = 0$

Sendo $t = 0; A_0 = 2; A_1 = 5; A_2 = 2$:
$B_0 = (1 - t) * A_0 + tA_1$   =   $(1 - 0) * 2 + 0 * 5$   =   $2$
$B_1 = (1 - t) * A_1 + tA_2$   =   $(1 - 0) * 5 + 0 * 2$   =   $5$

Quase no meio da curva $t = 0.4$

Sendo $t = 0.4; A_0 = 2; A_1 = 5; A_2 = 2$:
$B_0 = (1 - t) A_0 + tA_1$   =   $(1 -0.4) * 2 + 0.4 * 5$   =   $0.6 * 2 + 2$   =   $1.2 + 2$   =   $3.2$
$B_1 = (1 - t) A_1 + tA_2$   =   $(1 -0.4) * 5 + 0.4 * 2$   =   $0.6 * 5 + 0.8$   =   $3 + 0.8$   =   $3.8$

Final da curva $t = 1$

Sendo $t = 1; A_0 = 2; A_1 = 5; A_2 = 2$:
$B_0 = (1 - t) A_0 + tA_1$   =   $(1 - 1) * 2 + 1 * 5$   =   $0 + 5$   =   $5$
$B_1 = (1 - t) A_1 + tA_2$   =   $(1 - 1) * 5 + 1 * 2$   =   $0 + 2$   =   $2$

Assim dá pra concluir que essa é um fórmula para mover tanto o ponto $B_0$ quanto o ponto $B_1$ de um ponto inicial ao um ponto final.

Passo 2: Calculando C

O ponto $C$ vai representar a curva em si, e esse ponto vai ser formado usando os outros dois pontos $B_0$ e $B_1$. A fórmula vai ser a seguinte:

$C = (1 - t) B_{0} + tB_{1}$

Logo usando os exemplos anteriores de $B_0$ e $B_1$:

$t = 0; B_0 = 2; B_1 = 5$
$C = (1 - t) B_{0} + tB_{1} = (1 - 0) * 2 + 0 * 5 = 2$

$t = 0.4; B_0 = 3.2; B_1 = 3.8$
$C = (1 - t) B_{0} + tB_{1} = (1 - 0.4)*3.2 + 0.4 * 3.8 = 0.6 * 3.2 + 0.4 * 3.8 = 1.92 + 1.52 = 3.44$

$t = 1; B_0 = 5; B_1 = 2$
$C = (1 - t) B_{0} + tB_{1} = (1 - 1) * 5 + 1 * 2 = 0 + 2 = 2$

Aqui dá pra ver que a curva começa sendo o mesmo ponto que $A_0$, vai aumentando até chegar no ponto $A_1$ e depois volta em direção ao ponto $A_2$.

A Fórmula Completa

$t$ = tempo entre 0 e 1
$A_{0}, A_{1}, A_{2}$ - pontos fixos
$B_{0}, B_{1}$ - pontos que vão se mover
$C$ - ponto que forma a curva de Bézier

$B_{0} = (1 - t) A_{0} + tA_{1}$
$B_{1} = (1 - t) A_{1} + tA_{2}$
$C = (1 - t) B_{0} + tB_{1}$

Programando

Para programar essa curva vamos usar o portal codepen: https://codepen.io/.

No código abaixo está um trecho do que eu desenvolvi usando Javascript com Canvas API do navegador.

Link do código completo

Definindo as váriaveis

Aqui vamos definir a variável $t$ no tempo 0 e os pontos $A_0$, $A_1$ e $A_2$:

// Váriaveis para curva
let t = 0;
const A0 = { x: 30, y: 150 };
const A1 = { x: 175, y: 20 };
const A2 = { x: 350, y: 150 };

Canvas

Construindo o canvas que vai pintar a curva, caso não conheça muito sobre o Canvas API, apenas entenda que

let canvas;
let ctx;
const WIDTH = 400;
const HEIGHT = 300;

function clear() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
}

function init() {
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");

  ctx.fillStyle = "#402050";

  ctx.beginPath();
  ctx.rect(0, 0, WIDTH, HEIGHT);
  ctx.closePath();
  ctx.fill();

  ctx.moveTo(30, 150);
  return setInterval(drawLine, 20);
}

init();

Desenhando a curva

Essa é a função que vai ser chamada a cada 20 milisegundos e vai desenhar os pontos da curva. Por isso é preciso calcular o ponto Cx e o ponto Cy, assim vão se tornar parametro para ctx.lineTo(Cx, Cy).

function drawLine() {
  const B0x = (1 - t) * A0.x + t * A1.x;
  const B1x = (1 - t) * A1.x + t * A2.x;
  const Cx = (1 - t) * B0x + t * B1x;

  const B0y = (1 - t) * A0.y + t * A1.y;
  const B1y = (1 - t) * A1.y + t * A2.y;
  const Cy = (1 - t) * B0y + t * B1y;

  ctx.lineTo(Cx, Cy);
  ctx.lineWidth = 2;
  ctx.strokeStyle = "#FFF";
  ctx.stroke();

  if (t < 1) t += 0.005;
}

Conclusão

A Curva Bézier pode ter diversos pontos de controle deixando cada vez maior a fórmula, mas não mais complexa. Esse artigo me demandou alguns dias para escrever já que parece haver pouca tecnologia para sintaxe matemática nas ferramentas web.

Espero que o público-alvo também goste do artigo, pois não é algo simples de ler. É preciso prestar muita atenção e ter interesse em aprender.

Obrigado.