2015-08-01 14 views
7

Der quadratische/kubische Bézier-Kurvencode, den ich über Google finde, funktioniert meistens, indem er die Linie in eine Reihe von Punkten unterteilt und sie mit Geraden verbindet. Die Rasterung geschieht im Zeilenalgorithmus, nicht im Bézier. Algorithmen wie Bresenham arbeiten Pixel für Pixel, um eine Linie zu rastern und können optimiert werden (siehe Po-Han Lin's solution).Pixel für Pixel Bézier Curve

Was ist ein quadratischer Bézier-Kurven-Algorithmus, der pixelweise wie Linienalgorithmen arbeitet, anstatt eine Reihe von Punkten zu zeichnen?

+0

Es ist eine sehr gute Frage, aber ich bin mir nicht sicher, ob es eine Antwort hat. Ein Bezier wird nicht aus seiner X- oder Y-Koordinate berechnet, sondern aus einer unabhängigen Variablen T, die nicht mit einer der beiden korreliert ist. –

+0

Ich spekulierte, dass man die Schrittlänge in Béziers Parametergleichung so berechnen könnte, dass sie ein Pixel lang wäre, dann zeichne jeden Schritt auf, aber die Längenberechnung für einen Bézier ist verrückt teuer. – nebuch

+0

Der teure Teil der Längenberechnungen ist 'Math.sqrt'. Stattdessen können Sie (1) Punkte entlang der Kurve zeichnen, (2) jedes [x, y] in ganze Zahlen umwandeln, (3) wenn die aktuell berechnete ganze Zahl [x, y] nicht mit der vorher berechneten Ganzzahl [x] übereinstimmt , y] dann ist die aktuelle [x, y] eindeutig und sollte zu der Lösungsmenge von Punkten entlang der Kurve hinzugefügt werden. Ich habe ein Beispiel für diese relativ effiziente Lösung veröffentlicht. :-) – markE

Antwort

5

Eine Variante des Bresenham-Algorithmus arbeitet mit quadratischen Funktionen wie Kreise, Ellipsen und Parabeln, so es sollte auch mit quadratischen Bezier-Kurven arbeiten.

Ich wollte eine Implementierung versuchen, aber dann habe ich eine im Internet gefunden: http://members.chello.at/~easyfilter/bresenham.html.

Wenn Sie weitere Einzelheiten oder zusätzliche Beispiele wünschen, enthält die oben genannte Seite einen Link zu einer 100-seitigen PDF-Datei zur Methode: http://members.chello.at/~easyfilter/Bresenham.pdf.

Hier ist der Code von Alois Zingls Website zum Zeichnen einer beliebigen quadratischen Bezier-Kurve. Die erste Routine unterteilt die Kurve bei horizontalen und vertikalen Gradienten ändert:

void plotQuadBezier(int x0, int y0, int x1, int y1, int x2, int y2) 
{ /* plot any quadratic Bezier curve */ 
    int x = x0-x1, y = y0-y1; 
    double t = x0-2*x1+x2, r; 
    if ((long)x*(x2-x1) > 0) { /* horizontal cut at P4? */ 
    if ((long)y*(y2-y1) > 0) /* vertical cut at P6 too? */ 
     if (fabs((y0-2*y1+y2)/t*x) > abs(y)) { /* which first? */ 
     x0 = x2; x2 = x+x1; y0 = y2; y2 = y+y1; /* swap points */ 
     } /* now horizontal cut at P4 comes first */ 
    t = (x0-x1)/t; 
    r = (1-t)*((1-t)*y0+2.0*t*y1)+t*t*y2; /* By(t=P4) */ 
    t = (x0*x2-x1*x1)*t/(x0-x1); /* gradient dP4/dx=0 */ 
    x = floor(t+0.5); y = floor(r+0.5); 
    r = (y1-y0)*(t-x0)/(x1-x0)+y0; /* intersect P3 | P0 P1 */ 
    plotQuadBezierSeg(x0,y0, x,floor(r+0.5), x,y); 
    r = (y1-y2)*(t-x2)/(x1-x2)+y2; /* intersect P4 | P1 P2 */ 
    x0 = x1 = x; y0 = y; y1 = floor(r+0.5); /* P0 = P4, P1 = P8 */ 
    } 
    if ((long)(y0-y1)*(y2-y1) > 0) { /* vertical cut at P6? */ 
    t = y0-2*y1+y2; t = (y0-y1)/t; 
    r = (1-t)*((1-t)*x0+2.0*t*x1)+t*t*x2; /* Bx(t=P6) */ 
    t = (y0*y2-y1*y1)*t/(y0-y1); /* gradient dP6/dy=0 */ 
    x = floor(r+0.5); y = floor(t+0.5); 
    r = (x1-x0)*(t-y0)/(y1-y0)+x0; /* intersect P6 | P0 P1 */ 
    plotQuadBezierSeg(x0,y0, floor(r+0.5),y, x,y); 
    r = (x1-x2)*(t-y2)/(y1-y2)+x2; /* intersect P7 | P1 P2 */ 
    x0 = x; x1 = floor(r+0.5); y0 = y1 = y; /* P0 = P6, P1 = P7 */ 
    } 
    plotQuadBezierSeg(x0,y0, x1,y1, x2,y2); /* remaining part */ 
} 

