Last updated on

Booglengteformule voor Bezier-krommen

ENNLESPT-BR


De booglengte van een Bezier-kromme is de totale afstand die een punt aflegt van het begin tot het einde van de kromme. Je krijgt die door de snelheid van dat punt te integreren, de lengte van de afgeleide van de kromme, over het parameterbereik. Een kwadratische Bezier-kromme heeft een exacte gesloten vorm. Een kubische Bezier-kromme heeft die over het algemeen niet, dus benaderen implementaties de lengte met numerieke kwadratuur. Deze pagina leidt de kwadratische formule af, bouwt de kubische benadering op en laat zien hoe je booglengte omzet in een lengteparametrisatie die een punt met constante snelheid voortbeweegt. De interactieve tutorial over Bezier-krommen behandelt de meetkunde van de controlepunten waarop alles hier voortbouwt.

Booglengte is de integraal van de snelheid

Een Bezier-kromme kent aan elke parameterwaarde tt tussen 00 en 11 een punt B(t)B(t) toe. Naarmate tt toeneemt, schuift dat punt langs de kromme. De snelheidsvector is de afgeleide B′(t)B'(t), een vector die in de bewegingsrichting wijst, en de snelheid is de lengte van die vector:

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

De snelheid meet de afgelegde afstand per eenheid van tt. Snelheid maal een infinitesimale stap dtdt geeft de afstand die tijdens die stap wordt afgelegd, dus door al die kleine stukjes op te tellen krijg je het totaal:

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

Hier is tt de parameter van de kromme, τ\tau een dummy-variabele van de integratie, s(t)s(t) de booglengte die vanaf het begin tot parameter tt is opgebouwd, en LL de volledige lengte van de kromme. De rechte lijn tussen de eindpunten is altijd korter dan de kromme, en de controleveelhoek, die de controlepunten met rechte segmenten verbindt, is altijd langer. De werkelijke lengte ligt tussen die twee grenzen en is gelijk aan de oppervlakte onder de snelheidskromme uitgezet tegen tt.

De belangrijke praktische consequentie is dat tt geen afstand is. Gelijke stappen in tt leveren ongelijke stappen in afstand op wanneer de snelheid langs de kromme verandert. Een renderer die gelijkmatig in tt samplet, plaatst meer punten waar de kromme langzaam is en minder waar ze snel is.

Het linkerpaneel is een bewerkbare kwadratische of kubische kromme. Het rechterpaneel zet de bijbehorende snelheid ∣B′(t)∣|B'(t)| uit tegen tt en arceert de oppervlakte eronder. Die gearceerde oppervlakte is de booglengte die in de hoek wordt weergegeven. Een controlepunt slepen verandert beide panelen tegelijk: de controlepunten uit elkaar trekken verhoogt de snelheidskromme en laat de oppervlakte groeien, terwijl een compacte vorm de kromme verlaagt en laat krimpen. Schakel over naar het kubische geval en de snelheidskromme kan meerdere bulten ontwikkelen, omdat de afgeleide van een kubische kromme een kwadratische polynoom is waarvan de lengte vrijer verandert dan de lineaire afgeleide van een kwadratische kromme.

De volledige lengte van een kwadratische Bezier-kromme vinden

Een kwadratische Bezier-kromme gebruikt drie punten en de formule

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

Differentiëren geeft de snelheidsvector:

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

Die uitdrukking is lineair in tt, wat de sleutel tot de gesloten vorm is. Verzamel het constante en het lineaire deel door twee nieuwe vectoren te definiëren:

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

Nu is de snelheidsvector eenvoudigweg

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

Je kunt dit controleren door 2At+B2At + B uit te werken: het is gelijk aan 2(1−t)(P1−P0)+2t(P2−P1)2(1-t)(P_1 - P_0) + 2t(P_2 - P_1), de afgeleide hierboven. Omdat de afgeleide een rechte lijn in tt is, is het kwadraat van de lengte een kwadratische polynoom:

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

met de drie scalaire coëfficiënten

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

De snelheid is de vierkantswortel van die kwadratische uitdrukking, en de lengte is de integraal ervan:

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

Om die te berekenen, maak je het kwadraat af binnen de wortel. Schrijf k=b/(2a)k = b / (2a) en m=c/a−k2m = c/a - k^2. Dan geldt

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

