GDI+ Cardinal Spline Curves

Curves can be created via six different function calls in GDI+. Coordinates can be specified as integers or floating-point numbers, and each method has three corresponding function calls. For either of these, one function uses a default tension value of .5, one uses a specified tenstion value, and the third uses a partial set of points and a specified tension value. The six different methods are illustrated in the program that we have written, and each one corresponds to a curve that we have displayed in the output.

The DrawCuve() command uses cardinal spline to interpolate a set of points. The cardinal spline is a piecewise polynomial in x and y that runs through each pair of specified points. The curve between each successive pair of points is called a segment of the curve. So, a curve that interpolates n points has n - 1 segments. The curve is continuous and smooth everywhere--even between segments, unless the tension is set to zero. When the tension is zero, the curve is just a string of line segments.

For the basic curve, we must specify an array of points and the count for the number of those points. The tension value is set to the default value of .5 in this case. Alternatively, we can call the function that adds a tension valur specification. We can set the tension to zero to make a perfectly tense curve that is a line or we can set the tension to one for a smoothe cerve. We can go above one is some cases to get a smoother looking curve, but we usually want to avoid making the value too large. For the third type of function call, we have the tenstion parameter, but we can give specifications for a subset of the points. The subset of points is specified by setting the offset value to the integer that we want to begin the curve at and then we set the numberOfSegmetns value to the number to segments that we want to include from the given set of points, starting at the offset.

For curve drawing, we can specify the points as an array or point objects. The integer coordinates or points are specified as INT type, while the floating-point coordinates are specified as REAL type. These correspond to the native int and float types. The point types are Point for integers and PointF for the floating-point type; each has two coordinates.

The code that we use illustrates each of the six methods for drawing curves. First, we use the integer point method with the default tension value of .5 to draw an orange curve. Next, we use a green pen to draw a curve using integer points and a tension paremeter. Third, we use a red pen to draw a curve through a subset of integer point with a specified tension parameter. Fourth, we use a yellow pen to draw a curve using floating point coordinates with the default tension value of .5. Fifth, we use a blue pen to draw a curve using floating-point based points and a tension parameter. Finally, the sixth command draws a curve in purple, using a subset of the array of floating-point points and a tension parameter.

The drawing code is given here.

	Graphics graphics(hdc);
	// This makes the drawing smooth, rather than jagged.
	graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
	// Pens have ARGB color channels and line width parameters

	// Curve 1 - Integer points and default tension
	Pen qOrangePen(Color(255, 255, 128, 0), 1.0);
	Point qaIntPoints1[5] = { Point(25, 80), Point(100, 20),
		Point(170, 70), Point(120, 90), Point(25, 15) };
	graphics.DrawCurve(&qOrangePen, qaIntPoints1, 5);

	// Curve 2 - Integer points and specified tension
	Pen qGreenPen(Color(255, 0, 200, 0), 1.0);
	Point qaIntPoints2[5] = { Point(225, 80), Point(300, 20),
		Point(370, 70), Point(320, 90), Point(225, 15) };
	graphics.DrawCurve(&qGreenPen, qaIntPoints2, 5, 0.0f);

	// Curve 3 - Integer points, partial curve, and specified tension
	Pen qRedPen(Color(255, 255, 0, 0), 1.0);
	Point qaIntPoints3[5] = { Point(425, 80), Point(500, 20),
		Point(570, 70), Point(520, 90), Point(425, 15) };
	graphics.DrawCurve(&qRedPen, qaIntPoints3, 5, 1, 3, 0.5f);

	// Curve 4 - Floating-point points and default tension
	Pen qYellowPen(Color(255, 200, 200, 0), 1.0);
	PointF qaFloatPoints1[5] = { PointF(14.3f, 183.5f), PointF(169.3f, 128.2f),
		PointF(43.2f, 151.8f), PointF(176.3f, 187.3f),  PointF(27.7f, 103.3f) };
	graphics.DrawCurve(&qYellowPen, qaFloatPoints1, 5);

	// Curve 5 - Floating-point points and specified tension
	Pen qBluePen(Color(255, 0, 0, 255), 1.0);
	PointF qaFloatPoints2[5] = { PointF(214.3f, 183.5f), PointF(369.3f, 128.2f),
		PointF(243.2f, 151.8f), PointF(376.3f, 187.3f), PointF(227.7f, 103.3f) };
	graphics.DrawCurve(&qBluePen, qaFloatPoints2, 5, 1.5f);

	// Curve 6 - Floating-point points, partial curve, and specified tension
	Pen qPurplePen(Color(255, 200, 0, 240), 1.0);
	PointF qaFloatPoints3[5] = { PointF(414.3f, 183.5f), PointF(569.3f, 128.2f),
		PointF(443.2f, 151.8f), PointF(576.3f, 187.3f), PointF(427.7f, 103.3f) };
	graphics.DrawCurve(&qPurplePen, qaFloatPoints3, 5, 1, 2, 1.0f);
  	

    The six curve drawing commands are given below and are color coded.

  1. Integer points and default tension
    Pen qOrangePen(Color(255, 255, 128, 0), 1.0);
    Point qaIntPoints1[5] = { Point(25, 80), Point(100, 20),
    	Point(170, 70), Point(120, 90), Point(25, 15) };
    graphics.DrawCurve(&qOrangePen, qaIntPoints1, 5);
      	
  2. Integer points and specified tension
    Pen qGreenPen(Color(255, 0, 200, 0), 1.0);
    Point qaIntPoints2[5] = { Point(225, 80), Point(300, 20),
    	Point(370, 70), Point(320, 90), Point(225, 15) };
    graphics.DrawCurve(&qGreenPen, qaIntPoints2, 5, 0.0f);
      	
  3. Integer points, partial curve, and specified tension
    Pen qRedPen(Color(255, 255, 0, 0), 1.0);
    Point qaIntPoints3[5] = { Point(425, 80), Point(500, 20),
    	Point(570, 70), Point(520, 90), Point(425, 15) };
    graphics.DrawCurve(&qRedPen, qaIntPoints3, 5, 1, 3, 0.5f);
      	
  4. Floating-point points and default tension
    Pen qYellowPen(Color(255, 200, 200, 0), 1.0);
    PointF qaFloatPoints1[5] = { PointF(14.3f, 183.5f), PointF(169.3f, 128.2f),
    	PointF(43.2f, 151.8f), PointF(176.3f, 187.3f),  PointF(27.7f, 103.3f) };
    graphics.DrawCurve(&qYellowPen, qaFloatPoints1, 5);
      	
  5. Floating-point points and specified tension
    Pen qBluePen(Color(255, 0, 0, 255), 1.0);
    PointF qaFloatPoints2[5] = { PointF(214.3f, 183.5f), PointF(369.3f, 128.2f),
    	PointF(243.2f, 151.8f), PointF(376.3f, 187.3f), PointF(227.7f, 103.3f) };
    graphics.DrawCurve(&qBluePen, qaFloatPoints2, 5, 1.5f);
      	
  6. Floating-point points, partial curve, and specified tension
    Pen qPurplePen(Color(255, 200, 0, 240), 1.0);
    PointF qaFloatPoints3[5] = { PointF(414.3f, 183.5f), PointF(569.3f, 128.2f),
    	PointF(443.2f, 151.8f), PointF(576.3f, 187.3f), PointF(427.7f, 103.3f) };
    graphics.DrawCurve(&qPurplePen, qaFloatPoints3, 5, 1, 2, 1.0f);