die zweite Routine zeichnet tatsächlich ein Bezier-Kurvensegment (ein ohne Steigung ändert):

void plotQuadBezierSeg(int x0, int y0, int x1, int y1, int x2, int y2) 
{ /* plot a limited quadratic Bezier segment */ 
    int sx = x2-x1, sy = y2-y1; 
    long xx = x0-x1, yy = y0-y1, xy; /* relative values for checks */ 
    double dx, dy, err, cur = xx*sy-yy*sx; /* curvature */ 
    assert(xx*sx <= 0 && yy*sy <= 0); /* sign of gradient must not change */ 
    if (sx*(long)sx+sy*(long)sy > xx*xx+yy*yy) { /* begin with longer part */ 
    x2 = x0; x0 = sx+x1; y2 = y0; y0 = sy+y1; cur = -cur; /* swap P0 P2 */ 
    } 
    if (cur != 0) { /* no straight line */ 
    xx += sx; xx *= sx = x0 < x2 ? 1 : -1; /* x step direction */ 
    yy += sy; yy *= sy = y0 < y2 ? 1 : -1; /* y step direction */ 
    xy = 2*xx*yy; xx *= xx; yy *= yy; /* differences 2nd degree */ 
    if (cur*sx*sy < 0) { /* negated curvature? */ 
     xx = -xx; yy = -yy; xy = -xy; cur = -cur; 
    } 
    dx = 4.0*sy*cur*(x1-x0)+xx-xy; /* differences 1st degree */ 
    dy = 4.0*sx*cur*(y0-y1)+yy-xy; 
    xx += xx; yy += yy; err = dx+dy+xy; /* error 1st step */ 
    do { 
     setPixel(x0,y0); /* plot curve */ 
     if (x0 == x2 && y0 == y2) return; /* last pixel -> curve finished */ 
     y1 = 2*err < dx; /* save value for test of y step */ 
     if (2*err > dy) { x0 += sx; dx -= xy; err += dy += yy; } /* x step */ 
     if (y1) { y0 += sy; dy -= xy; err += dx += xx; } /* y step */ 
    } while (dy < 0 && dx > 0); /* gradient negates -> algorithm fails */ 
    } 
    plotLine(x0,y0, x2,y2); /* plot remaining part to end */ 
} 

-Code für Anti-Aliasing ist auch verfügbar der Standort.

Die entsprechenden Funktionen von Zingl Website für kubische Bezier-Kurven sind