Substitutie van u=t+ku = t + k brengt de integraal in standaardvorm:

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

De primitieve van u2+m\sqrt{u^2 + m} voor m>0m > 0 is

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)

dus de exacte kwadratische booglengte is

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

De grootheid mm is nooit negatief voor een kwadratische Bezier-kromme. Het product (A⋅B)2(A \cdot B)^2 kan volgens de ongelijkheid van Cauchy-Schwarz nooit groter zijn dan (A⋅A)(B⋅B)(A \cdot A)(B \cdot B), en dat is precies de voorwaarde waaronder m≥0m \ge 0. Wanneer AA en BB evenwijdig zijn, is mm nul, wordt de logaritme singulier en vereenvoudigt de wortel tot a ∣t+k∣\sqrt{a},|t + k|. De integraal van de absolute waarde is eenvoudig stuksgewijs te berekenen.

Uitgewerkt voorbeeld

Neem P0=(0,0)P_0 = (0,0), P1=(1,2)P_1 = (1,2) en P2=(3,0)P_2 = (3,0). Dan

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)

De coëfficiënten zijn a=4(1+16)=68a = 4(1 + 16) = 68, b=4(2−16)=−56b = 4(2 - 16) = -56 en c=4+16=20c = 4 + 16 = 20. De verschuiving is

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

en de offset is

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

Het evalueren van FF op de twee eindpunten geeft F(1+k)≈0.2169F(1 + k) \approx 0.2169 en F(k)≈−0.2385F(k) \approx -0.2385. Met a≈8.2462\sqrt{a} \approx 8.2462 is de lengte

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

Kwadratische booglengte in code

Deze functie geeft de exacte lengte terug, inclusief de gevallen van een rechte lijn en een evenwijdige snelheidsvector:

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));
}

De tak a === 0 treedt op wanneer P1P_1 het midden is van P0P_0 en P2P_2, waardoor de kromme tot een recht lijnstuk samenvouwt. De tak met bijna-nul discriminant vangt de situatie op waarin de snelheidsvector op één lijn blijft maar van richting kan omkeren, zodat de kromme heen en terug beweegt. Voor het gangbare geval draait de gesloten vorm in constante tijd zonder sampling.

Waarom de booglengte van een kubische Bezier geen gesloten vorm heeft

Een kubische Bezier-kromme gebruikt vier punten:

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

De afgeleide ervan is

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)

Elke term is een vector maal een kwadratische polynoom in tt, dus B′(t)B'(t) is een vector van graad twee en ∣B′(t)∣2|B'(t)|^2 is één enkele vierdegraadspolynoom in tt. De snelheid is de vierkantswortel van die vierdegraadspolynoom. Integralen van de vierkantswortel van een algemene vierdegraadspolynoom zijn elliptische integralen, en elliptische integralen hebben geen uitdrukking in elementaire functies. Er bestaat geen logaritmische of wortelformule die elke kubische kromme dekt zoals de kwadraatafsplitsingsformule elke kwadratische kromme dekt.

Dat betekent niet dat de lengte onkenbaar is. Het betekent dat de lengte moet worden berekend in plaats van opgezocht, en het standaardgereedschap daarvoor is Gauss-kwadratuur.

De booglengte van een kubische Bezier benaderen

Gauss-Legendre-kwadratuur benadert een bepaalde integraal door de integrand op een klein aantal punten te sampelen en een gewogen som te nemen:

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

De punten xix_i zijn de wortels van de nn-de Legendre-polynoom, en de gewichten wiw_i zijn zo gekozen dat de regel exact is voor elke polynoom tot graad 2n−12n - 1. Ons interval is [0,1][0,1] in plaats van [−1,1][-1,1], dus substitueren we t=(x+1)/2t = (x + 1)/2, wat geeft

∫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)

Zestien punten maken de regel exact voor polynomen tot graad 31. Snelheid is een vierkantswortel en geen polynoom, dus de regel is niet exact, maar voor een gladde snelheidsfunctie komen 16 punten al binnen enkele delen op een miljoen van de werkelijke lengte uit.

// 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;
}

Dezelfde hulpfunctie werkt wanneer de kwadratuur de lengte van het begin tot een willekeurige parameter tt nodig heeft in plaats van de hele kromme. Behoud de abscissen en gewichten en schaal het interval naar [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;
}

Hoe nauwkeurig is de kwadratuur?

