Bezier eğrisi yay uzunluğu


23

Ayrıca bakınız: Math.SE'de aynı soru

Bezier eğrisinin yayını nasıl bulabilirim? Örneğin, doğrusal bir Bezier eğrisi uzunluğa sahiptir:

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

Peki ya ikinci dereceden, kübik veya n derece Bezier eğrileri?

(Amacım önceden bir örnekleme çözünürlüğü tahmin etmekti, bu yüzden bir sonraki noktanın önceki noktaya dokunup dokunmadığını kontrol etmekle zaman kaybetmek zorunda kalmam.)


1
Eğrinin uzunluğuna atıfta bulunmak için soruyu yanıtlamalısınız, bu çok daha basit (ve aranabilir) bir terimdir.
Sparr

Bunu matematiğe göndermeyi öneriyorum, oradaki bazı akıllı yüzlerin size akıllı web fontlarından birinde cevap vereceğinden eminim: p
Tor Valamo

2
@ Çünkü (dün) yaptım ama bana çok karmaşık ve dolayısıyla pratik olmadığı söylendi. [ math.stackexchange.com/q/12186/2736 ]
Mateen Ulhaq

Sözde clothoid eğrileri / spline'ları bebek bezlerine bir alternatif ve kapalı formda arkcleng ifadeleri var, ancak henüz bu konuda çok fazla bilgim yok. (Bir eğri boyunca eşit mesafe noktaları oluşturmaya çalışılıyor.) Katenerlerin ayrıca kapalı formda yay uzunluğu ifadeleri var mı?
Endolit

Yanıtlar:


9

Kübik Beziers için basit bir yol, eğriyi N segmentlere ayırmak ve segmentlerin uzunluklarını toplamaktır.

Bununla birlikte, eğrinin sadece bir kısmının uzunluğuna ihtiyaç duyduğunuzda (örneğin, uzunluğun% 30'una kadar bir noktaya kadar), yay uzunluğu parametresi devreye girecektir. Ben yayınlanmıştır oldukça uzun bir cevap basit örnek kodla, Bézierstam hakkında kendi sorulardan biri.


Bunu, gerçekten zayıf bir işlemciye (48Mhz) sahip olan LEGO Mindstorms NXT için yapıyorum, bu yüzden mümkün olduğunca fazla hıza ihtiyacım var. Bazı hızlardan tasarruf etmek için bölme yaklaşımını kullanacağım ve bunu yeterince doğru hale getireceğim (“gerçek zamanlı olmayan” render için). Ayrıca 1.0/t(çağrılan resolution) değerini ayarlayabileceğiniz bir seçeneğim var , bu yüzden "gerçek zamanlı" (yavaş NXT'de en iyi 10 kare / sn). Her yineleme, t += resolutionve yeni bir nokta / çizgi çizilir. Neyse, fikir için teşekkürler.
Mateen Ulhaq

4

Zaten aldığınız cevapları benimsediğimde, herhangi bir derece Bézier eğrisi için kullanabileceğiniz basit ama güçlü bir yaklaşım mekanizması eklemek istiyorum: Kontrol noktasının maksimum mesafesine kadar de Casteljau alt bölmesini kullanarak eğriyi sürekli olarak bölüyorsunuz alt eğrinin taban çizgisine giden bir alt eğrinin bir kısmı sabit epsilonun altındadır . Bu durumda, alt eğri taban çizgisine göre yaklaştırılabilir.

Aslında, bunun bir grafik altsisteminin bir Bézier eğrisi çizmesi gerektiğinde, genellikle uygulanan yaklaşım olduğuna inanıyorum. Ama benden alıntı yapma, şu anda elimde referans yok.

Uygulamada şöyle görünecektir: (dilin alakasız olması dışında)

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

Bu iyi bir yaklaşım olsa da, başka bir fikir gerektiren yüksek dereceli Bezier eğrilerinde sayısal dengesizlik duydum: yüksek dereceli eğrileri daha küçük kübik eğrilere bölmek.
Mateen Ulhaq

Ayrıca, eğer nihai hedef doğru bir tahmin ise, yüksek eğriliğe sahip konumlardaki tahmininizin anlaşılmamasını sağlamak için çizgiler yerine kuadratiklerle yaklaşmak iyi bir fikir olabilir.
Mateen Ulhaq

2

Bezier eğrilerinin yay uzunluğu sadece doğrusal ve ikinci dereceden olanlar için kapalı formdadır. Kübikler için kapalı bir çözüme sahip olması garanti edilemez. Sebep yay uzunluğu, sadece 2. derece polinomlar için kapalı olan radikal bir integral ile tanımlanır.

Sadece referans için: (a, p) (b, q) ve (c, r) noktaları için ikinci dereceden bir Bezier uzunluğu

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

LN'nin doğal logaritma olduğu ve ^ gücü ve karekökü ifade eder.

Bu nedenle, bir poligon veya Simpson'ın kuralı gibi bir entegrasyon şeması gibi yayı başka bir kuralla yaklaştırmak daha kolay ve ucuz olmalıdır, çünkü LN'nin kare kökleri pahalı işlemlerdir.


2

3 puanlık Bezier (aşağıda) için kapalı uzunluktaki ifadeyi çalıştım. 4+ puan için kapalı bir form oluşturma girişiminde bulunmadım. Bu büyük olasılıkla temsil ve idare etmek zor olabilir. Bununla birlikte, Runge-Kutta entegrasyon algoritması gibi sayısal bir yaklaşım tekniği, yay uzunluğu formülünü kullanarak bütünleşerek oldukça iyi çalışacaktır . RK45'teki Soru ve Cevaplarım , RK45 uygulamasına yardımcı olabilir.

Burada puanla 3 puanlı Bezier yayı uzunluğu için bazı Java kodu vardır a, bve 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)));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.