void plotCubicBezier(int x0, int y0, int x1, int y1, 
    int x2, int y2, int x3, int y3) 
{ /* plot any cubic Bezier curve */ 
    int n = 0, i = 0; 
    long xc = x0+x1-x2-x3, xa = xc-4*(x1-x2); 
    long xb = x0-x1-x2+x3, xd = xb+4*(x1+x2); 
    long yc = y0+y1-y2-y3, ya = yc-4*(y1-y2); 
    long yb = y0-y1-y2+y3, yd = yb+4*(y1+y2); 
    float fx0 = x0, fx1, fx2, fx3, fy0 = y0, fy1, fy2, fy3; 
    double t1 = xb*xb-xa*xc, t2, t[5]; 
    /* sub-divide curve at gradient sign changes */ 
    if (xa == 0) { /* horizontal */ 
    if (abs(xc) < 2*abs(xb)) t[n++] = xc/(2.0*xb); /* one change */ 
    } else if (t1 > 0.0) { /* two changes */ 
    t2 = sqrt(t1); 
    t1 = (xb-t2)/xa; if (fabs(t1) < 1.0) t[n++] = t1; 
    t1 = (xb+t2)/xa; if (fabs(t1) < 1.0) t[n++] = t1; 
    } 
    t1 = yb*yb-ya*yc; 
    if (ya == 0) { /* vertical */ 
    if (abs(yc) < 2*abs(yb)) t[n++] = yc/(2.0*yb); /* one change */ 
    } else if (t1 > 0.0) { /* two changes */ 
    t2 = sqrt(t1); 
    t1 = (yb-t2)/ya; if (fabs(t1) < 1.0) t[n++] = t1; 
    t1 = (yb+t2)/ya; if (fabs(t1) < 1.0) t[n++] = t1; 
    } 
    for (i = 1; i < n; i++) /* bubble sort of 4 points */ 
    if ((t1 = t[i-1]) > t[i]) { t[i-1] = t[i]; t[i] = t1; i = 0; } 
    t1 = -1.0; t[n] = 1.0; /* begin/end point */ 
    for (i = 0; i <= n; i++) { /* plot each segment separately */ 
    t2 = t[i]; /* sub-divide at t[i-1], t[i] */ 
    fx1 = (t1*(t1*xb-2*xc)-t2*(t1*(t1*xa-2*xb)+xc)+xd)/8-fx0; 
    fy1 = (t1*(t1*yb-2*yc)-t2*(t1*(t1*ya-2*yb)+yc)+yd)/8-fy0; 
    fx2 = (t2*(t2*xb-2*xc)-t1*(t2*(t2*xa-2*xb)+xc)+xd)/8-fx0; 
    fy2 = (t2*(t2*yb-2*yc)-t1*(t2*(t2*ya-2*yb)+yc)+yd)/8-fy0; 
    fx0 -= fx3 = (t2*(t2*(3*xb-t2*xa)-3*xc)+xd)/8; 
    fy0 -= fy3 = (t2*(t2*(3*yb-t2*ya)-3*yc)+yd)/8; 
    x3 = floor(fx3+0.5); y3 = floor(fy3+0.5); /* scale bounds to int */ 
    if (fx0 != 0.0) { fx1 *= fx0 = (x0-x3)/fx0; fx2 *= fx0; } 
    if (fy0 != 0.0) { fy1 *= fy0 = (y0-y3)/fy0; fy2 *= fy0; } 
    if (x0 != x3 || y0 != y3) /* segment t1 - t2 */ 
     plotCubicBezierSeg(x0,y0, x0+fx1,y0+fy1, x0+fx2,y0+fy2, x3,y3); 
    x0 = x3; y0 = y3; fx0 = fx3; fy0 = fy3; t1 = t2; 
    } 
} 

und