De tabel vergelijkt de regel met een referentie met hoge precisie voor drie kubische krommen. De fouten zijn absoluut.

Controlepunten van de kubische kromme Werkelijke lengte 8 punten 16 punten 24 punten
(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}

De eerste twee krommen hebben gladde snelheidsprofielen, en 16 punten zijn ruim voldoende. De derde kromme keert op zichzelf terug, waardoor haar snelheid tot nul daalt en de snelheidsfunctie een hoek krijgt. Kwadratuur convergeert langzaam bij een hoek, en meer punten toevoegen helpt nauwelijks. De oplossing is om het parameterbereik op het lastige punt te splitsen en elk stuk apart te integreren, of om de onderverdelingsmethode hieronder te gebruiken.

Adaptieve onderverdeling als alternatief

Het algoritme van De Casteljau kan een kubisch segment bij elke parameterwaarde in twee kleinere kubische segmenten splitsen, en splitsen bij 0.50.5 is bijzonder eenvoudig: middel naburige controlepunten totdat één punt overblijft. De controleveelhoek van een klein stukje is bijna een rechte lijn, dus zowel de lengte ervan als de koordelengte tussen de eindpunten liggen dicht bij de werkelijke booglengte. Het verschil ertussen meet hoe gebogen het stukje nog is. Wanneer het verschil onder een tolerantie ligt, geef je het gemiddelde van de twee terug; anders splits je en ga je recursief verder.

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)
  );
}

Adaptieve onderverdeling kost meer evaluaties dan één enkele 16-puntsregel, maar concentreert het werk waar de kromme buigt en blijft werken bij krommen met hoeken of bijna-cuspen. De kwadratuurregel is sneller voor de gladde krommen die in de meeste rendering- en animatiewerk voorkomen, en onderverdeling is de veilige terugvaloptie wanneer een tolerantie gegarandeerd moet worden.

Lengteparametrisatie van een Bezier-kromme

Alles tot nu toe berekent de lengte uit de parameter. De omgekeerde vraag, het vinden van de parameter die bij een gegeven afstand hoort, is wat beweging met constante snelheid mogelijk maakt. Definieer de opgebouwde-lengtefunctie

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

Omdat snelheid nooit negatief is, stijgt s(t)s(t) gelijkmatig van 00 naar LL terwijl tt van 00 naar 11 gaat, dus de functie kan worden geïnverteerd. De inverse, geschreven als t(s)t(s), is de lengteparametrisatie: geef er een afstand aan en ze geeft de parameter terug die het punt precies zo ver langs de kromme plaatst. De voorwaartse richting heeft een gesloten vorm voor kwadratische krommen en een kwadratuurregel voor kubische krommen, maar geen van beide inversen heeft in het algemeen een elementaire uitdrukking, dus bouwen implementaties een tabel op en interpoleren ze.

Het recept bestaat uit drie stappen. Sample s(t)s(t) op veel gelijkmatig verdeelde tt-waarden en sla de paren op. Om een doelfstand naar een parameter om te zetten, zoek je in de tabel binair naar het omringende paar en interpoleer je lineair. Omdat de tabel slechts een stuksgewijs lineaire benadering van een gladde functie is, sluit je af met een of twee Newton-stappen. De methode van Newton vindt een nulpunt van s(t)−stargets(t) - s_{\text{target}} met de afgeleide s′(t)=∣B′(t)∣s'(t) = |B'(t)|, precies de snelheid die al beschikbaar is.

Beide panelen tonen dezelfde kubische kromme. Het linkerpaneel plaatst een stip bij elke tiende van het parameterbereik, en het rechterpaneel plaatst een stip bij elke tiende van de totale booglengte. Een controlepunt slepen hervormt beide panelen samen. Waar de kromme langzaam beweegt, kruipen de parametermarkeringen samen, en waar ze snel beweegt, spreiden ze uiteen. De booglengtemarkeringen blijven gelijkmatig verdeeld omdat de tabel elke gelijke afstand terugvertaalt naar de parameter die die afstand bereikt. De rode markeringen doorlopen beide krommen in dezelfde tijd. De linker markering versnelt en vertraagt met de parameter, en de rechter markering beweegt in een gelijkmatig tempo.

De lengtetabel opbouwen en inverteren

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;
}

