/* Bezier Curve Elegant addition-only differencing method . WARNING: untested code. 2002-04-13:DAV: Translated from lovely idiomatic PostScript to lowest-common-denominator C language. 1998-02-14: Don Lancaster wrote Version 3.2 in PostScript and posted online at http://www.tinaja.com/text/bezgen3.html . How the method works: Given a point on the spline curve, the next point on the curve can be found by simple addition of running terms. The method is device and language independent, letting you generate a cubic spline **without** using the PostScript -curveto- operator! TODO: Is it more efficient to leave like this, breaking up a smooth Bezier curve into 30 or so straight line segments, or would it be cool to make this even more like the Bresenham circle algorithm, *only* doing putpixel() and directly sets the correct pixels without reference to a lineto() routine ? */ extern void moveto( int x, int y); extern void lineto( int x, int y); void bezier( const int x0, const int y0, // start point const int x1, const int y1, // first control point const int x2, const int y2, // last control point const int x3, const int y3 // end point ){ const int numincs = 100; int i = numincs; // % Plot the spline as a standard PostScript curveto... // x0 y0 moveto x1 y1 x2 y2 x3 y3 curveto line1 stroke // Find t-power coefficients a-d given control points. See // HACK62.PDF http://www.tinaja.com/glib/hack62.pdf // for more details. This moves you from graph space to math space.. const float ax = x3 - x2*3 + x1*3 - x0; const float ay = y3 - y2*3 + y1*3 - y0; const float bx = x2*3 - x1*6 + x0*3; const float by = y2*3 - y1*6 + y0*3; const float cx = x1*3 - x0*3; const float cy = y1*3 - y0*3; // /dx x0 def // /dy y0 def // Elegant addition-only differencing method // /numincs 100 def % number of steps to generate the spline // % next, precalculate delta-t increment, square, and cube const float dt1 = 1/(float)numincs; // delta t const float dt2 = dt1*dt1; // delta t squared const float dt3 = dt1*dt2; // delta t cubed // % initialize some stuff... float xx = (float)x0; float yy = (float)y0; float ux = 0; float uy = 0; float vx = 0; float vy = 0; float mx1 = ax * dt3; float my1 = ay * dt3; float lx1 = bx * dt2; float ly1 = by * dt2; float kx = mx1 + lx1 + cx * dt1; float ky = my1 + ly1 + cy * dt1; float mx = mx1 * 6; float my = my1 * 6; float lx = mx + 2*lx1; float ly = my + 2*ly1; // % now generate the fake curveto... moveto( xx, yy ); // xx yy moveto for( i = numincs; i; i-- ){ xx += ux + kx; yy += uy + ky; ux += vx + lx; uy += vy + ly; vx += mx; vy += my; lineto( xx, yy ); // xx yy lineto }; /* Note that successive points along the curve require only *ten* repeated additions. There are no multiplies or other time-intensive operators. Note that this is **not** an approximation, but an exact solution! Try changing -numincs- to 3 to prove this to yourself. */ };