A variant of the Bresenem algorithm works with quadratic functions, such as circles, ellipses, and parabolas, so it should work with quadratic Bezier curves.
I tried to implement the implementation, but then found one on the Internet: http://members.chello.at/~easyfilter/bresenham.html .
If you need more detailed or additional examples, the page mentioned above has a link to a 100-page PDF document on the method: http://members.chello.at/~easyfilter/Bresenham.pdf .
Here is the code of the Alois Zinl site for constructing any quadratic Bezier curve. The first procedure divides the curve into changes in horizontal and vertical gradients:
void plotQuadBezier(int x0, int y0, int x1, int y1, int x2, int y2) { int x = x0-x1, y = y0-y1; double t = x0-2*x1+x2, r; if ((long)x*(x2-x1) > 0) { if ((long)y*(y2-y1) > 0) if (fabs((y0-2*y1+y2)/t*x) > abs(y)) { x0 = x2; x2 = x+x1; y0 = y2; y2 = y+y1; } t = (x0-x1)/t; r = (1-t)*((1-t)*y0+2.0*t*y1)+t*t*y2; t = (x0*x2-x1*x1)*t/(x0-x1); x = floor(t+0.5); y = floor(r+0.5); r = (y1-y0)*(t-x0)/(x1-x0)+y0; plotQuadBezierSeg(x0,y0, x,floor(r+0.5), x,y); r = (y1-y2)*(t-x2)/(x1-x2)+y2; x0 = x1 = x; y0 = y; y1 = floor(r+0.5); } if ((long)(y0-y1)*(y2-y1) > 0) { t = y0-2*y1+y2; t = (y0-y1)/t; r = (1-t)*((1-t)*x0+2.0*t*x1)+t*t*x2; t = (y0*y2-y1*y1)*t/(y0-y1); x = floor(r+0.5); y = floor(t+0.5); r = (x1-x0)*(t-y0)/(y1-y0)+x0; plotQuadBezierSeg(x0,y0, floor(r+0.5),y, x,y); r = (x1-x2)*(t-y2)/(y1-y2)+x2; x0 = x; x1 = floor(r+0.5); y0 = y1 = y; } plotQuadBezierSeg(x0,y0, x1,y1, x2,y2); }
The second procedure actually displays a segment of the Bezier curve (one without gradient changes):
void plotQuadBezierSeg(int x0, int y0, int x1, int y1, int x2, int y2) { int sx = x2-x1, sy = y2-y1; long xx = x0-x1, yy = y0-y1, xy; double dx, dy, err, cur = xx*sy-yy*sx; assert(xx*sx <= 0 && yy*sy <= 0); if (sx*(long)sx+sy*(long)sy > xx*xx+yy*yy) { x2 = x0; x0 = sx+x1; y2 = y0; y0 = sy+y1; cur = -cur; } if (cur != 0) { xx += sx; xx *= sx = x0 < x2 ? 1 : -1; yy += sy; yy *= sy = y0 < y2 ? 1 : -1; xy = 2*xx*yy; xx *= xx; yy *= yy; if (cur*sx*sy < 0) { xx = -xx; yy = -yy; xy = -xy; cur = -cur; } dx = 4.0*sy*cur*(x1-x0)+xx-xy; dy = 4.0*sx*cur*(y0-y1)+yy-xy; xx += xx; yy += yy; err = dx+dy+xy; do { setPixel(x0,y0); if (x0 == x2 && y0 == y2) return; y1 = 2*err < dx; if (2*err > dy) { x0 += sx; dx -= xy; err += dy += yy; } if ( y1 ) { y0 += sy; dy -= xy; err += dx += xx; } } while (dy < 0 && dx > 0); } plotLine(x0,y0, x2,y2); }
Code for smoothing is also available on the site.
Relevant Zingl site features for cubic Bezier curves
void plotCubicBezier(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { 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]; if (xa == 0) { if (abs(xc) < 2*abs(xb)) t[n++] = xc/(2.0*xb); } else if (t1 > 0.0) { 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) { if (abs(yc) < 2*abs(yb)) t[n++] = yc/(2.0*yb); } else if (t1 > 0.0) { 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++) if ((t1 = t[i-1]) > t[i]) { t[i-1] = t[i]; t[i] = t1; i = 0; } t1 = -1.0; t[n] = 1.0; for (i = 0; i <= n; i++) { t2 = 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); 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) plotCubicBezierSeg(x0,y0, x0+fx1,y0+fy1, x0+fx2,y0+fy2, x3,y3); x0 = x3; y0 = y3; fx0 = fx3; fy0 = fy3; t1 = t2; } }
and
void plotCubicBezierSeg(int x0, int y0, float x1, float y1, float x2, float y2, int x3, int y3) { int f, fx, fy, leg = 1; int sx = x0 < x3 ? 1 : -1, sy = y0 < y3 ? 1 : -1; 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; 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) { sx = floor((3*x1-x0+1)/2); sy = floor((3*y1-y0+1)/2); return plotQuadBezierSeg(x0,y0, sx,sy, x3,y3); } x1 = (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1; x2 = (x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)+1; do { ab = xa*yb-xb*ya; ac = xa*yc-xc*ya; bc = xb*yc-xc*yb; ex = ab*(ab+ac-3*bc)+ac*ac; f = ex > 0 ? 1 : sqrt(1+1024/x1); ab *= f; ac *= f; bc *= f; ex *= f*f; xy = 9*(ab+ac+bc)/8; cb = 8*(xa-ya); 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); 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) { dx = -dx; dy = -dy; xx = -xx; yy = -yy; xy = -xy; ac = -ac; cb = -cb; } ab = 6*ya*ac; ac = -6*xa*ac; bc = 6*ya*cb; cb = -6*xa*cb; dx += xy; ex = dx+dy; dy += xy; for (pxy = &xy, fx = fy = f; x0 != x3 && y0 != y3; ) { setPixel(x0,y0); do { if (dx > *pxy || dy < *pxy) goto exit; y1 = 2*ex-dy; if (2*ex >= dx) { fx--; ex += dx += xx; dy += xy += ac; yy += bc; xx += ab; } if (y1 <= 0) { fy--; ex += dy += yy; dx += xy += bc; xx += ac; yy += cb; } } while (fx > 0 && fy > 0); if (2*fx <= f) { x0 += sx; fx += f; } if (2*fy <= f) { y0 += sy; fy += f; } if (pxy == &xy && dx < 0 && dy > 0) pxy = &EP; } exit: xx = x0; x0 = x3; x3 = xx; sx = -sx; xb = -xb; yy = y0; y0 = y3; y3 = yy; sy = -sy; yb = -yb; x1 = x2; } while (leg--); plotLine(x0,y0, x3,y3); }
As Mike Pomax Kamermans noted, the solution for cubic Bezier curves on the site is not complete; in particular, there are problems with smoothing Bezier cubic curves, and the discussion of rational Bezier cubic curves is incomplete.