void plotCubicBezierSeg(int x0, int y0, float x1, float y1, 
    float x2, float y2, int x3, int y3) 
{ /* plot limited cubic Bezier segment */ 
    int f, fx, fy, leg = 1; 
    int sx = x0 < x3 ? 1 : -1, sy = y0 < y3 ? 1 : -1; /* step direction */ 
    float xc = -fabs(x0+x1-x2-x3), xa = xc-4*sx*(x1-x2), xb = sx*(x0-x1-x2+x3); 
    float yc = -fabs(y0+y1-y2-y3), ya = yc-4*sy*(y1-y2), yb = sy*(y0-y1-y2+y3); 
    double ab, ac, bc, cb, xx, xy, yy, dx, dy, ex, *pxy, EP = 0.01; 

    /* check for curve restrains */ 
    /* slope P0-P1 == P2-P3 and (P0-P3 == P1-P2 or no slope change) */ 
    assert((x1-x0)*(x2-x3) < EP && ((x3-x0)*(x1-x2) < EP || xb*xb < xa*xc+EP)); 
    assert((y1-y0)*(y2-y3) < EP && ((y3-y0)*(y1-y2) < EP || yb*yb < ya*yc+EP)); 
    if (xa == 0 && ya == 0) { /* quadratic Bezier */ 
    sx = floor((3*x1-x0+1)/2); sy = floor((3*y1-y0+1)/2); /* new midpoint */ 
    return plotQuadBezierSeg(x0,y0, sx,sy, x3,y3); 
    } 
    x1 = (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1; /* line lengths */ 
    x2 = (x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)+1; 
    do { /* loop over both ends */ 
    ab = xa*yb-xb*ya; ac = xa*yc-xc*ya; bc = xb*yc-xc*yb; 
    ex = ab*(ab+ac-3*bc)+ac*ac; /* P0 part of self-intersection loop? */ 
    f = ex > 0 ? 1 : sqrt(1+1024/x1); /* calculate resolution */ 
    ab *= f; ac *= f; bc *= f; ex *= f*f; /* increase resolution */ 
    xy = 9*(ab+ac+bc)/8; cb = 8*(xa-ya);/* init differences of 1st degree */ 
    dx = 27*(8*ab*(yb*yb-ya*yc)+ex*(ya+2*yb+yc))/64-ya*ya*(xy-ya); 
    dy = 27*(8*ab*(xb*xb-xa*xc)-ex*(xa+2*xb+xc))/64-xa*xa*(xy+xa); 
    /* init differences of 2nd degree */ 
    xx = 3*(3*ab*(3*yb*yb-ya*ya-2*ya*yc)-ya*(3*ac*(ya+yb)+ya*cb))/4; 
    yy = 3*(3*ab*(3*xb*xb-xa*xa-2*xa*xc)-xa*(3*ac*(xa+xb)+xa*cb))/4; 
    xy = xa*ya*(6*ab+6*ac-3*bc+cb); ac = ya*ya; cb = xa*xa; 
    xy = 3*(xy+9*f*(cb*yb*yc-xb*xc*ac)-18*xb*yb*ab)/8; 
    if (ex < 0) { /* negate values if inside self-intersection loop */ 
     dx = -dx; dy = -dy; xx = -xx; yy = -yy; xy = -xy; ac = -ac; cb = -cb; 
    } /* init differences of 3rd degree */ 
    ab = 6*ya*ac; ac = -6*xa*ac; bc = 6*ya*cb; cb = -6*xa*cb; 
    dx += xy; ex = dx+dy; dy += xy; /* error of 1st step */ 
    for (pxy = &xy, fx = fy = f; x0 != x3 && y0 != y3;) { 
     setPixel(x0,y0); /* plot curve */ 
     do { /* move sub-steps of one pixel */ 
     if (dx > *pxy || dy < *pxy) goto exit; /* confusing values */ 
     y1 = 2*ex-dy; /* save value for test of y step */ 
     if (2*ex >= dx) { /* x sub-step */ 
      fx--; ex += dx += xx; dy += xy += ac; yy += bc; xx += ab; 
     } 
     if (y1 <= 0) { /* y sub-step */ 
      fy--; ex += dy += yy; dx += xy += bc; xx += ac; yy += cb; 
     } 
     } while (fx > 0 && fy > 0); /* pixel complete? */ 
     if (2*fx <= f) { x0 += sx; fx += f; } /* x step */ 
     if (2*fy <= f) { y0 += sy; fy += f; } /* y step */ 
     if (pxy == &xy && dx < 0 && dy > 0) pxy = &EP;/* pixel ahead valid */ 
    } 
    exit: xx = x0; x0 = x3; x3 = xx; sx = -sx; xb = -xb; /* swap legs */ 
    yy = y0; y0 = y3; y3 = yy; sy = -sy; yb = -yb; x1 = x2; 
    } while (leg--); /* try other end */ 
    plotLine(x0,y0, x3,y3); /* remaining part in case of cusp or crunode */ 
} 

Als Mike ‚Pomax‘ Kamermans festgestellt hat, ist die Lösung für kubische Bezier-Kurven auf der Website nicht Komplett; insbesondere gibt es Probleme mit kubischen Bezier-Kurven mit Antialiasing, und die Diskussion rationaler kubischer Bezier-Kurven ist unvollständig.

+0

wird aber nur für quadratische Kurven berechnet und auf jene Kurven beschränkt, die in ihrem Gradienten keine Vorzeichenänderung haben. Es ist also eine nette Spielzeugimplementierung, aber ohne zusätzlichen Code zum Segmentieren einer Kurve in solche Unterabschnitte nicht sehr nützlich. –

+0

@MPK Der zusätzliche Link, den ich gerade gepostet habe, enthält die gewünschten Informationen, glaube ich. –

+0

nicht so sehr "Ich will" als "ist entscheidend, um die ursprüngliche Frage richtig zu beantworten" =) Nizza Link obwohl, obwohl der Autor darauf hinweist, ihre Lösung für kubische Kurven ist nicht vollständig, so dass * * ist, dass zu prüfen. –

