Last updated on

Fórmula de Comprimento de Arco de uma Curva de Bézier

ENNLESPT-BR


O comprimento de arco de uma curva de Bézier é a distância total que um ponto percorre desde o início da curva até o fim. Você o obtém integrando a rapidez desse ponto, que é o comprimento da derivada da curva, ao longo do intervalo do parâmetro. Uma curva de Bézier quadrática tem uma forma fechada exata. Uma curva de Bézier cúbica geralmente não tem, então as implementações aproximam seu comprimento com quadratura numérica. Esta página deriva a fórmula quadrática, constrói a aproximação cúbica e mostra como transformar o comprimento de arco em uma parametrização por comprimento que move um ponto com rapidez constante. O tutorial interativo de curvas de Bézier cobre a geometria dos pontos de controle sobre a qual tudo aqui se baseia.

O comprimento de arco é a integral da rapidez

Uma curva de Bézier associa um ponto B(t)B(t) a cada valor do parâmetro tt entre 00 e 11. Conforme tt aumenta, esse ponto desliza ao longo da curva. Sua velocidade é a derivada B′(t)B'(t), um vetor que aponta na direção do movimento, e a rapidez é o comprimento desse vetor:

∣B′(t)∣=Bx′(t)2+By′(t)2|B'(t)| = \sqrt{B_x'(t)^2 + B_y'(t)^2}

A rapidez mede a distância percorrida por unidade de tt. A rapidez vezes um passo infinitesimal dtdt dá a distância coberta nesse passo, então somar essas pequenas parcelas dá o total:

s(t)=∫0t∣B′(τ)∣ dτ,L=s(1)=∫01∣B′(t)∣ dts(t) = \int_0^t |B'(\tau)|,d\tau, \qquad L = s(1) = \int_0^1 |B'(t)|,dt

Aqui tt é o parâmetro da curva, τ\tau é uma variável muda de integração, s(t)s(t) é o comprimento de arco acumulado desde o início até o parâmetro tt, e LL é o comprimento total da curva. A linha reta entre as extremidades é sempre mais curta que a curva, e o polígono de controle, que conecta os pontos de controle com segmentos retos, é sempre mais longo. O comprimento verdadeiro fica entre esses dois limites, e é igual à área sob a curva de rapidez representada em função de tt.

A consequência prática importante é que tt não é distância. Passos iguais em tt produzem passos desiguais em distância sempre que a rapidez muda ao longo da curva. Um renderizador que amostra uniformemente em tt colocará mais pontos onde a curva é lenta e menos onde ela é rápida.

O painel esquerdo é uma curva quadrática ou cúbica editável. O painel direito representa a rapidez correspondente ∣B′(t)∣|B'(t)| em função de tt e sombreia a área sob ela. Essa área sombreada é o comprimento de arco exibido no canto. Arrastar um ponto de controle muda os dois painéis ao mesmo tempo: afastar os pontos de controle eleva a curva de rapidez e aumenta a área, enquanto uma forma compacta abaixa a curva e a reduz. Mude para o caso cúbico e a curva de rapidez pode desenvolver várias corcovas, porque a derivada da cúbica é um polinômio quadrático cujo comprimento muda com mais liberdade que a derivada linear da quadrática.

Encontrar o comprimento total de uma curva de Bézier quadrática

Uma curva de Bézier quadrática usa três pontos e a fórmula

B(t)=(1−t)2P0+2(1−t)tP1+t2P2B(t) = (1 - t)^2 P_0 + 2(1 - t)t P_1 + t^2 P_2

Derivar dá a velocidade:

B′(t)=2(1−t)(P1−P0)+2t(P2−P1)B'(t) = 2(1 - t)(P_1 - P_0) + 2t(P_2 - P_1)

Essa expressão é linear em tt, o que é a chave da forma fechada. Reúna as partes constante e linear definindo dois vetores novos:

A=P0−2P1+P2,B=2(P1−P0)A = P_0 - 2P_1 + P_2, \qquad B = 2(P_1 - P_0)

Agora a velocidade é simplesmente

B′(t)=2At+BB'(t) = 2A t + B

Você pode verificar isso expandindo 2At+B2At + B: é igual a 2(1−t)(P1−P0)+2t(P2−P1)2(1-t)(P_1 - P_0) + 2t(P_2 - P_1), a derivada acima. Como a derivada é uma linha reta em tt, o quadrado de seu comprimento é um polinômio quadrático:

∣B′(t)∣2=(2At+B)⋅(2At+B)=at2+bt+c|B'(t)|^2 = (2At + B)\cdot(2At + B) = a t^2 + b t + c

com os três coeficientes escalares

a=4(A⋅A),b=4(A⋅B),c=B⋅Ba = 4(A \cdot A), \qquad b = 4(A \cdot B), \qquad c = B \cdot B

A rapidez é a raiz quadrada desse polinômio quadrático, e o comprimento é sua integral:

L=∫01at2+bt+c dtL = \int_0^1 \sqrt{a t^2 + b t + c},dt

Para calculá-la, complete o quadrado dentro da raiz. Escreva k=b/(2a)k = b / (2a) e m=c/a−k2m = c/a - k^2. Então

at2+bt+c=a((t+k)2+m)a t^2 + b t + c = a\left((t + k)^2 + m\right)

Substituir u=t+ku = t + k transforma a integral em uma forma padrão:

L=a∫kk+1u2+m duL = \sqrt{a}\int_k^{k+1} \sqrt{u^2 + m},du

A primitiva de u2+m\sqrt{u^2 + m} para m>0m > 0 é

F(u)=12(uu2+m+mln⁡(u+u2+m))F(u) = \frac{1}{2}\left(u\sqrt{u^2 + m} + m\ln\left(u + \sqrt{u^2 + m}\right)\right)

então o comprimento de arco quadrático exato é

L=a (F(k+1)−F(k))L = \sqrt{a},\bigl(F(k+1) - F(k)\bigr)

A quantidade mm nunca é negativa para uma curva de Bézier quadrática. O produto (A⋅B)2(A \cdot B)^2 nunca pode exceder (A⋅A)(B⋅B)(A \cdot A)(B \cdot B) pela desigualdade de Cauchy-Schwarz, e essa é exatamente a condição que faz m≥0m \ge 0. Quando AA e BB são paralelos, mm é zero, o logaritmo se torna singular e a raiz se simplifica para a ∣t+k∣\sqrt{a},|t + k|. A integral do valor absoluto é fácil de calcular por partes.

Exemplo resolvido

Tome P0=(0,0)P_0 = (0,0), P1=(1,2)P_1 = (1,2) e P2=(3,0)P_2 = (3,0). Então

A=(0,0)−2(1,2)+(3,0)=(1,−4),B=2(1,2)−2(0,0)=(2,4)A = (0,0) - 2(1,2) + (3,0) = (1,-4), \qquad B = 2(1,2) - 2(0,0) = (2,4)

Os coeficientes são a=4(1+16)=68a = 4(1 + 16) = 68, b=4(2−16)=−56b = 4(2 - 16) = -56 e c=4+16=20c = 4 + 16 = 20. O deslocamento é

k=−562⋅68=−717≈−0.4118k = \frac{-56}{2 \cdot 68} = -\frac{7}{17} \approx -0.4118

e o termo constante é

m=2068−(−717)2=36289≈0.1246m = \frac{20}{68} - \left(-\frac{7}{17}\right)^2 = \frac{36}{289} \approx 0.1246

Calcular FF nas duas extremidades dá F(1+k)≈0.2169F(1 + k) \approx 0.2169 e F(k)≈−0.2385F(k) \approx -0.2385. Com a≈8.2462\sqrt{a} \approx 8.2462, o comprimento é

L≈8.2462×(0.2169+0.2385)≈3.7546L \approx 8.2462 \times (0.2169 + 0.2385) \approx 3.7546

Comprimento de arco quadrático em código

Esta função retorna o comprimento exato, incluindo os casos de linha reta e de velocidade paralela:

function quadraticArcLength(P0, P1, P2) {
  // A = P0 - 2 P1 + P2 and B = 2 (P1 - P0) make B'(t) = 2 A t + B.
  const ax = P0.x - 2 * P1.x + P2.x;
  const ay = P0.y - 2 * P1.y + P2.y;
  const bx = 2 * (P1.x - P0.x);
  const by = 2 * (P1.y - P0.y);

  const a = 4 * (ax * ax + ay * ay);
  const b = 4 * (ax * bx + ay * by);
  const c = bx * bx + by * by;

  // Constant speed: the curve is a straight line.
  if (a === 0) return Math.sqrt(c);

  const k = b / (2 * a);
  const scale = Math.sqrt(a);
  const disc = b * b - 4 * a * c;

  // A parallel to B: the speed is sqrt(a) * |t + k|.
  if (Math.abs(disc) < 1e-12 * a * c + 1e-30) {
    const abs = (x) => 0.5 * x * Math.abs(x);
    return scale * (abs(1 + k) - abs(k));
  }

  const m = c / a - k * k;
  const F = (u) => 0.5 * (u * Math.sqrt(u * u + m) + m * Math.log(u + Math.sqrt(u * u + m)));
  return scale * (F(1 + k) - F(k));
}

