Lunghezza dell'arco della curva di Bezier


23

Vedi anche: stessa domanda su Math.SE

Come posso trovare la lunghezza di una curva di Bezier? Ad esempio, una curva lineare di Bezier ha la lunghezza:

length = sqrt(pow(x[1] - x[0], 2) + pow(y[1] - y[0], 2));

Ma che dire delle curve di Bezier quadratiche, cubiche o di grado n?

(Il mio obiettivo era stimare in anticipo una risoluzione di campionamento, quindi non devo perdere tempo a controllare se il punto successivo tocca il punto precedente.)


1
Dovresti riformulare la domanda per fare riferimento alla lunghezza della curva, che è un termine molto più semplice (e ricercabile).
Sparr,

ti suggerisco di postare questo in matematica, sono sicuro che qualche faccia intelligente laggiù ti darà la risposta in uno di quei caratteri web intelligenti: p
Tor Valamo,

2
@Tor l'ho fatto (ieri), ma mi è stato detto che è molto complicato, e quindi poco pratico. [ math.stackexchange.com/q/12186/2736 ]
Mateen Ulhaq,

Presumibilmente le curve / spline di Clothoid sono un'alternativa ai bezier e hanno espressioni di arclength a forma chiusa, ma non ne so ancora molto. (Cercando di generare punti di uguale distanza lungo una curva.) I catenari hanno anche espressioni di lunghezza d'arco in forma chiusa?
Endolith,

Risposte:


9

Un modo semplice per Beziers cubici è dividere la curva in N segmenti e sommare le lunghezze dei segmenti.

Tuttavia, non appena sarà necessaria la lunghezza di solo una parte della curva (ad es. Fino a un punto del 30% della lunghezza), entrerà in gioco la parametrizzazione della lunghezza dell'arco . Ho pubblicato una risposta abbastanza lunga su una delle mie domande su Béziers, con un semplice codice di esempio.


Lo sto facendo per il LEGO Mindstorms NXT, che ha un processore davvero debole (48Mhz), quindi ho bisogno della massima velocità possibile. Prenderò l'approccio di divisione per conservare un po 'di velocità e renderlo abbastanza accurato (per il rendering "non in tempo reale"). Ho anche un'opzione in cui puoi impostare il valore di 1.0/t(chiamato resolution), quindi è per "realtime" (che è al massimo 10 fps sul NXT lento). t += resolutionViene disegnata ogni iterazione e un nuovo punto / linea. Comunque, grazie per l'idea.
Mateen Ulhaq,

4

Mentre sono d'accordo con le risposte che hai già, voglio aggiungere un semplice ma potente meccanismo di approssimazione che puoi usare per qualsiasi grado di curve di Bézier: Suddividi continuamente la curva usando la suddivisione de Casteljau fino alla distanza massima dei punti di controllo di una curva secondaria rispetto alla linea di base della curva secondaria è al di sotto di un epsilon costante . In tal caso, la curva secondaria può essere approssimata dalla sua linea di base.

In realtà, credo che questo sia l'approccio generalmente adottato quando un sottosistema grafico deve disegnare una curva di Bézier. Ma non citarmi su questo, al momento non ho riferimenti a portata di mano.

In pratica sembrerà così: (tranne che la lingua è irrilevante)

public static Line[] toLineStrip(BezierCurve bezierCurve, double epsilon) {
    ArrayList<Line> lines = new ArrayList<Line>();

    Stack<BezierCurve> parts = new Stack<BezierCurve>();
    parts.push(bezierCurve);

    while (!parts.isEmpty()) {
        BezierCurve curve = parts.pop();
        if (distanceToBaseline(curve) < epsilon) {
            lines.add(new Line(curve.get(0), curve.get(1)));
        } else {
            parts.addAll(curve.split(0.5));
        }
    }

    return lines.toArray(new Line[0]);
}

Mentre questo è un buon approccio, ho sentito parlare di instabilità numerica nelle curve di Bezier di alto ordine, che richiedono un'altra idea: dividere le curve di ordine superiore in curve cubiche più piccole.
Mateen Ulhaq,

Inoltre, se l'obiettivo finale è una stima accurata, potrebbe essere una buona idea approssimarsi con la quadratica anziché con le linee per assicurarsi che non sottovalutiamo la nostra stima in punti di alta curvatura.
Mateen Ulhaq,

2