2

Sie können De Casteljau's algorithm verwenden, um eine Kurve in so viele Teile zu unterteilen, dass jeder Unterabschnitt ein Pixel ist.

Dies ist die Gleichung für die Suche nach dem [x, y] Punkt auf einer Kurve zweiten Grad im Intervall T:

// Given 3 control points defining the Quadratic curve 
// and given T which is an interval between 0.00 and 1.00 along the curve. 
// Note: 
// At the curve's starting control point T==0.00. 
// At the curve's ending control point T==1.00. 

var x = Math.pow(1-T,2)*startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
var y = Math.pow(1-T,2)*startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 

Um die praktische Anwendung dieser Gleichung eingegeben werden kann, etwa 1000 T-Werte zwischen 0,00 zu machen und 1.00. Dies führt zu einer Menge von 1000 Punkten, die garantiert entlang der Quadratischen Kurve liegen.

Die Berechnung von 1000 Punkten entlang der Kurve ist wahrscheinlich zu stark (einige berechnete Punkte befinden sich an derselben Pixelkoordinate). Daher sollten Sie die 1000 Punkte de-duplizieren, bis die Menge eindeutige Pixelkoordinaten entlang der Kurve darstellt.

enter image description here

Es gibt eine ähnliche Gleichung für Cubic Bezier-Kurven.

Hier ist Beispielcode, der eine quadratische Kurve als ein Satz von berechneten Pixeln Plots:

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 

 
var points=[]; 
 
var lastX=-100; 
 
var lastY=-100; 
 
var startPt={x:50,y:200}; 
 
var controlPt={x:150,y:25}; 
 
var endPt={x:250,y:100}; 
 

 
for(var t=0;t<1000;t++){ 
 
    var xyAtT=getQuadraticBezierXYatT(startPt,controlPt,endPt,t/1000); 
 
    var x=parseInt(xyAtT.x); 
 
    var y=parseInt(xyAtT.y); 
 
    if(!(x==lastX && y==lastY)){ 
 
    points.push(xyAtT); 
 
    lastX=x; 
 
    lastY=y; 
 
    } 
 
} 
 

 
$('#curve').text('Quadratic Curve made up of '+points.length+' individual points'); 
 

 
ctx.fillStyle='red'; 
 
for(var i=0;i<points.length;i++){ 
 
    var x=points[i].x; 
 
    var y=points[i].y; 
 
    ctx.fillRect(x,y,1,1); 
 
} 
 

 
function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) { 
 
    var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
 
    var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
 
    return({x:x,y:y}); 
 
}
body{ background-color: ivory; } 
 
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
 
<h4 id='curve'>Q</h4> 
 
<canvas id="canvas" width=350 height=300></canvas>

1

Zunächst möchte ich sagen, dass die schnellste und zuverlässigste Möglichkeit, Bezier-Kurven zu rendern, darin besteht, sie über eine adaptive Unterteilung nach Polylinie anzunähern und dann die Polylinie zu rendern. Approach von @markE mit der Zeichnung viele Punkte auf der Kurve ist ziemlich schnell, aber es kann Pixel überspringen. Hier beschreibe ich einen anderen Ansatz, der der Linienrasterisierung am nächsten kommt (obwohl er langsam und schwer robust zu implementieren ist).

Ich werde in der Regel Kurvenparameter als Zeit behandeln. Hier ist der Pseudocode:

  1. Setzen Sie Ihren Cursor auf den ersten Kontrollpunkt, finden Sie die umliegenden Pixel.
  2. Überprüfen Sie für jede Seite des Pixels (insgesamt vier), ob Ihre Bezierkurven ihre Linie schneiden, indem Sie quadratische Gleichungen lösen.
  3. Wählen Sie unter allen berechneten Seitenkreuzungszeiten diejenige aus, die streng in Zukunft passieren wird, aber so früh wie möglich.
  4. Wechseln Sie zum benachbarten Pixel, je nachdem, welche Seite am besten ist.
  5. Stellen Sie die aktuelle Uhrzeit des besten Seitenschnittpunkts ein.
  6. Wiederholen von Schritt 2.