A ramificação a === 0 é acionada quando P1P_1 é o ponto médio de P0P_0 e P2P_2, o que colapsa a curva em uma linha reta. A ramificação de discriminante quase nulo captura a situação em que a velocidade permanece sobre uma mesma reta mas pode inverter a direção, de modo que a curva vai e volta. Para o caso comum, a forma fechada roda em tempo constante sem amostragem.

Por que o comprimento de arco de uma Bézier cúbica não tem forma fechada

Uma curva de Bézier cúbica usa quatro pontos:

B(t)=(1−t)3P0+3(1−t)2tP1+3(1−t)t2P2+t3P3B(t) = (1 - t)^3 P_0 + 3(1 - t)^2t P_1 + 3(1 - t)t^2 P_2 + t^3 P_3

Sua derivada é

B′(t)=3(1−t)2(P1−P0)+6(1−t)t(P2−P1)+3t2(P3−P2)B'(t) = 3(1 - t)^2 (P_1 - P_0) + 6(1 - t)t (P_2 - P_1) + 3t^2 (P_3 - P_2)

Cada termo é um vetor multiplicado por um polinômio quadrático em tt, então B′(t)B'(t) é um vetor de grau dois, e ∣B′(t)∣2|B'(t)|^2 é um único polinômio de quarto grau em tt. A rapidez é a raiz quadrada desse polinômio de quarto grau. Integrais da raiz quadrada de um quarto grau geral são integrais elípticas, e integrais elípticas não têm expressão em funções elementares. Não existe uma fórmula logarítmica ou com raízes que cubra toda cúbica como a fórmula de completar o quadrado cobre toda quadrática.

Isso não significa que o comprimento seja incognoscível. Significa que o comprimento precisa ser calculado em vez de consultado, e a ferramenta padrão para esse trabalho é a quadratura gaussiana.

Aproximar o comprimento de arco de uma Bézier cúbica

A quadratura de Gauss-Legendre aproxima uma integral definida amostrando o integrando em um pequeno conjunto de pontos e tomando uma soma ponderada:

∫−11f(x) dx≈∑i=1nwif(xi)\int_{-1}^{1} f(x),dx \approx \sum_{i=1}^{n} w_i f(x_i)

Os pontos xix_i são as raízes do nn-ésimo polinômio de Legendre, e os pesos wiw_i são escolhidos de modo que a regra seja exata para todo polinômio até o grau 2n−12n - 1. Nosso intervalo é [0,1][0,1] em vez de [−1,1][-1,1], então substitua t=(x+1)/2t = (x + 1)/2, o que dá

∫01f(t) dt=12∑i=1nwif ⁣(xi+12)\int_0^1 f(t),dt = \frac{1}{2}\sum_{i=1}^{n} w_i f!\left(\frac{x_i + 1}{2}\right)

Dezesseis pontos tornam a regra exata para polinômios até o grau 31. A rapidez é uma raiz quadrada em vez de um polinômio, então a regra não é exata, mas para uma função de rapidez suave 16 pontos já chegam a poucas partes por milhão do comprimento verdadeiro.

// 16-point Gauss-Legendre abscissae and weights on [-1, 1].
const GL_X = [
  -0.989400934991650, -0.944575023073233, -0.865631202387832, -0.755404408355003,
  -0.617876244402644, -0.458016777657227, -0.281603550779259, -0.095012509837637,
   0.095012509837637,  0.281603550779259,  0.458016777657227,  0.617876244402644,
   0.755404408355003,  0.865631202387832,  0.944575023073233,  0.989400934991650,
];
const GL_W = [
  0.027152459411754, 0.062253523938648, 0.095158511682493, 0.124628971255534,
  0.149595988816577, 0.169156519395003, 0.182603415044924, 0.189450610455069,
  0.189450610455069, 0.182603415044924, 0.169156519395003, 0.149595988816577,
  0.124628971255534, 0.095158511682493, 0.062253523938648, 0.027152459411754,
];

