Title: Graph pi approximations in C#
My post In honor of Pi Day (3.14), approximate pi in C# uses the following series to approximate the value π.
As you add terms to the series, the approximation alternates between values that are above and below the true value of π. The alternating series test says that any alternating series such as this one where the terms decrease monotonically to zero converges. In other words, if you add more and more terms, the series converges on some value, in this case π.
This example shows the convergence graphically. The green curve connects the approximations that use different numbers of terms. You can see from the picture how the approximations start above π (represented by the blue line) and alternate between being too high and too low. Eventually they start to home in on the correct value.
The red dashed curves envelope the approximations. The upper curve connects approximations that use an odd number of terms so they are always larger than the true value of π. The lower curve connects approximations that use an even number of terms and that are always smaller than the true value of π. Basically the true value is sandwiched between the two enveloping curves so the series converges as those curves converge.
However, you can see in the picture that the approximation isn't in a big hurry to converge. On the right side of the graph, the upper and lower enveloping curves are getting closer together but not very quickly.
As in many drawing applications, the program's drawing code is fairly long but mostly straightforward so I won't show it here. In short, the code makes arrays holding points it wants to draw (the approximations or every other approximation for the dashed enveloping curves) and then calls the Graphics object's DrawCurve method to draw a smooth curve through the points. Download the example to see it in full.
The only really tricky part is the code that draws the textual labels. The program uses a transformation to make the graph nicely fill the form, but it shouldn't use the transformation before drawing the text because that would scale the text and make it unreadable.
To work around that problem, the program uses the following code to define the transformation.
// Set up a transformation to fit
// the graph to the PictureBox.
RectangleF rect = new RectangleF(-1, 2.5f, num_terms - 1, 2);
PointF[] points =
{
new PointF(0, picGraph.ClientSize.Height),
new PointF(
picGraph.ClientSize.Width,
picGraph.ClientSize.Height),
new PointF(0, -0.5f),
};
Matrix transform = new Matrix(rect, points);
Next the code uses the transformation to find the points where the text should be. For example, this is how the program draws a Y-axis label.
// See where this point will be after it is transformed.
PointF[] txt_pts = { new PointF(-0.25f, y) };
transform.TransformPoints(txt_pts);
gr.DrawString(y.ToString(), font,
Brushes.Black, txt_pts[0].X, txt_pts[0].Y, sf);
This code makes an array containing a single point that indicates where the text should be drawn on the graph. It uses the transformation matrix's TransformPoints method to transform the array. Now the point tells where the text should be drawn after scaling the graph to fit the form. The program then uses the DrawString method to draw the text unscaled in a normal font at the transformed position. The result is the text is placed at the right spot on the graph but the text isn't transformed.
Download the example to experiment with it and to see additional details.
|