// File: cubic-curve.cxx // Written by: Michael Main (main@colorado.edu) on Sep 27, 2011 // The purpose of this program is to show // how to draw a parametric curve that interpolates four // points via a cubic curve. //------------------------------------------------------------- // Directives: #include #include #include #include #include using namespace std; //------------------------------------------------------------- //------------------------------------------------------------- // Function Prototypes. // This function draws a filled circle in a square graphics // window of size pmax. The coordinate system for the circle // goes from -wmax to +wmax, with the origin at the center of // the screen. The center of the circle is specified in this // coordinate system as wx, wy, and its radius in pixels is // given by pixel_size. The fill color is given by the c // parameter. void fill_circle( int pmax, double wmax, double wx, double wy, int pixel_size, int c ); // pixel(v, v0, v1, p0, p1) converts v from an interval that // ranges from v0 to v1 into an integer interval that ranges // from p0 to p1. int pixel(double v, double v0, double v1, int p0, int p1); // This function draws a parametric cubic curve on a square // graphics window of size pmax. The coordinate system for // the curve goes from -wmax to +wmax, with the origin in // the center of the screen. The curve is guaranteed to // pass through the four points (x0,y0), (x1, y1), (x2,y2) // and (x3,y3). void cubic_curve( int pmax, double wmax, double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3 ); //------------------------------------------------------------- //------------------------------------------------------------- int main() { // Open the graphics window: initwindow(500, 500, "Parametric Cubic Curve"); // Show the four control points to the user in yellow: fill_circle(500, 200.0, -100, -100, 6, YELLOW); fill_circle(500, 200.0, 0, 0, 6, YELLOW); fill_circle(500, 200.0, -100, 100, 6, YELLOW); fill_circle(500, 200.0, 100, 0, 6, YELLOW); // Draw the curve and delay before ending: cubic_curve(500, 200.0, -100, -100, 0, 0, -100, 100, 100, 0); delay(20000); return EXIT_SUCCESS; } //------------------------------------------------------------- //------------------------------------------------------------- // Note: Algorithm from Section 12.4 "Interpolation" of // Ed Angel's Interactive Computer Graphics: A Top-Down // Approach Using OpenGL (5th Edition) void cubic_curve( int pmax, double wmax, double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3 ) { double t; // "Time" parameter controls where on the curve double t2, t3; // Powers of t double c0, c1, c2, c3; // Coef. for the cubic x-polynomial double d0, d1, d2, d3; // Coef. for the cubic y-polynomial double wx, wy; // World coordinates of the next pt int px, py; // Pixel coordinates of the next pt // Compute the coefficients for the cubic polynomials: c0 = x0; c1 = -5.5*x0 + 9.0*x1 - 4.5*x2 + 1.0*x3; c2 = +9.0*x0 - 22.5*x1 + 18.0*x2 - 4.5*x3; c3 = -4.5*x0 + 13.5*x1 - 13.5*x2 + 4.5*x3; d0 = y0; d1 = -5.5*y0 + 9.0*y1 - 4.5*y2 + 1.0*y3; d2 = +9.0*y0 - 22.5*y1 + 18.0*y2 - 4.5*y3; d3 = -4.5*y0 + 13.5*y1 - 13.5*y2 + 4.5*y3; // Move to the start of the curve: moveto( pixel(x0, -wmax, +wmax, 0, pmax), pixel(y0, +wmax, -wmax, 0, pmax) ); // For each possible t value draw a line to the point // of the curve that is determined by t: for (t = 0; t <= 1; t += 0.0001) { // Compute the world coordinates of the t point // on the curve: t2 = t*t; t3 = t*t2; wx = c0 + c1*t + c2*t2 + c3*t3; wy = d0 + d1*t + d2*t2 + d3*t3; // Convert to pixel coordinates and draw a line to // that next point: px = pixel(wx, -wmax, +wmax, 0, pmax); py = pixel(wy, +wmax, -wmax, 0, pmax); lineto(px, py); } } //------------------------------------------------------------- //------------------------------------------------------------- void fill_circle( int pmax, double wmax, double wx, double wy, int pixel_size, int c ) { int px, py; // Pixel coordinates of the circle center px = pixel(wx, -wmax, +wmax, 0, pmax); py = pixel(wy, +wmax, -wmax, 0, pmax); setfillstyle(SOLID_FILL, c); fillellipse(px, py, pixel_size, pixel_size); } //------------------------------------------------------------- //------------------------------------------------------------- int pixel(double v, double v0, double v1, int p0, int p1) { return int(p0 + (v - v0)/(v1 - v0) * (p1 - p0)); } //-------------------------------------------------------------