function cubicSpeed(t, P) {
  const u = 1 - t;
  const dx = 3 * u * u * (P[1].x - P[0].x) + 6 * u * t * (P[2].x - P[1].x) + 3 * t * t * (P[3].x - P[2].x);
  const dy = 3 * u * u * (P[1].y - P[0].y) + 6 * u * t * (P[2].y - P[1].y) + 3 * t * t * (P[3].y - P[2].y);
  return Math.sqrt(dx * dx + dy * dy);
}

function cubicArcLength(P) {
  let sum = 0;
  for (let i = 0; i < GL_X.length; i++) {
    const t = 0.5 * GL_X[i] + 0.5;
    sum += GL_W[i] * cubicSpeed(t, P);
  }
  return 0.5 * sum;
}

A mesma função auxiliar serve quando a quadratura precisa do comprimento desde o início até um parâmetro arbitrário tt em vez da curva inteira. Mantenha as abcissas e os pesos, e escale o intervalo para [0,t][0, t]:

function cubicArcLengthTo(t, P) {
  if (t <= 0) return 0;
  let sum = 0;
  for (let i = 0; i < GL_X.length; i++) {
    const s = 0.5 * t * (GL_X[i] + 1);
    sum += GL_W[i] * cubicSpeed(s, P);
  }
  return 0.5 * t * sum;
}

Qual é a precisão da quadratura?

A tabela compara a regra com uma referência de alta precisão para três curvas cúbicas. Os erros são absolutos.

Pontos de controle da cúbica Comprimento verdadeiro 8 pontos 16 pontos 24 pontos
(0,0) (1,3) (4,−2) (5,1)(0,0)\ (1,3)\ (4,-2)\ (5,1) 6.214707537 1.9×10−41.9\times10^{-4} 7.1×10−77.1\times10^{-7} 2.2×10−102.2\times10^{-10}
(0,0) (1,1) (2,1) (3,0)(0,0)\ (1,1)\ (2,1)\ (3,0) 3.443380724 6.2×10−86.2\times10^{-8} 1.6×10−141.6\times10^{-14} <10−15<10^{-15}
(0,0) (0,1) (0,−1) (0,0)(0,0)\ (0,1)\ (0,-1)\ (0,0) 1.154700538 1.5×10−21.5\times10^{-2} 3.8×10−33.8\times10^{-3} 2.4×10−32.4\times10^{-3}

As duas primeiras curvas têm perfis de rapidez suaves, e 16 pontos são mais que suficientes. A terceira curva volta sobre si mesma, então sua rapidez cai a zero e a função de rapidez tem um canto. A quadratura converge lentamente em um canto, e adicionar mais pontos ajuda muito pouco. A solução é dividir o intervalo do parâmetro no ponto problemático e integrar cada parte separadamente, ou usar o método de subdivisão abaixo.

Subdivisão adaptativa como alternativa

O algoritmo de De Casteljau pode dividir um segmento cúbico em dois segmentos cúbicos menores em qualquer valor de parâmetro, e dividir em 0.50.5 é especialmente simples: faça a média de pontos de controle vizinhos até restar um único ponto. O polígono de controle de uma peça pequena é quase uma linha reta, então tanto seu comprimento quanto o comprimento da corda entre as extremidades ficam próximos do comprimento de arco verdadeiro. A diferença entre eles mede o quanto a peça ainda se curva. Quando a diferença fica abaixo de uma tolerância, retorne a média dos dois; caso contrário, divida e recorra.

const distance = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
const midpoint = (a, b) => ({ x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 });

function adaptiveArcLength(P0, P1, P2, P3, tolerance = 1e-6) {
  const chord = distance(P0, P3);
  const polygon =
    distance(P0, P1) + distance(P1, P2) + distance(P2, P3);
  if (polygon - chord <= tolerance) {
    return (polygon + chord) / 2;
  }

  // Split at t = 0.5 with de Casteljau averaging.
  const p01 = midpoint(P0, P1);
  const p12 = midpoint(P1, P2);
  const p23 = midpoint(P2, P3);
  const p012 = midpoint(p01, p12);
  const p123 = midpoint(p12, p23);
  const mid = midpoint(p012, p123);

  return (
    adaptiveArcLength(P0, p01, p012, mid, tolerance) +
    adaptiveArcLength(mid, p123, p23, P3, tolerance)
  );
}