Dieser Algorithmus funktioniert, bis die Zeit Parameter eines überschreitet. Beachten Sie auch, dass es schwerwiegende Probleme mit Kurven gibt, die genau die Seite eines Pixels berühren. Ich nehme an, dass es mit einer speziellen Kontrolle lösbar ist.

Hier ist der Hauptcode:

double WhenEquals(double p0, double p1, double p2, double val, double minp) { 
    //p0 * (1-t)^2 + p1 * 2t(1 - t) + p2 * t^2 = val 
    double qa = p0 + p2 - 2 * p1; 
    double qb = p1 - p0; 
    double qc = p0 - val; 
    assert(fabs(qa) > EPS); //singular case must be handled separately 
    double qd = qb * qb - qa * qc; 
    if (qd < -EPS) 
     return INF; 
    qd = sqrt(max(qd, 0.0)); 
    double t1 = (-qb - qd)/qa; 
    double t2 = (-qb + qd)/qa; 
    if (t2 < t1) swap(t1, t2); 
    if (t1 > minp + EPS) 
     return t1; 
    else if (t2 > minp + EPS) 
     return t2; 
    return INF; 
} 

void DrawCurve(const Bezier &curve) { 
    int cell[2]; 
    for (int c = 0; c < 2; c++) 
     cell[c] = int(floor(curve.pts[0].a[c])); 
    DrawPixel(cell[0], cell[1]); 
    double param = 0.0; 
    while (1) { 
     int bc = -1, bs = -1; 
     double bestTime = 1.0; 
     for (int c = 0; c < 2; c++) 
      for (int s = 0; s < 2; s++) { 
       double crit = WhenEquals(
        curve.pts[0].a[c], 
        curve.pts[1].a[c], 
        curve.pts[2].a[c], 
        cell[c] + s, param 
       ); 
       if (crit < bestTime) { 
        bestTime = crit; 
        bc = c, bs = s; 
       } 
      } 
     if (bc < 0) 
      break; 
     param = bestTime; 
     cell[bc] += (2*bs - 1); 
     DrawPixel(cell[0], cell[1]); 
    } 
} 

Voll Code verfügbar ist here. Es verwendet loadbmp.h, here es ist.

1

Die Sache, die hier zu realisieren ist, ist, dass "Liniensegmente", wenn sie klein genug sind, Pixel entsprechen. Bezier-Kurven sind keine linear überbrückbaren Kurven, so dass wir nicht einfach in einem Schritt zum nächsten Pixel springen können, wie wir es für Linien oder Kreisbögen tun können.

Sie könnten natürlich die Tangente an einem beliebigen Punkt für eine t nehmen, die Sie bereits haben, und dann raten, welcher nächste Wert t' einen Pixel weiter liegen wird. Was jedoch normalerweise passiert ist, dass Sie raten und falsch raten, weil die Kurve sich nicht linear verhält, dann prüfen Sie, wie "aus" Ihre Schätzung war, korrigieren Sie Ihre Schätzung und überprüfen Sie dann erneut. Wiederholen Sie dies, bis Sie auf das nächste Pixel konvergiert sind: Dies ist weit, viel langsamer als die Kurve auf eine hohe Anzahl von Liniensegmenten zu reduzieren, was eine schnelle Operation ist.

Wenn Sie die Anzahl der Segmente so wählen, dass sie für die Länge der Kurve geeignet sind, kann Ihnen niemand bei der Anzeige, für die sie gerendert wird, sagen, dass die Kurve abgeflacht ist.

Es gibt Möglichkeiten, Bezier-Kurven neu zu parametrisieren, aber sie sind teuer, und verschiedene kanonische Kurven erfordern eine andere Umparametrierung, so dass sie auch nicht schneller sind. Was für diskrete Anzeigen am nützlichsten ist, ist die Erstellung einer LUT (Nachschlagetabelle) für Ihre Kurve mit einer Länge, die für die Größe der Kurve auf dem Bildschirm funktioniert, und die Verwendung dieser LUT als Basisdaten für das Zeichnen. Kreuzungserkennung, usw. usw.