De tabel wordt één keer per krommevorm opgebouwd. Het wijzigen van een controlepunt maakt de tabel ongeldig, maar een punt langs de kromme verplaatsen tijdens runtime voert alleen opzoekingen uit. Om een object met constante snelheid vv te verplaatsen, verhoog je de afstand met vv maal de verstreken tijd en roep je parameterAtLength aan met het resultaat:

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.
}

Zonder de tabelopzoekingen zou het direct verhogen van de parameter het object door de snelle delen van de kromme laten schokken en door de langzame delen laten kruipen.

De implementatie controleren

Een paar asserties dekken de belangrijkste takken. De kwadratische gesloten vorm zou moeten overeenkomen met de kwadratuurregel op dezelfde kromme, omdat de kwadratuurregel op deze schaal nauwkeurig genoeg is. De heen-en-terugreis door de tabel zou de oorspronkelijke afstand moeten teruggeven nadat je naar een parameter en terug hebt omgezet.

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);
}

Randgevallen en praktische opmerkingen

Rechte lijnen. Wanneer een kwadratisch controlepunt precies op het midden van zijn buren ligt, valt de kromme samen met een recht lijnstuk, en is de koorde tussen de eindpunten de volledige lengte. De kwadratische tak behandelt dit geval rechtstreeks. Een kubische kromme waarvan de controlepunten collineair zijn en waarvan de richting nooit omkeert, doorloopt ook een recht lijnstuk, en de kwadratuur geeft de juiste waarde terug omdat de snelheid langs de lijn constant is.

Stationaire punten en cuspen. Een kubische kromme kan een parameterwaarde hebben waarop haar snelheidsvector nul is, wat gebeurt wanneer de kromme van richting verandert of een cusp vormt. De snelheidsfunctie raakt daar nul en heeft een scherpe hoek, en Gauss-kwadratuur verliest nauwkeurigheid. De adaptieve onderverdelingsmethode hierboven is de betrouwbare keuze voor deze vormen.

Zelfsnijdingen. Een lusvormige kubische kromme snijdt zichzelf, maar haar booglengte blijft na de kruising doorlopen. Dat komt overeen met de afstand die een punt aflegt, wat meestal is wat animatie en offsetting nodig hebben. Wil je in plaats daarvan de lengte van de zichtbare omtrek, splits de kromme dan op de kruising en tel elke tak één keer mee.

Twee en drie dimensies. De formules gebruiken alleen vectoroptelling, inwendige producten en lengtes, dus dezelfde code werkt voor 2D- en 3D-controlepunten. Een 3D-controlepunt heeft eenvoudigweg een zz-veld, en de snelheid krijgt er een derde kwadraatterm bij.

Vooraf berekenen wanneer de vorm vastligt. Een lengtetabel voor een statisch pad kan één keer worden opgebouwd en opgeslagen. Een hulpmiddel dat alleen de totale lengte leest, kan de tabel helemaal overslaan en de kwadratuur aanroepen, wat neerkomt op een handvol vermenigvuldigingen en vierkantswortels.

Omkering en symmetrie van de kromme. Het omkeren van de volgorde van de controlepunten laat de lengte onveranderd, en dat geldt ook voor de gesloten vorm en de kwadratuurregel. Dit is een nuttige sanity check wanneer een kromme vanaf beide uiteinden wordt opgebouwd.

Samenvatting

De booglengte van een Bezier-kromme is de integraal van de snelheid ∣B′(t)∣|B'(t)| over het parameterbereik. Voor een kwadratische kromme is de snelheidsvector lineair in tt, dus de snelheid is de vierkantswortel van een kwadratische polynoom en heeft de integraal de gesloten vorm L=a(F(k+1)−F(k))L = \sqrt{a}(F(k+1) - F(k)) die hierboven is afgeleid. Voor een kubische kromme is de snelheid de vierkantswortel van een vierdegraadspolynoom, die geen elementaire primitieve heeft, dus berekent een 16-punts Gauss-Legendre-regel de lengte tot ongeveer zes significante cijfers, en dekt adaptieve onderverdeling krommen met hoeken. Het inverteren van de opgebouwde lengte geeft de lengteparametrisatie, die een opzoektabel, binair zoeken en een paar Newton-stappen implementeren voor beweging met constante snelheid. De interactieve tutorial over Bezier-krommen behandelt de meetkunde van de controlepunten achter deze lengtes.