A subdivisão adaptativa custa mais avaliações que uma única regra de 16 pontos, mas concentra o trabalho onde a curva dobra e continua funcionando em curvas com cantos ou quase cúspides. A regra de quadratura é mais rápida para as curvas suaves que aparecem na maior parte do trabalho de renderização e animação, e a subdivisão é o recurso seguro quando uma tolerância precisa ser garantida.

Parametrização por comprimento de uma curva de Bézier

Tudo até aqui calcula o comprimento a partir do parâmetro. A pergunta inversa, encontrar o parâmetro que corresponde a uma distância dada, é o que torna possível o movimento com rapidez constante. Defina a função de comprimento acumulado

s(t)=∫0t∣B′(τ)∣ dτs(t) = \int_0^t |B'(\tau)|,d\tau

Como a rapidez nunca é negativa, s(t)s(t) cresce de forma constante de 00 a LL conforme tt vai de 00 a 11, então ela pode ser invertida. A inversa, escrita t(s)t(s), é a parametrização por comprimento: dê a ela uma distância e ela retorna o parâmetro que coloca o ponto exatamente a essa distância ao longo da curva. A direção direta tem uma forma fechada para curvas quadráticas e uma regra de quadratura para curvas cúbicas, mas nenhuma das inversas tem expressão elementar em geral, então as implementações constroem uma tabela e interpolam.

A receita tem três passos. Amostre s(t)s(t) em muitos valores de tt igualmente espaçados e armazene os pares. Para converter uma distância alvo em um parâmetro, faça uma busca binária na tabela pelo par que a cerca e depois interpole linearmente. Como a tabela é apenas uma aproximação linear por partes de uma função suave, finalize com um ou dois passos de Newton. O método de Newton encontra uma raiz de s(t)−stargets(t) - s_{\text{target}} usando a derivada s′(t)=∣B′(t)∣s'(t) = |B'(t)|, que é exatamente a rapidez que já está disponível.

Os dois painéis mostram a mesma curva cúbica. O painel esquerdo coloca um ponto a cada décimo do intervalo do parâmetro, e o painel direito coloca um ponto a cada décimo do comprimento de arco total. Arrastar um ponto de controle remodela os dois painéis juntos. Onde a curva se move devagar, os pontos do parâmetro se aglomeram, e onde ela se move rápido, eles se espalham. Os pontos de comprimento de arco permanecem igualmente espaçados porque a tabela mapeia cada distância igual de volta ao parâmetro que a alcança. Os marcadores vermelhos percorrem as duas curvas no mesmo tempo. O marcador esquerdo acelera e desacelera com o parâmetro, e o marcador direito se move em ritmo constante.

Construir e inverter a tabela de comprimentos

function buildArcLengthTable(P, samples = 128) {
  const ts = new Float64Array(samples + 1);
  const ss = new Float64Array(samples + 1);
  for (let i = 1; i <= samples; i++) {
    ts[i] = i / samples;
    ss[i] = cubicArcLengthTo(ts[i], P);
  }
  return { ts, ss, length: ss[samples] };
}

function parameterAtLength(table, target, P) {
  const { ts, ss } = table;

  // Binary search for the pair of samples that bracket the target.
  let lo = 0;
  let hi = ts.length - 1;
  while (lo + 1 < hi) {
    const mid = (lo + hi) >> 1;
    if (ss[mid] <= target) lo = mid;
    else hi = mid;
  }

  // Linear interpolation gives a good starting point.
  const span = ss[hi] - ss[lo];
  let t = span > 0 ? ts[lo] + ((target - ss[lo]) / span) * (ts[hi] - ts[lo]) : ts[lo];

  // Newton steps refine the answer to full precision.
  for (let i = 0; i < 3; i++) {
    const speed = cubicSpeed(t, P);
    if (speed < 1e-9) break;
    t -= (cubicArcLengthTo(t, P) - target) / speed;
    t = Math.min(1, Math.max(0, t));
  }

  return t;
}

A tabela é construída uma vez por formato de curva. Mudar um ponto de controle a invalida, mas mover um ponto ao longo da curva em tempo de execução apenas realiza consultas. Para mover um objeto com rapidez constante vv, avance a distância em vv vezes o tempo decorrido e chame parameterAtLength com o resultado:

const table = buildArcLengthTable(P);
let travelled = 0;
let previous = performance.now();

function step(now, targetSpeed) {
  travelled += targetSpeed * (now - previous) / 1000;
  previous = now;
  const distance = travelled % table.length;
  const t = parameterAtLength(table, distance, P);
  // Sample the curve at t to place the object.
}