Le lunghezze dell'arco per le curve di Bezier sono solo forme chiuse per quelle lineari e quadratiche. Per i cubi, non è garantito avere una soluzione chiusa. Il motivo è che la lunghezza dell'arco è definita da un integrale radicale, per il quale è chiuso solo per polinomi di 2 ° grado.

Solo per riferimento: la lunghezza di un Bezier quadratico per i punti (a, p) (b, q) e (c, r) è

(a ^ 2 · (q ^ 2 - 2 · q · r + r ^ 2) + 2 · a · (r - q) · (b · (p - r) + c · (q - p)) + ( b · (p - r) + c · (q - p)) ^ 2) · LN ((√ (a ^ 2 - 2 · a · b + b ^ 2 + p ^ 2 - 2 · p · q + q ^ 2) · √ (a ^ 2 + 2 · a · (c - 2 · b) + 4 · b ^ 2 - 4 · b · c + c ^ 2 + (p - 2 · q + r) ^ 2) + a ^ 2 + a · (c - 3 · b) + 2 · b ^ 2 - b · c + (p - q) · (p - 2 · q + r)) / (√ (a ^ 2 + 2 · A · (c - 2 · b) + 4 · b ^ 2 - 4 · b · c + c ^ 2 + (p - 2 · q + r) ^ 2) · √ (b ^ 2 - 2 · b · c + c ^ 2 + q ^ 2 - 2 · q · r + r ^ 2) + a · (b - c) - 2 · b ^ 2 + 3 · b · c - c ^ 2 + (p - 2 · q + r) · (q - r))) / (a ​​^ 2 + 2 · a · (c - 2 · b) + 4 · b ^ 2 - 4 · b · c + c ^ 2 + (p - 2 · Q + r) ^ 2) ^ (3/2) + (√ (a ^ 2 - 2 · a · b + b ^ 2 + p ^ 2 - 2 · p · q + q ^ 2) · (a ^ 2 + a · (c - 3 · b) + 2 · b ^ 2 - b · c + (p - q) · (p - 2 · q + r)) - √ (b ^ 2 - 2 · b · c + c ^ 2 + q ^ 2 - 2 · q · r + r ^ 2) · (a · (b - c) - 2 · b ^ 2 + 3 · b · c - c ^ 2 + (p - 2 · q + r) · (q - r))) / (a ​​^ 2 + 2 · a · (c - 2 · b) + 4 · b ^ 2 - 4 · b · c + c ^ 2 + (p - 2 · Q + r) ^ 2)

Dove LN è il logaritmo naturale e ^ indica potenza e √ la radice quadrata.

Quindi, dovrebbe essere più facile ed economico approssimare l'arco con qualche altra regola, come un poligono o uno schema di integrazione come la regola di Simpson, perché le radici quadrate della LN sono operazioni costose.


2

Ho elaborato l'espressione a forma chiusa di lunghezza per un Bezier a 3 punti (sotto). Non ho tentato di elaborare un modulo chiuso per 4+ punti. Molto probabilmente questo sarebbe difficile o complicato da rappresentare e gestire. Tuttavia, una tecnica di approssimazione numerica come un algoritmo di integrazione di Runge-Kutta funzionerebbe abbastanza bene integrandosi usando la formula della lunghezza dell'arco . Le mie domande e risposte su RK45 su MSE possono aiutare con l'implementazione di RK45.

Ecco un po 'di codice Java per la lunghezza arco di 3 punti di Bezier, con i punti a, be c.

    v.x = 2*(b.x - a.x);
    v.y = 2*(b.y - a.y);
    w.x = c.x - 2*b.x + a.x;
    w.y = c.y - 2*b.y + a.y;

    uu = 4*(w.x*w.x + w.y*w.y);

    if(uu < 0.00001)
    {
        return (float) Math.sqrt((c.x - a.x)*(c.x - a.x) + (c.y - a.y)*(c.y - a.y));
    }

    vv = 4*(v.x*w.x + v.y*w.y);
    ww = v.x*v.x + v.y*v.y;

    t1 = (float) (2*Math.sqrt(uu*(uu + vv + ww)));
    t2 = 2*uu+vv;
    t3 = vv*vv - 4*uu*ww;
    t4 = (float) (2*Math.sqrt(uu*ww));

    return (float) ((t1*t2 - t3*Math.log(t2+t1) -(vv*t4 - t3*Math.log(vv+t4))) / (8*Math.pow(uu, 1.5)));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.