Sem as consultas à tabela, avançar o parâmetro diretamente faria o objeto dar trancos nas partes rápidas da curva e rastejar nas partes lentas.

Verificar a implementação

Algumas asserções cobrem as principais ramificações. A forma fechada quadrática deve coincidir com a regra de quadratura na mesma curva, porque a regra de quadratura é precisa o suficiente nessa escala. A ida e volta pela tabela deve retornar a distância original após converter para um parâmetro e voltar.

const q = [{ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 3, y: 0 }];
console.assert(Math.abs(quadraticArcLength(q[0], q[1], q[2]) - 3.7546364123) < 1e-9);

// A straight-line quadratic has length equal to its endpoint distance.
console.assert(Math.abs(quadraticArcLength({ x: 0, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 2 }) - Math.SQRT2 * 2) < 1e-9);

const c = [{ x: 0, y: 0 }, { x: 1, y: 3 }, { x: 4, y: -2 }, { x: 5, y: 1 }];
console.assert(Math.abs(cubicArcLength(c) - 6.2147075374) < 1e-5);

const table = buildArcLengthTable(c);
for (let i = 0; i <= 10; i++) {
  const target = (i / 10) * table.length;
  const t = parameterAtLength(table, target, c);
  console.assert(Math.abs(cubicArcLengthTo(t, c) - target) < 1e-6);
}

Casos extremos e notas práticas

Linhas retas. Quando um ponto de controle quadrático fica exatamente no ponto médio de seus vizinhos, a curva colapsa em um segmento reto, e a corda entre as extremidades é o comprimento total. A ramificação quadrática trata esse caso diretamente. Uma cúbica cujos pontos de controle são colineares e cuja direção nunca se inverte também traça um segmento reto, e a quadratura retorna o valor correto porque a rapidez é constante ao longo da linha.

Pontos estacionários e cúspides. Uma curva cúbica pode ter um valor de parâmetro em que sua velocidade é zero, o que acontece quando a curva inverte a direção ou forma uma cúspide. A função de rapidez toca o zero ali e tem um canto afiado, e a quadratura gaussiana perde precisão. O método de subdivisão adaptativa acima é a escolha confiável para esses formatos.

Autointerseções. Uma cúbica em forma de laço cruza a si mesma, mas seu comprimento de arco continua contando após o cruzamento. Isso corresponde à distância que um ponto percorre, que geralmente é o que a animação e o deslocamento de curvas precisam. Se em vez disso você quer o comprimento do contorno visível, divida a curva no cruzamento e conte cada ramo uma vez.

Duas dimensões e três dimensões. As fórmulas usam apenas soma de vetores, produtos escalares e comprimentos, então o mesmo código funciona para pontos de controle em 2D e 3D. Um ponto de controle em 3D simplesmente tem um campo zz, e a rapidez ganha um terceiro termo ao quadrado.

Pré-calcule quando a forma é fixa. Uma tabela de comprimentos para um caminho estático pode ser construída uma vez e armazenada. Uma ferramenta que só lê o comprimento total pode dispensar a tabela por completo e chamar a quadratura, que é um punhado de multiplicações e raízes quadradas.

Inversão e simetria da curva. Inverter a ordem dos pontos de controle deixa o comprimento inalterado, e o mesmo vale para a forma fechada e a regra de quadratura. É uma verificação de sanidade útil quando uma curva é construída a partir de qualquer uma das extremidades.

Resumo

O comprimento de arco de uma curva de Bézier é a integral da rapidez ∣B′(t)∣|B'(t)| ao longo do intervalo do parâmetro. Para uma curva quadrática, a velocidade é linear em tt, então a rapidez é a raiz quadrada de um polinômio quadrático e a integral tem a forma fechada L=a(F(k+1)−F(k))L = \sqrt{a}(F(k+1) - F(k)) derivada acima. Para uma curva cúbica, a rapidez é a raiz quadrada de um polinômio de quarto grau, que não tem primitiva elementar, então uma regra de Gauss-Legendre de 16 pontos calcula o comprimento com cerca de seis dígitos significativos, e a subdivisão adaptativa cobre curvas com cantos. Inverter o comprimento acumulado dá a parametrização por comprimento, que uma tabela de consulta, uma busca binária e alguns passos de Newton implementam para o movimento com rapidez constante. O tutorial interativo de curvas de Bézier cobre a geometria dos pontos de controle por trás desses comprimentos.